ViewPager 无限滚动广告栏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_23237491/article/details/62418243

现在很多App在进入的时候,都会在首页的顶部有一个广告栏,这两天跟着视频,我也学习了一把广告栏的制作,具体实现了以下的功能:

1.实现用户左右手动滑动

2.实现广告栏自动轮播

3.实现广告栏点击事件

4.无论是用户手动滑动还是广告栏自动轮播的时候,下方的指示点都会随之改变状态

5.实现用户点击或者拖拽时轮播停止,松手时继续轮播

先上3个效果gif吧:

第一个gif,展示的是功能1和2;


第二个gif,展示的是功能3;


第三个gif展示的是功能5;


那功能4,每个gif都可以看得到。


以上就是所有的效果,那么以下部分,是代码逻辑,我们一部分一部分粘贴出来,很多地方都已经写了非常详细的注释了:


先上布局文件,布局文件就非常简单,activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.honey.guanggaoview.MainActivity">

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


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/vp"
        android:background="#44000000"
        android:orientation="vertical"
        android:padding="5dp">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" />

        <LinearLayout
            android:id="@+id/point_group"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:orientation="horizontal"></LinearLayout>
    </LinearLayout>
</RelativeLayout>


再上adapter,MyAdapter:

/**
 * 功 能:
 * 邮 件:[email protected]
 * 2017/3/16  by:honeyHan
 */

public class MyAdapter extends PagerAdapter {
    private Context ctx;
    private ArrayList<ImageView> imageViews = new ArrayList<>();
    View.OnTouchListener myOnTouchListener;
    View.OnClickListener myOnClickListener;


    public MyAdapter(Context context, ArrayList<ImageView> imageViewsList, View.OnTouchListener onTouchListener, View.OnClickListener onClickListener) {
        ctx = context;
        imageViews = imageViewsList;
        myOnTouchListener = onTouchListener;
        myOnClickListener = onClickListener;
    }

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;//这里设置一个最大的数值,用以实现广告栏无限滚动
    }

    /**
     * 相当于listview适配器的getView()---创建某个页面
     *
     * @param container viewPager本身
     * @param position  当前实例化页面的位置
     * @return
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int realPosition = position % imageViews.size();
        ImageView imageView = imageViews.get(realPosition);
        ViewParent vp = imageView.getParent();
        if (vp != null) {
            ViewGroup parent = (ViewGroup) vp;
            parent.removeView(imageView);
        }
        container.addView(imageView);

        imageView.setOnTouchListener(myOnTouchListener);

        imageView.setTag(position);//设置一个tag用以标记位置
        imageView.setOnClickListener(myOnClickListener);

        return imageView;
    }

    /**
     * 比较view和object是不是同一个参数
     *
     * @param view   某个页面
     * @param object instantiateItem()返回的结果
     * @return
     */
    @Override
    public boolean isViewFromObject(View view, Object object) {
        if (view == object) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 释放资源
     *
     * @param container viewPager
     * @param position  要释放的位置
     * @param object    要释放的页面
     */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
//            container.removeView((View) object);
    }
}
这里有一个值得注意的地方,就是instantiateItem()和destroyItem()这两个方法,为什么这么说呢,传统的写法是这样的(注意红色标注部分):

    /**
     * 相当于listview适配器的getView()---创建某个页面
     *
     * @param container viewPager本身
     * @param position  当前实例化页面的位置
     * @return
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int realPosition = position % imageViews.size();
        ImageView imageView = imageViews.get(realPosition);
        container.addView(imageView);

        imageView.setOnTouchListener(myOnTouchListener);

        imageView.setTag(position);//设置一个tag用以标记位置
        imageView.setOnClickListener(myOnClickListener);

        return imageView;
    }

    /**
     * 释放资源
     *
     * @param container viewPager
     * @param position  要释放的位置
     * @param object    要释放的页面
     */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
    }
看上面的代码,也是非常容易理解,该加的加,该释放资源的就去释放资源,蛮好的是吧,跑起项目来,左边的滑动也是没有问题的,但是,我在启动demo时,就立马往右滑动,得了,crash。查看报错发现,它说我正在试图把一个已经有父容器的View添加到另一个组件,在添加之前,应该把父容器给移除。上网百度了一番,发现也有小伙伴碰到了我这样的情况,那么根据他们的经验,我把这两个方法改造了一下,感谢那些小伙伴~那么改造之后的这两个方法如下:

/**
     * 相当于listview适配器的getView()---创建某个页面
     *
     * @param container viewPager本身
     * @param position  当前实例化页面的位置
     * @return
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        int realPosition = position % imageViews.size();
        ImageView imageView = imageViews.get(realPosition);
        ViewParent vp = imageView.getParent();
        if (vp != null) {
            ViewGroup parent = (ViewGroup) vp;
            parent.removeView(imageView);
        }
        container.addView(imageView);

        imageView.setOnTouchListener(myOnTouchListener);

        imageView.setTag(position);//设置一个tag用以标记位置
        imageView.setOnClickListener(myOnClickListener);

        return imageView;
    }


    /**
     * 释放资源
     *
     * @param container viewPager
     * @param position  要释放的位置
     * @param object    要释放的页面
     */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
//            container.removeView((View) object);
    }


最后,在Activity中是这样使用的,MainActivity:

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.vp)
    ViewPager vp;
    @BindView(R.id.title)
    TextView title;
    @BindView(R.id.point_group)
    LinearLayout pointGroup;

    private ArrayList<ImageView> imageViews;//创建一个图片集合

    private int[] imageViewsId = {//图片资源
            R.drawable.timg,
            R.drawable.timg2,
            R.drawable.timg3
    };

    private String[] imageViewsTitle = {//标题资源
            "小猪佩琪--1",
            "小猪佩琪--2",
            "小猪佩琪--3"
    };

    private int lastPosition = 0;//上一次选中的位置

    private Handler handler = new Handler() {//利用handler来进行循环轮播,本质其实就是每2s就set下一个item
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int item = vp.getCurrentItem() + 1;
            vp.setCurrentItem(item);

            handler.sendEmptyMessageDelayed(0, 2000);//延迟2s发一次消息
        }
    };

    private boolean isDragging = false;//判断ViewPager是否处于拖拽的状态

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        //准备数据
        imageViews = new ArrayList<>();
        for (int i = 0; i < imageViewsId.length; i++) {
            //准备图片数据
            ImageView imageView = new ImageView(this);
            imageView.setBackgroundResource(imageViewsId[i]);
            imageViews.add(imageView);

            //添加指示点
            ImageView point = new ImageView(this);
            point.setBackgroundResource(R.drawable.point_selector);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(8, 8);
            if (i == 0) {//刚进入app时,默认第一个选中
                point.setEnabled(true);//显示红色
                title.setText(imageViewsTitle[0]);//设置最初启动应用时对应文本的信息
            } else {
                point.setEnabled(false);//显示灰色
                params.leftMargin = 8;//除了第一个点 其他的点都距离左侧8个像素
            }
            point.setLayoutParams(params);//设置间距
            pointGroup.addView(point);
        }

        vp.setAdapter(new MyAdapter(MainActivity.this, imageViews, new MyOnTouchListener(), new MyOnClickListener()));//绑定适配器
        vp.addOnPageChangeListener(new MyPageChangeListener());

        int item = Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % imageViews.size();//要保证是imageViews的整数倍
        vp.setCurrentItem(item);//设置中间位置,这样的设置,是为了让viewPager可以向左滑动,因为最初的时候,viewPager处于第0个页面是无法朝左滑动的,所以这里设置在中间,是取到imageViews的整数倍,让它处于整数倍的第0个

        handler.sendEmptyMessageDelayed(0, 2000);//发消息开始广告轮询
    }

    private class MyPageChangeListener implements 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 realPosition = position % imageViews.size();
            pointGroup.getChildAt(lastPosition).setEnabled(false);//把上一个红色的设置为灰色
            pointGroup.getChildAt(realPosition).setEnabled(true);//把当前被选中的设置为红色
            lastPosition = realPosition;

            title.setText(imageViewsTitle[realPosition]);//设置对应文本的信息
        }

        /**
         * 当页面滚动状态变化的时候回调
         * 静止-->滑动
         * 滑动-->静止
         *
         * @param state
         */
        @Override
        public void onPageScrollStateChanged(int state) {
            if (state == vp.SCROLL_STATE_DRAGGING) {//ViewPager处于拖拽状态时,取消广告轮播事件
                isDragging = true;
                handler.removeCallbacksAndMessages(null);
            } else if (state == vp.SCROLL_STATE_IDLE && isDragging) {//ViewPager处于空闲状态
                isDragging = false;
                handler.removeCallbacksAndMessages(null);//发消息之前先移除旧的消息
                handler.sendEmptyMessageDelayed(0, 2000);//开启广告轮播事件
            }
        }
    }

    private class MyOnTouchListener implements View.OnTouchListener {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            switch (motionEvent.getAction()) {
                case MotionEvent.ACTION_DOWN://当手指按下时,取消handler即取消广告轮播事件
                    handler.removeCallbacksAndMessages(null);//removeCallbacksAndMessages()的参数为null时,会把消息队列里所有的消息都移除
                    break;
                case MotionEvent.ACTION_UP://手指离开时,在发消息开启广告轮播事件
                    handler.removeCallbacksAndMessages(null);
                    handler.sendEmptyMessageDelayed(0, 2000);
                    break;
            }
            return false;
        }
    }

    private class MyOnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            int position = (int) view.getTag() % imageViews.size();
            String text = imageViewsTitle[position];
            Toast.makeText(MainActivity.this, "" + text, Toast.LENGTH_LONG).show();
        }
    }
}

至于其他的point_selector、point_normal、point_choose等资源,均在源码当中,我就不一一贴出来了,有需要的小伙伴可以自行下载: 点击下载源码

猜你喜欢

转载自blog.csdn.net/qq_23237491/article/details/62418243
今日推荐