ǰλã >> Android >> Android实现?部图片滑动指引效
  ϸ

Android实现?部图片滑动指引效

ȶȣ442   ʱ䣺2016-04-28 07:18:04.0
Android实现?部图片滑动指引效?

?部的图片滑动指引效果。这种效果一?在新闻?户?上比较常见,其功能是?/p>

??1、顶部单张图片左右拖拉滑?

??2、带指引?/p>

??3、仅滑动顶部单张图片,不滑动页面,下面的图文内?不动?/p>

??4、类似于新闻客户?功能

 

??为了大?能更好的理解,我?来看下?实现的效果图?/p>

   

    

    

 

??以上便是实现的效果图,其实实现原理也并不难,我们?要将android-support-v4.jar包中ViewPager控件设置成局部就?,只??理界面时稍微有点麻烦,不过看完本篇之后,大?以后使用时直接调用就行?也希望?能?对大家有???/span>

??好了,下面?我们?始我?实现过程,主要给大?介绍?下实现?骤和?些核心代码??先我?要将android-support-v4.jar添加到工程当?然后让我??下程序结构:

 

   

 

??我先?要介绍其实现原理?/p>

??在布?页面?设置成局?限制其高度,然后为滑动的图片集合生成布局界面,并在代码中设置相应的数??配器和监听事件。在切换事件监听器中更改相应的圆点图片和显示标?,由于滑动图片下方的界面不需要改变内容,?以很很?易内容超过屏幕,?以需要?置ScrollView以在内?比较多时显示滚动条,我会在下?绍?何?ViewPager和ScrollView结合使用?/p>

??

??先看下android.support.v4.view.ViewPager在布?界面?核心代码?/p>

<android.support.v4.view.ViewPager        android:id="@+id/image_slide_page"        android:layout_width="fill_parent"        android:layout_height="180dip"        android:focusable="true" />

 

??在程序结构中,MainActivity.java?动的Activity,而TopicNews.java?示头条的Acitivity。在显示时,我们?要将TopicNews.java?对象进?初?化??如下代码?/p>

复制代码
    /**     * 初??     */    private void initeViews(){        // 滑动图片区域        imagePageViews = new ArrayList<View>();        LayoutInflater inflater = getLayoutInflater();          main = (ViewGroup)inflater.inflate(R.layout.page_topic_news, null);        viewPager = (ViewPager) main.findViewById(R.id.image_slide_page);                  // 圆点图片区域        parser = new NewsXmlParser();        int length = parser.getSlideImages().length;        imageCircleViews = new ImageView[length];        imageCircleView = (ViewGroup) main.findViewById(R.id.layout_circle_images);        slideLayout = new SlideImageLayout(TopicNews.this);        slideLayout.setCircleImageLayout(length);                for(int i = 0;i < length;i++){            imagePageViews.add(slideLayout.getSlideImageLayout(parser.getSlideImages()[i]));            imageCircleViews[i] = slideLayout.getCircleImageLayout(i);            imageCircleView.addView(slideLayout.getLinearLayout(imageCircleViews[i], 10, 10));        }                // 设置默?的滑动标?/span>        tvSlideTitle = (TextView) main.findViewById(R.id.tvSlideTitle);        tvSlideTitle.setText(parser.getSlideTitles()[0]);                setContentView(main);                // 设置ViewPager        viewPager.setAdapter(new SlideImageAdapter());          viewPager.setOnPageChangeListener(new ImagePageChangeListener());    }
复制代码

 

??以上对象的声明代码?下所示:

复制代码
??// 滑动图片的集?/span>    private ArrayList<View> imagePageViews = null;    private ViewGroup main = null;    private ViewPager viewPager = null;    // 当前ViewPager索引    private int pageIndex = 0;         // 包含圆点图片的View    private ViewGroup imageCircleView = null;    private ImageView[] imageCircleViews = null;         // 滑动标?    private TextView tvSlideTitle = null;        // 布局设置?/span>    private SlideImageLayout slideLayout = null;    // 数据解析?/span>    private NewsXmlParser parser = null; 
复制代码

 

??由于在显示头条的Activity即TopicNews?设置布局文件不是直接设置的,也就??过inflate将Layout?为View控件的,?以在使用page_topic_news.xml?View时,?要?过main.findViewById(),即如下代码?示:

???? main = (ViewGroup)inflater.inflate(R.layout.page_topic_news, null);        viewPager = (ViewPager) main.findViewById(R.id.image_slide_page);  

 

??而不能像这样直接使用:

        viewPager = (ViewPager) findViewById(R.id.image_slide_page); 

 

??这点大?在使用时?要注意??/p>

??NewsXmlParser类是用于对显示的数据进?解析,由于本示例???示示例,?以在这个类里我只???些?显示的固定数?没有设置动?数?这点明白就可以,代码如下?/p>

复制代码
package com.image.indicator.parser;import java.io.InputStream;import java.util.HashMap;import java.util.List;import org.xmlpull.v1.XmlPullParser;import android.util.Xml;import com.image.indicator.R;import com.image.indicator.entity.News;import com.image.indicator.utility.FileAccess;/** * 解析新闻数据列表 * @Description: 解析新闻数据列表,这里只?示例,具体地不再实现? * @File: NewsXmlParser.java * @Package com.image.indicator.parser * @Author Hanyonglu * @Date 2012-6-18 下午02:31:26 * @Version V1.0 */public class NewsXmlParser {    // 新闻列表    private List<HashMap<String, News>> newsList = null;        // 滑动图片的集合,这里设置成了固定加载,当然也?态加载??/span>    private int[] slideImages = {            R.drawable.image01,            R.drawable.image02,            R.drawable.image03,            R.drawable.image04,            R.drawable.image05};        // 滑动标?的集?/span>    private int[] slideTitles = {            R.string.title1,            R.string.title2,            R.string.title3,            R.string.title4,            R.string.title5,    };        // 滑动链接的集?/span>    private String[] slideUrls = {            "http://mobile.csdn.net/a/20120616/2806676.html",            "http://cloud.csdn.net/a/20120614/2806646.html",            "http://mobile.csdn.net/a/20120613/2806603.html",            "http://news.csdn.net/a/20120612/2806565.html",            "http://mobile.csdn.net/a/20120615/2806659.html",    };        public int[] getSlideImages(){        return slideImages;    }        public int[] getSlideTitles(){        return slideTitles;    }        public String[] getSlideUrls(){        return slideUrls;    }        /**     * 获取XmlPullParser对象     * @param result     * @return     */    private XmlPullParser getXmlPullParser(String result){        XmlPullParser parser = Xml.newPullParser();        InputStream inputStream = FileAccess.String2InputStream(result);                try {            parser.setInput(inputStream, "UTF-8");        } catch (Exception e) {            // TODO: handle exception            e.printStackTrace();        }                return parser;    }        public int getNewsListCount(String result){        int count = -1;                try {            XmlPullParser parser = getXmlPullParser(result);            int event = parser.getEventType();//产生???/span>                        while(event != XmlPullParser.END_DOCUMENT){                switch(event){                case XmlPullParser.START_DOCUMENT:                    break;                case XmlPullParser.START_TAG://判断当前事件??签元素开始事?/span>                    if("count".equals(parser.getName())){//判断?始标签元素是否是count                        count = Integer.parseInt(parser.nextText());                    }                                        break;                case XmlPullParser.END_TAG://判断当前事件??签元素结束事?//                    if("count".equals(parser.getName())){//判断?始标签元素是否是count//                        count = Integer.parseInt(parser.nextText());//                    }                                        break;                }                            event = parser.next();//进入下一?素并触发相应事件            }        } catch (Exception e) {            // TODO: handle exception            e.printStackTrace();        }                // 无返回?,则返?1        return count;    }}
复制代码

 

??关于NewsXmlParser这个类,实现比较?单,不再详述,有兴趣的朋友可以在?发过程中将其设置成动态数?进?解析?/p>

 

??刚才在上?绍其实现原理时,我提到需要??动图片集合的布局界面,那么?何??布局?这里我们?要用到SlideImageLayout?/p>

??SlideImageLayout类是用于生成滑动图片区域布局和圆点图片布?的类。我在上面的代码?即在TopicNews.java的初始化方法initeViews())使用for?设置滑动图片及圆点图片的布局。在??用到了getSlideImageLayout()、getCircleImageLayout()和getLinearLayout()这几?法?下面分?下其功能,先看下getSlideImageLayout()实现代码?/p>

复制代码
    /**     * 生成滑动图片区域布局     * @param index     * @return     */    public View getSlideImageLayout(int index){        // 包含TextView的LinearLayout        LinearLayout imageLinerLayout = new LinearLayout(activity);        LinearLayout.LayoutParams imageLinerLayoutParames = new LinearLayout.LayoutParams(                LinearLayout.LayoutParams.WRAP_CONTENT,                 LinearLayout.LayoutParams.WRAP_CONTENT,                1);                ImageView iv = new ImageView(activity);        iv.setBackgroundResource(index);        iv.setOnClickListener(new ImageOnClickListener());        imageLinerLayout.addView(iv,imageLinerLayoutParames);        imageList.add(iv);                return imageLinerLayout;    }
复制代码

 ??

??由于滑动图片??要??链接或是相应的ID,以便在点击时转向相应的Activity,显示相应的内?或?细信??这里我没有过?的???在点击时显示标?及链接地?,代码?下:

复制代码
    // 滑动页面点击事件监听?/span>    private class ImageOnClickListener implements OnClickListener{        @Override        public void onClick(View v) {            // TODO Auto-generated method stub            Toast.makeText(activity, parser.getSlideTitles()[pageIndex], Toast.LENGTH_SHORT).show();            Toast.makeText(activity, parser.getSlideUrls()[pageIndex], Toast.LENGTH_SHORT).show();        }    }
复制代码

 

??getCircleImageLayout()方法主??圆点图片生成相应的ImageView对象,代码?下:

复制代码
    /**     * 生成圆点图片区域布局对象     * @param index     * @return     */    public ImageView getCircleImageLayout(int index){        imageView = new ImageView(activity);          imageView.setLayoutParams(new LayoutParams(10,10));        imageView.setScaleType(ScaleType.FIT_XY);                imageViews[index] = imageView;                 if (index == 0) {              //默?选中?张图?/span>            imageViews[index].setBackgroundResource(R.drawable.dot_selected);          } else {              imageViews[index].setBackgroundResource(R.drawable.dot_none);          }                   return imageViews[index];    }
复制代码

 

??getLinearLayout()方法则是为圆点图片添加相应的LinearLayout布局,以便??点图片之间的距?,代码?下:

复制代码
    /**     * 获取LinearLayout     * @param view     * @param width     * @param height     * @return     */    public View getLinearLayout(View view,int width,int height){        LinearLayout linerLayout = new LinearLayout(activity);        LinearLayout.LayoutParams linerLayoutParames = new LinearLayout.LayoutParams(                width,                 height,                1);        // 这里?好也?义??有兴趣的?设置?/span>        linerLayout.setPadding(10, 0, 10, 0);        linerLayout.addView(view, linerLayoutParames);                return linerLayout;    }
复制代码

 

??getCircleImageLayout()和getLinearLayout()方法在NewsTopic.java中for?的结构中结合代码如下?/span>

     imageCircleViews[i] = slideLayout.getCircleImageLayout(i);     imageCircleView.addView(slideLayout.getLinearLayout(imageCircleViews[i], 10, 10));

??

??这两?法结合使用便能优美地实现其圆点图片的布局?/p>

 

??以上?于NewsXmlParser和SlideImageLayout两个类的介绍,下面?我们再回到TopicNews类中继续介绍相关知识。在TopicNews?行?象初始化(initeViews()方法)以后,还需要?置ViewPager对象?数据适配器和监听事件。ViewPager???配器的代码如下?/p>

复制代码
??// 滑动图片数据适配?/span>    private class SlideImageAdapter extends PagerAdapter {          @Override          public int getCount() {             return imagePageViews.size();          }            @Override          public boolean isViewFromObject(View arg0, Object arg1) {              return arg0 == arg1;          }            @Override          public int getItemPosition(Object object) {              // TODO Auto-generated method stub              return super.getItemPosition(object);          }            @Override          public void destroyItem(View arg0, int arg1, Object arg2) {              // TODO Auto-generated method stub              ((ViewPager) arg0).removeView(imagePageViews.get(arg1));          }            @Override          public Object instantiateItem(View arg0, int arg1) {              // TODO Auto-generated method stub              ((ViewPager) arg0).addView(imagePageViews.get(arg1));                        return imagePageViews.get(arg1);          }            @Override          public void restoreState(Parcelable arg0, ClassLoader arg1) {              // TODO Auto-generated method stub            }            @Override          public Parcelable saveState() {              // TODO Auto-generated method stub              return null;          }            @Override          public void startUpdate(View arg0) {              // TODO Auto-generated method stub            }            @Override          public void finishUpdate(View arg0) {              // TODO Auto-generated method stub            }      }
复制代码

 

??而ViewPager的事件监?代码如下?/p>

复制代码
??// 滑动页面更改事件监听?/span>    private class ImagePageChangeListener implements OnPageChangeListener {        @Override          public void onPageScrollStateChanged(int arg0) {              // TODO Auto-generated method stub            }            @Override          public void onPageScrolled(int arg0, float arg1, int arg2) {              // TODO Auto-generated method stub            }            @Override          public void onPageSelected(int index) {              pageIndex = index;            slideLayout.setPageIndex(index);            tvSlideTitle.setText(parser.getSlideTitles()[index]);                        for (int i = 0; i < imageCircleViews.length; i++) {                  imageCircleViews[index].setBackgroundResource(R.drawable.dot_selected);                                if (index != i) {                      imageCircleViews[i].setBackgroundResource(R.drawable.dot_none);                  }              }        }      }
复制代码

 

??事件监听器中主?在回调函数onPageSelected(int index)?换标题和圆点图片?/p>

 

??由于滑动区域下方的内容是不变的,也就?滑动的,正?在我在上面提到的,内容可能会超出屏幕的范围,?以我?要使用ScrollView以便内?过?的时候显示滚动条。可能一部分朋友会想到,要显示滚动条我也知道使用ScrollView。我想在这里说的?这里即有ViewPager控件,也有ScrollView,?果两个View单独使用不会有什么问题?然而不幸的?两个?结合使用就出现了??。什么问题呢?就?滑动图片时出现反弹的现象,就?滑动时很难滑?我滑动时感?很吃力,而且图片就是滑动不过去,这个就是两个View之间的冲突,因为两个View都是滑动的View,都会?算相应的位置和判?应的距??/p>

 

??我们如何来解决这?突呢?这里我?要重写ScrollView的onInterceptTouchEvent()回调函数。需要在程序里新加一个ScrollViewExtend类并继承自ScrollView,下面是其代码:

复制代码
package com.image.indicator.control;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.widget.ScrollView;/** * 能?兼?ViewPager的ScrollView * @Description: 解决了ViewPager在ScrollView?滑动反弹?? * @File: ScrollViewExtend.java * @Package com.image.indicator.control * @Author Hanyonglu * @Date 2012-6-18 下午01:34:50 * @Version V1.0 */public class ScrollViewExtend extends ScrollView {    // 滑动距?及坐?/span>    private float xDistance, yDistance, xLast, yLast;    public ScrollViewExtend(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                xDistance = yDistance = 0f;                xLast = ev.getX();                yLast = ev.getY();                break;            case MotionEvent.ACTION_MOVE:                final float curX = ev.getX();                final float curY = ev.getY();                                xDistance += Math.abs(curX - xLast);                yDistance += Math.abs(curY - yLast);                xLast = curX;                yLast = curY;                                if(xDistance > yDistance){                    return false;                }          }        return super.onInterceptTouchEvent(ev);    }}
复制代码

 

??然后在我?布局代码?加这?展的View,?下代码:

复制代码
<com.image.indicator.control.ScrollViewExtend        android:layout_width="match_parent"        android:layout_height="fill_parent">        …??</com.image.indicator.control.ScrollViewExtend>
复制代码

 

??以上的操作便?决ViewPager和ScrollView之间冲突??,这样便?用滚动条顺利显示下方不变的内容?在这里再?给大家?明一下,由于?例只?演示示例,所以在滑动图片的下方,我只?了一张图片固定地显示头条Activity的下方?当然有?要的朋友,可以将其进行改造,将滑动图片的下方区域添加个ListView等View之类的以显示相应要求的信???/p>

 

???些朋友可能会注意到,在滑动图片区域的下方有一段?明的效果,如下图所示:

 

??

 

??这个实现也不难,?在相应的布局代码?加background属?即?如下?/p>

android:background="#55000000"

 

??当然,?明度的设置有个范围,有兴趣的朋友到网上查找?下,这里不再详述?/p>

 

???例除了实现Android?部图片滑动指引效果以外,还实现了上方导航菜单切换的效果,关于这个效果并不?奇,因为网上有一些人已经实现该功能?不过在这里,我跟他?不太?样的?点击上方的新闻分类时灵敏度比较好,也就是说点?概率比较大?因为上方的新闻分类文字比较小,要想点中有时不是件?易的事?下面简要??下其实现过程及相应的代码?/p>

??

??由于要在点击新闻类别时背?片需要动画效果,?以我添加了一?:ImageAnimatioin,用于?理图片移动时动画效果。其代码如下?/p>

复制代码
    /**     * 设置图像移动动画效果     * @param v     * @param startX     * @param toX     * @param startY     * @param toY     */    public static void SetImageSlide(View v, int startX, int toX, int startY, int toY) {        TranslateAnimation anim = new TranslateAnimation(startX, toX, startY, toY);        anim.setDuration(100);        anim.setFillAfter(true);        v.startAnimation(anim);    }
复制代码

 

??下面展示?下点击新闻类?的事件监??代码,因为在这个过程?要?算移动图片的位置和切?面的主体内?,?下:

复制代码
    // 新闻分类事件监听?/span>    private class ItemOnclickListener implements OnClickListener{        @Override        public void onClick(View v) {            // TODO Auto-generated method stub            itemWidth = findViewById(R.id.layout).getWidth();                        switch (v.getId()) {            case R.id.tv_title_news:                ImageAnimatioin.SetImageSlide(tvSelectedItem, startX, 0, 0, 0);                startX = 0;                tvSelectedItem.setText(R.string.title_news_category_tops);                                // 显示头条信息                intent.setClass(MainActivity.this, TopicNews.class);                vNewsMain = getLocalActivityManager().startActivity(                        "TopicNews", intent).getDecorView();                break;            case R.id.tv_title_info:                ImageAnimatioin.SetImageSlide(tvSelectedItem, startX, itemWidth, 0, 0);                startX = itemWidth;                tvSelectedItem.setText(R.string.title_news_category_info);                                // 显示资?信息                intent.setClass(MainActivity.this, InfoNews.class);                vNewsMain = getLocalActivityManager().startActivity(                        "InfoNews", intent).getDecorView();                break;            case R.id.tv_title_blog:                ImageAnimatioin.SetImageSlide(tvSelectedItem, startX, itemWidth * 2, 0, 0);                startX = itemWidth * 2;                tvSelectedItem.setText(R.string.title_news_category_blog);                                // 显示博?信息                intent.setClass(MainActivity.this, BlogNews.class);                vNewsMain = getLocalActivityManager().startActivity(                        "BlogNews", intent).getDecorView();                break;            case R.id.tv_title_magazine:                ImageAnimatioin.SetImageSlide(tvSelectedItem, startX, itemWidth * 3, 0, 0);                startX = itemWidth * 3;                tvSelectedItem.setText(R.string.title_news_category_magazine);                                // 显示杂志信息                intent.setClass(MainActivity.this, MagazineNews.class);                vNewsMain = getLocalActivityManager().startActivity(                        "MagazineNews", intent).getDecorView();                break;            case R.id.tv_title_domain:                ImageAnimatioin.SetImageSlide(tvSelectedItem, startX, itemWidth * 4, 0, 0);                startX = itemWidth * 4;                tvSelectedItem.setText(R.string.title_news_category_domain);                // 显示业界信息                intent.setClass(MainActivity.this, DomainNews.class);                vNewsMain = getLocalActivityManager().startActivity(                        "DomainNews", intent).getDecorView();                break;            case R.id.tv_title_more:                ImageAnimatioin.SetImageSlide(tvSelectedItem, startX, itemWidth * 5, 0, 0);                startX = itemWidth * 5;                tvSelectedItem.setText(R.string.title_news_category_more);                                // 显示更?信息                intent.setClass(MainActivity.this, MoreNews.class);                vNewsMain = getLocalActivityManager().startActivity(                        "MoreNews", intent).getDecorView();                break;            default:                break;            }                        // 更换Layout?新闻主体            rlNewsMain.removeAllViews();            rlNewsMain.addView(vNewsMain, params);        }    }
复制代码

 

??这里设置时是在一?框架?换新闻类?布局,?不?接显示,?以需要注意下。另外,在点击除头条之?的新闻类?,下方展示的也只?图片而已,有?要的朋友将其进?改?,这点不再多??/p>

??

??好了,不想再写下去了,以上便?文的介绍过程,希望能给开发Android的朋友们带来??/p>

 

??示例下载?a href="http://files.cnblogs.com/hanyonglu/AndroidFile/MyImageIndicator.rar">/Files/hanyonglu/AndroidFile/MyImageIndicator.rar 

?地址?a href="http://www.cnblogs.com/hanyonglu/archive/2012/06/19/2555113.html">http://www.cnblogs.com/hanyonglu/archive/2012/06/19/2555113.html