Android---ViewPager循环滑动+自动滑动

前言

图片轮播是APP常见的功能,我这里就是用ViewPager实现了一个图片轮播的功能,它的不同之处:
1.实现自动轮播,只要是靠handler发送延时消息实现。
2.实现循环播放,只要原理:在List中0和Size位置分别添加尾部和头部信息,在ViewPager展示到position==0的时候,自动跳转到position==size的地方,而在ViewPager展示到position==size的时候,自动跳转到position==0的地方。
3.解决ViewPager的嵌套的冲突问题。

布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <RadioGroup
        android:id="@+id/radiogroup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="10dp"
        android:orientation="horizontal" >
    </RadioGroup>

</RelativeLayout>

ViewPager实现轮播,而RadioGroup利用了单一点击性完成图片下方提示点的作用。
点点的selector:

<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_checked="true" android:drawable="@drawable/point_true"></item>
    <item android:state_checked="false" android:drawable="@drawable/point_false"></item>
</selector>

主要原理

怕图片出现OOM,我这里用了xUtils中的BitmapUtils,这里可以根据实际情况选择。

ViewPager viewPager;
    BitmapUtils bitmapUtils;
    // 存放图片
    List<ImageView> imageViews = new ArrayList<ImageView>();
    // 适配器
    ViewPagerAdapter mAdapter = new ViewPagerAdapter();
    // 点点的父容器
    RadioGroup radioGroup;
    // 是否可循环
    boolean recycled = true;
    // 首页
    int firstItem = 0;
    // 循环展示的msg
    static final int WHAT_RECYCLED = 0;
    // 当前位置
    int index;
    String[] urls = {
            "http://cdn.duitang.com/uploads/item/201409/13/20140913141520_Ydidj.jpeg",
            "http://p.qq181.com/cms/1304/2013040607430286882.jpg",
            "http://cdn.duitang.com/uploads/item/201409/17/20140917231336_URiHE.jpeg",
            "http://img5.duitang.com/uploads/item/201409/13/20140913141545_E3xtA.thumb.700_0.jpeg",
            "http://img4.duitang.com/uploads/item/201411/30/20141130160518_FzGfQ.jpeg",
            "http://img1.imgtn.bdimg.com/it/u=744685945,4101336496&fm=21&gp=0.jpg",
            "http://img4.duitang.com/uploads/item/201406/27/20140627004739_nQwxv.jpeg",
            "http://img4.duitang.com/uploads/item/201206/06/20120606175027_BGuaY.thumb.700_0.jpeg" };

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

初始化,没什么好说的。

viewPager = (ViewPager) findViewById(R.id.viewpager);
        radioGroup = (RadioGroup) findViewById(R.id.radiogroup);
        bitmapUtils = new BitmapUtils(this);
        // 添加存放图片的imageview,有几张图片生成几个imageview
        for (int i = 0; i < urls.length; i++)
        {
            ImageView imageView = new ImageView(this);
            bitmapUtils.display(imageView, urls[i]);
            imageViews.add(imageView);
        }
        // 一张图片的时候不能循环
        recycled = imageViews.size() >= 2;
        // 为了可以循环滑动,在左右各加一个,最左边的界面是图片资源的最后一个,最右边的界面是图片资源的第一个
        if (recycled)
        {
            ImageView imageView = new ImageView(this);
            bitmapUtils.display(imageView, urls[urls.length - 1]);
            imageViews.add(0, imageView);

            ImageView imageView2 = new ImageView(this);
            bitmapUtils.display(imageView2, urls[0]);
            imageViews.add(imageView2);

            firstItem = 1;
        }

主要是根据图片的张数,生成对应的ImageView存放图片,为了防止OOM,用到了BitmapUtils,在左右两边再次添加首尾资源,主要有俩个原因:
1.第一次打开的时候,也可以左滑和右滑。
2.在使ViewPager即使在0和size位置的时候仍然可以滑动。这样我们才能监听滑动时间,使ViewPager再次跳转。(为什么有种网站跳转连接的感脚)

// 添加对应的点点图片
        for (int i = 0; i < imageViews.size(); i++)
        {
            RadioButton rbtn = new RadioButton(this);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            params.rightMargin = 5;
            params.leftMargin = 5;
            rbtn.setLayoutParams(params);
            rbtn.setBackgroundResource(R.drawable.point);
            rbtn.setClickable(false);
            radioGroup.addView(rbtn);
            if (recycled && i == 0 || recycled && i == imageViews.size() - 1)
            {
                rbtn.setVisibility(View.GONE);
            }
        }

向RadioGroup中添加RadioButton,其实RadioButton就是用来显示的点点,注意的一点是第一个点和最后一个点要setVisibility(View.GONE)隐藏起来。

viewPager.setAdapter(mAdapter);
        viewPager.setCurrentItem(firstItem);
        viewPager.setOnPageChangeListener(listener);
        index = viewPager.getCurrentItem();
        ((RadioButton) radioGroup.getChildAt(index)).setChecked(true);

        mHandler.sendEmptyMessageDelayed(WHAT_RECYCLED, 3000);

添加监听,以及初始化。

class ViewPagerAdapter extends PagerAdapter
    {

        @Override
        public int getCount()
        {
            return imageViews.size();
        }

        @Override
        public boolean isViewFromObject(View arg0, Object arg1)
        {
            return arg0 == arg1;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object)
        {
            container.removeView(imageViews.get(position));
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position)
        {
            ImageView imageView = imageViews.get(position);
            container.addView(imageView);
            return imageView;
        }
    }

用过ViewPager的人应该都会写吧,没什么区别,不用详解了。

final OnPageChangeListener listener = new OnPageChangeListener()
    {
        @Override
        public void onPageSelected(int position)
        {
            if (!recycled)
            {
                return;
            }
            if (position == 0)
            {
                index = imageViews.size() - 2;
                viewPager.setCurrentItem(index);
            } else if (position == imageViews.size() - 1)
            {
                index = 1;
                viewPager.setCurrentItem(index);
            } else
            {
                index = position;
            }
            ((RadioButton) radioGroup.getChildAt(index)).setChecked(true);
        }

        @Override
        public void onPageScrolled(int position, float arg1, int arg2)
        {

        }

        @Override
        public void onPageScrollStateChanged(int scrollState)
        {
            if (scrollState == ViewPager.SCROLL_STATE_DRAGGING)
            {
                mHandler.removeMessages(WHAT_RECYCLED);
                mHandler.sendEmptyMessageDelayed(WHAT_RECYCLED, 3000);
            }
        }
    };

添加页面切换事件。
1.onPageScrolled:主要处理滑动过程中的时间,position是当前位置,arg1滑动百分比,arg2滑动像素。
2.onPageScrollStateChanged:滑动状态改变,这里有三个状态,分别是ViewPager.SCROLL_STATE_IDLE(每个页面的初始化状态),ViewPager.SCROLL_STATE_DRAGGING(用户发起的滑动状态),ViewPager.SCROLL_STATE_SETTLING(页面切换的最终流程)。
3:onPageSelected:页面切换事件。

@SuppressLint("HandlerLeak")
    final Handler mHandler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            if (recycled && msg.what == WHAT_RECYCLED)
            {
                index = viewPager.getCurrentItem() + 1;
                viewPager.setCurrentItem(index);
                sendEmptyMessageDelayed(WHAT_RECYCLED, 3000);
            }
        }
    };

在这里我没3秒发送一次消息切换下一个页面,为了更好的用户体验,所以在onPageScrollStateChanged中用户操作的时候,取消消息的发送,在用户操作完成后再次发送。
当然,不要忘记在onPageSelected判断一下recycled,因为它标记了能否循环(在一张图片的时候肯定不能循环播放了)。然后就是在0和size位置跳转到n-1和1的位置。不要忘记radiobutton的状态啊~
好了,这样一个ViewPager循环滑动+自动滑动就实现了。

ViewPager 嵌套冲突

有的时候一个界面上会有俩个ViewPager,这样,可能我们滑动嵌套的ViewPager的时候,外面的ViewPager响应了滑动事件,所以,我们要判断一下滑动的位置来解决冲突。

public NestViewPager(Context context)
    {
        super(context);
    }

    public NestViewPager(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

不要忘记构造方法。。。不要忘记构造方法。。。不要忘记构造方法。。。重要的事说三遍,我还记得我第一次重写View的时候,不知道要重写构造方法,那个苦闷啊 - -。

public boolean onTouchEvent(MotionEvent evt)
    {
        switch (evt.getAction())
        {
        case MotionEvent.ACTION_DOWN:
            // 记录按下时候的坐标
            downPoint.x = evt.getX();
            downPoint.y = evt.getY();
            if (this.getChildCount() > 1)
            { // 有内容,多于1个时
                // 通知其父控件,现在进行的是本控件的操作,不允许拦截
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (this.getChildCount() > 1)
            { // 有内容,多于1个时
                // 通知其父控件,现在进行的是本控件的操作,不允许拦截
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            break;
        case MotionEvent.ACTION_UP:
            // 在up时判断是否按下和松手的坐标为一个点
            if (PointF.length(evt.getX() - downPoint.x, evt.getY()
                    - downPoint.y) < (float) 5.0)
            {
                //onSingleTouch(this);
                return true;
            }
            break;
        }
        return super.onTouchEvent(evt);
    }

重写触屏事件,就是在本控件被触摸的时候,通知父控件不能拦截额。

public void onSingleTouch(View v)
    {
        if (onSingleTouchListener != null)
        {
            onSingleTouchListener.onSingleTouch(v);
        }
    }

    public interface OnSingleTouchListener
    {
        public void onSingleTouch(View v);
    }

    public void setOnSingleTouchListener(
            OnSingleTouchListener onSingleTouchListener)
    {
        this.onSingleTouchListener = onSingleTouchListener;
    }

这里我还写了个接口,为的是,在点击本控件中的子控件的时候,通过回调完成响应的操作,当然看你的需求了。

最后~~~ 效果图:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值