一个例子带你深入理解ViewPager之广告轮播条的实现

ViewPager在我们的日常开发中可以说是很常用的一个控件了,今天做一个小项目来讲解ViewPager广告轮播条的具体实现。在开始之前,我们先来看看成品是什么样子。



ViewPager是对android扩展包V4包中的一个类,这个类可以让用户左右切换当前的View,我们首先看看android官网对这个类的表述:

Layout manager that allows the user to flip left and right through pages of data. You supply an implementation of a PagerAdapter to generate the pages that the view shows.

Note this class is currently under early design and development. The API will likely change in later updates of the compatibility library, requiring changes to the source code of apps when they are compiled against the newer version.

ViewPager is most often used in conjunction with Fragment, which is a convenient way to supply and manage the lifecycle of each page. There are standard adapters implemented for using fragments with the ViewPager, which cover the most common use cases. These are FragmentPagerAdapterand FragmentStatePagerAdapter; each of these classes have simple code showing how to build a full user interface with them.

从上面的描述中我们可以大致得出一下3点观点:

1.ViewPager类直接继承了ViewGroup类,所以它是一个容器类。可以在其中添加其他的View类。这点我们可以从ViewPager的源码中看出来。



2.ViewePager需要一个PgaerAdapter适配器来给它提供数据

3.ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用。

下面我们来看看普通的ViewPager是如何实现的。

activity_main.xml中的布局文件编写,布局文件很简单,没有什么可说的。

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lqw.myapplication.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/vp_viewpager"
        android:layout_width="match_parent"
        android:layout_height="200dp">

    </android.support.v4.view.ViewPager>
</RelativeLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity
{

    private TextView mTextView;
    private ViewPager mViewPager;
    /**
     * 图片id
     */
    private int[] mImageIds = new int[]{R.mipmap.a,R.mipmap.b,R.mipmap.c,R.mipmap.d,R.mipmap.e,R.mipmap.f,R.mipmap.g};

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewPager = (ViewPager) findViewById(R.id.vp_viewpager);
        mViewPager.setAdapter(new MyViewPagerAdapter());
    }
    /**
     * PagerAdapterViewPager的适配器
     * ViewPager适配器必须要实现的几个方法
     * getCount
     * isViewFromObject
     * instantiateItem
     * destroyItem
     */
    class MyViewPagerAdapter extends PagerAdapter
    {
        @Override
        public int getCount()
        {
            /**
             * 返回图片的数量
             * 如果要使viewpager循环,直接返回比mImageIds.length大的值就可以了
             */
            return mImageIds.length;
        }
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        /**
         * 初始化ViewPager中的View
         * @param container
         * @param position
         * @return
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ImageView imageView = new ImageView(MainActivity.this);
            imageView.setBackgroundResource(mImageIds[position]);
            container.addView(imageView);
            return imageView;
        }

        /**
         * 移除ViewPager中的View
         * @param container
         * @param position
         * @param object
         */
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
           container.removeView((View) object);
        }
    }
}

首先我们在布局文件中定义了一个ViewPageri的控件,然后在MainActivity中根据VIewPager的id找到ViewPager这个控件,编写Viewpager的适配器MyViewPager使之继承PagerAdapter,实现其中的几个重载方法,然后给ViewPager设置这个适配器即可。我们现在来看看ViewPager的效果。


现在最基本的ViewPager滑动已经实现了,接下来我们实现VIewPager的循环滑动以及在viewPager的下方加入文字。

1.viewPager的循环滑动其实很简单,只需要在MyViewPager的回调方法getCount中将返回的条目数设置为比较大的一个数,这里我设置为Integer.Max_VALUE,整数的最大值。

2.ViewPager自动轮播实现原理:我所知道的原理主要有两种,一种是利用handler发送延时消息,而另外一种则是利用定时器(Timer)或者任务调度框架(例如quartz)等去实现。相比较而言,利用handler发送延时消息显得更为简单一点。

3.当用户手指触摸到轮播条的时候,轮播条应该停止滑动,而当用户手指离开屏幕的时候,轮播条应该继续轮播。这种方式的实现也很简单,主要是监听触摸事件。在不同的ACTION事件中实现不同的逻辑。

代码实现如下:

主要贴出MainActivity的代码:

public class MainActivity extends AppCompatActivity
{

    private TextView mTextView;
    private ViewPager mViewPager;
    private int mPreviousPosition;//记录上一个小圆点的位置
    private LinearLayout mLinearLayout;
    /**
     * 图片id
     */
    private int[] mImageIds = new int[]{R.mipmap.a,R.mipmap.b,R.mipmap.c,R.mipmap.
            d,R.mipmap.e,R.mipmap.f,R.mipmap.g};

    /**
     * 文字数组
     */
    private String[] mText = new String[]{"数百头母驴为何半夜惨叫?","小卖部安全套为何屡遭黑手?", "女生宿舍内裤为何频频失窃?",
            "连环弓虽女干母猪案,究竟是何人所为?", "老尼姑的门夜夜被敲,究竟是人是鬼?", "数百只小母狗意外身亡的背后又隐藏着什么?",
            "这一切的背后,是人性的扭曲还是道德的沦丧?"};

    /**
     * 广告条的自动轮播效果,将页面自动切换到下一个页面
     * 实现方法之一:可以利用handler发送一条延时消息
     * 实现方法之二:可以利用定时器
     */
    private Handler mHandler = new Handler()
    {
        @Override
        public void handleMessage(Message msg) {
           int currentItem = mViewPager.getCurrentItem();//获取viewPager当前页面的位置
            mViewPager.setCurrentItem(++currentItem);

            //继续发送延时两秒的消息,类似递归的效果,使广告一直切换
            mHandler.sendEmptyMessageDelayed(0, 2000);

            /**
             * 当用户触摸的时候,自动轮播就应该停止下来
             */
            mViewPager.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            mHandler.removeCallbacksAndMessages(null);
                            break;
                        case MotionEvent.ACTION_UP:
                            mHandler.sendEmptyMessageDelayed(0, 2000);
                            break;
                        default:
                            break;
                    }
                    /**
                     * 如果这里返回trueviewPager的事件将会被消耗掉,ViewPager将会响应不了
                     * 所以这里要返回false,让viewPager原生的触摸效果正常运行
                     */
                    return false;
                }
            });
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewPager = (ViewPager) findViewById(R.id.vp_viewpager);
        mTextView = (TextView) findViewById(R.id.tv_text);
        mLinearLayout = (LinearLayout) findViewById(R.id.ll_container);
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            /**
             * 滑动过程回调事件
             * @param position
             * @param positionOffset
             * @param positionOffsetPixels
             */
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
            {}

            /**
             * 页面选中回调事件
             * @param position
             */
            @Override
            public void onPageSelected(int position) {
                int pos = position % mImageIds.length;
                mTextView.setText(mText[pos]);//更新新闻标题
                Log.d("TAG", "当前位置:" + pos);

                /**
                 * 更新小圆点
                 * 将当前小圆点设置为红色,同时将上一个小圆点设置成灰色
                 */
                mLinearLayout.getChildAt(pos).setEnabled(true);
                mLinearLayout.getChildAt(mPreviousPosition).setEnabled(false);
                mPreviousPosition = pos;

            }

            /**
             * 滑动状态发生改变回调事件
             * @param state
             */
            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        /**
         * 动态添加5个小圆点
         */
        for(int i = 0; i < mImageIds.length; i++)
        {
            ImageView imageView = new ImageView(this);
            imageView.setImageResource(R.drawable.shape_point_selector);
            /**
             * 给小圆点之间设置间距,获取圆点的父布局的布局参数,然后给其设置左边距
             */
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT);
            /**
             * 从第二个圆点开始设置左边距
             */
            if(i != 0) {
                params.leftMargin = 8;
                imageView.setEnabled(false);//设置除第一个圆点外的圆点都为黑色
            }
            imageView.setLayoutParams(params);
            mLinearLayout.addView(imageView);
        }

        //延时两秒发送消息
        mHandler.sendEmptyMessageDelayed(0, 2000);

        mViewPager.setAdapter(new MyViewPagerAdapter());
        /**
         * 设置ViewPager起始页为第一页,并且可以向左滑动
         */
        mViewPager.setCurrentItem(mImageIds.length * 5000);
    }
    /**
     * PagerAdapterViewPager的适配器
     * ViewPager适配器必须要实现的几个方法
     * getCount
     * isViewFromObject
     * instantiateItem
     * destroyItem
     */
    class MyViewPagerAdapter extends PagerAdapter
    {
        @Override
        public int getCount()
        {
            /**
             * 返回图片的数量
             * 如果要使viewpager循环,直接返回比mImageIds.length大的值就可以了
             */
            return Integer.MAX_VALUE;
        }
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        /**
         * 初始化ViewPager中的View
         * @param container
         * @param position
         * @return
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            int pos = position % mImageIds.length;
            ImageView imageView = new ImageView(MainActivity.this);
            imageView.setBackgroundResource(mImageIds[pos]);
            container.addView(imageView);
            return imageView;
        }

        /**
         * 移除ViewPager中的View
         * @param container
         * @param position
         * @param object
         */
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
           container.removeView((View) object);
        }
    }
}
总结:其实ViewPager也不是很难,相比其他控件来说,已经很简单了。多多练习,自然而然也就熟悉了。


源码下载地址:http://download.csdn.net/detail/lqw_student/9549729

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值