sq_Hayden's blog

ViewPager无限循环自动轮播图的实现

2018/06/07 Share

ViewPager实现循环轮播图

  • 引言:以前利用自定义控件写过一次轮播图,十分的繁琐,既要监听用户手势的滑动操作,又需要根据点坐标处理图片的平移事件,还无法实现循环轮播的效果。今天通过ViewPager发现实现轮播效果十分的简单,接下来我们看看如何利用ViewPager来实现轮播图的效果。

1.利用ViewPager实现滑动切换效果

  主布局中添加控件ViewPager:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_centerInParent="true"
>

//ViewPager控件
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_centerInParent="true"
>
</android.support.v4.view.ViewPager>

</RelativeLayout>

  主Activity中为ViewPager设置数据填充,此次为了方便起见,准备了四个Fragment作为图片的数据视图源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//数据自己添加就行
private List<Fragment> fragmentList = new ArrayList<>();

class MyAdapter extends FragmentPagerAdapter {

public MyAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}

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

  接下来,在Fragment的视图中添加需要轮播的图片,此处为了区分直接用背景色替代了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  <LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity"
android:gravity="center"
//设置背景色当作图片
android:background="@color/red"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:textColor="@color/white"
android:layout_gravity="center"
android:text="这是第一个Fragment"
/>
</LinearLayout>
}

  接着在Activity中,将Adapter赋值给ViewPager,实现滑动切换效果。

myAdapter = new MyAdapter(getSupportFragmentManager());
viewPager.setAdapter(myAdapter);

  效果如下:
    

viewPager
    

2.ViewPager实现无限循环滑动效果

  从上述ViewPager的切换中我们可以看到,向下到达第四张图时,将不可往下继续滑动,同理,向上滑动到第一张时,也无法继续上滑。而我们要实现的效果便是,当滑动到第四张时,接着可以向下滑动回到第一张,向上滑动到第一张时,接着上滑回到末尾的第四张。怎么样实现呢?

1.思路分析

  我们这么来想,此时有四张图片处于我们的总体里,且依次从左到右排列。当我们滑到尾部的时候,如果接着还有一张图续在尾部后面,与第一张图相同,这样当我们接着向右滑动时,就会切回到首页的界面(但此时其实是我们在末尾新加的那张)。与此同时,我们将ViewPager的position替换为1,将ViewPager的Item替换为第一张图的Item项,这样当我们继续右滑,就可以实现轮播效果。同理,放一张图在最左边作为ViewPager的第一个Item项,与第四张图相同,切到时替换为第四张图,即可完成整体轮播效果。

2.画图分析

  

viewPager

3.代码实现

  首先,我们需要定义出六个页面,同样在此处用Fragment实现:

/**
 * 数据填充
 */
private void initData() {
    if(fragmentList==null){
        fragmentList = new ArrayList<>();
    }
    //添加第四个
    fragmentList.add(new Fragment4());
    //顺序添加
    fragmentList.add(new Fragment1());
    fragmentList.add(new Fragment2());
    fragmentList.add(new Fragment3());
    fragmentList.add(new Fragment4());
    //添加第一个
    fragmentList.add(new Fragment1());
    //设置起始的变更位置,由于采用先等待后变更模式,而起始就是1位置,所以索引从2开始
    position = 2;
}

  接着,我们来看看在ViewPager的监听逻辑实现:

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        //此方法用于监听滑动过程逻辑,不用处理
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        //此方法中变更当前页面的位置
        @Override
        public void onPageSelected(int position1) {
            position = position1;
            if (position == fragmentList.size()-1) {
                // 如果滑到了最后一个,即和第一张相同的图时,设置当前值为1
                position = FIRST_PAGE;
            } else if (position == 0) {
                // 如果索引值为0,即滑到了和第四张图相同的时候,就设置索引值为倒数第二个
                position = fragmentList.size()-2;
            } else {
                //否则正常显示
                position = position1;
            }
        }

        //此方法用来变更ViewPager显示的Item
        @Override
        public void onPageScrollStateChanged(int state) {
            //滑动状态改变的方法
            //state :dragging 拖拽 idle 静止 settling 惯性过程
            //如果是静止状态,将当前页进行替换
            if(state==ViewPager.SCROLL_STATE_IDLE){
                //每次滑动时会走这个方法
                viewPager.setCurrentItem(position, false);
            }
        }
    });

  分析一波:我们在起始时就设置viewPager.setCurrentItem(1,false),也就是显示我们的第一张图。然后,当我们向右滑动时,先走onPageSelected,位置未变更,再走onPageScrollStateChanged,此时position整体一致,因此视图保持正常切换。当滑到最后一个时,我们将位置设为1回到第一个图片的位置,再将ViewPager变更到图片1,不过由于末尾图与1图完全相同,因此感官上是看不出来的,就这样我们完成了后台的变更,实现了无限循环的轮播,向前也是一样的逻辑。

4.效果演示:

  此时,我们的效果就已经实现了:
  

viewPager

3.ViewPager轮播图中添加小圆点并完成联动

1.实现思路

  我们在布局文件中,用一个横向的LinearLayout存储四个自定义Shape小圆点,然后采用相对布局,将ViewPager同LinearLayout放在一个RelativeLayout下,从而实现小圆点的添加动作。(注:由于小圆点的点击范围过小,影响用户操作体验,因此用定宽高的LinearLayout将它包裹起来,完成联动)

2.代码实现

  主视图的布局代码如下:

//定高容器RelativeLayout
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:layout_centerInParent="true"
    >
    //轮播图ViewPager
    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:layout_centerInParent="true"
        >
    </android.support.v4.view.ViewPager>
    //横向小圆点容器
    <LinearLayout
        android:id="@+id/circle_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp"
        android:gravity="center"
        >
        //依次用定宽高的LinearLayout包裹
        <LinearLayout
            android:id="@+id/pic0_lay"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:gravity="center"
            >
            <ImageView
                android:id="@+id/pic_0"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/circle_check_style"
                />
        </LinearLayout>
        <LinearLayout
            android:id="@+id/pic1_lay"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:gravity="center"
            >
            <ImageView
                android:id="@+id/pic_1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/circle_uncheck_style"
                />
        </LinearLayout>
        <LinearLayout
            android:id="@+id/pic2_lay"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:gravity="center"
            >
            <ImageView
                android:id="@+id/pic_2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/circle_uncheck_style"
                />
        </LinearLayout>
        <LinearLayout
            android:id="@+id/pic3_lay"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:gravity="center"
            >
            <ImageView
                android:id="@+id/pic_3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/circle_uncheck_style"
                />
        </LinearLayout>
    </LinearLayout>
</RelativeLayout>

  自定义小圆点的布局:

   <shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"
    android:useLevel="false">

    <solid android:color="@color/green"/>
    //未选中设置为黑色的布局即可
    <solid android:color="@color/gray"/>

    <size android:width="15dp"
        android:height="15dp"/>
</shape>

  主Activity的逻辑处理:

//翻页时小圆点的联动
@Override
public void onPageSelected(int position1) {
    position = position1;
    if (position == fragmentList.size()-1) {
        // 设置当前值为1
        position = FIRST_PAGE;
    } else if (position == 0) {
        // 如果索引值为0了,就设置索引值为倒数第二个
        position = fragmentList.size()-2;
    } else {
        position = position1;
    }
    //翻页后需要去改变对应位置的图片
    switch (position){
        case 1:
            pic_0.setBackgroundResource(R.drawable.circle_check_style);
            pic_1.setBackgroundResource(R.drawable.circle_uncheck_style);
            pic_2.setBackgroundResource(R.drawable.circle_uncheck_style);
            pic_3.setBackgroundResource(R.drawable.circle_uncheck_style);
            break;
        case 2:
            pic_1.setBackgroundResource(R.drawable.circle_check_style);
            pic_0.setBackgroundResource(R.drawable.circle_uncheck_style);
            pic_2.setBackgroundResource(R.drawable.circle_uncheck_style);
            pic_3.setBackgroundResource(R.drawable.circle_uncheck_style);
            break;
        case 3:
            pic_2.setBackgroundResource(R.drawable.circle_check_style);
            pic_0.setBackgroundResource(R.drawable.circle_uncheck_style);
            pic_1.setBackgroundResource(R.drawable.circle_uncheck_style);
            pic_3.setBackgroundResource(R.drawable.circle_uncheck_style);
            break;
        case 4:
            pic_3.setBackgroundResource(R.drawable.circle_check_style);
            pic_0.setBackgroundResource(R.drawable.circle_uncheck_style);
            pic_1.setBackgroundResource(R.drawable.circle_uncheck_style);
            pic_2.setBackgroundResource(R.drawable.circle_uncheck_style);
            break;
        default:
            break;
    }
}
//点击小圆点时切换ViewPager  
pic_0 = findViewById(R.id.pic_0);
pic0_lay = findViewById(R.id.pic0_lay);
pic0_lay.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //此处对第二个参数SmoothScroll设置为false,表示禁止平滑移动效果,否则在4切1时会显示闪屏。
        viewPager.setCurrentItem(1,false);
    }
});
pic_1 = findViewById(R.id.pic_1);
pic1_lay = findViewById(R.id.pic1_lay);
pic1_lay.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        viewPager.setCurrentItem(2,false);
    }
});
pic_2 = findViewById(R.id.pic_2);
pic2_lay = findViewById(R.id.pic2_lay);
pic2_lay.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        viewPager.setCurrentItem(3,false);
    }
});
pic_3 = findViewById(R.id.pic_3);
pic3_lay = findViewById(R.id.pic3_lay);
pic3_lay.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        viewPager.setCurrentItem(4,false);
    }
});

  上述的代码逻辑比较简单,我们定义好主布局,将四个小圆点图片放在ViewPager中,然后在ViewPager的滑动监听中去同步改变小圆点的选中状态,保持与之匹配。而对于小圆点的点击事件来说,每当我们点击时,就切换到对应的ViewPager的Item项即可。

3.效果演示

 

circle

4.ViewPager无限自动轮播的最终实现

  到了这一步,成功已经在向我们招手了,接下来我们就写一个定时器来实现一个自动轮播的效果即可。代码如下:

 //添加一个定时器任务
    timerTask = new TimerTask() {
        @Override
        public void run() {
            while (flag) {
                try {
                    Thread.sleep(2000);
                    //向主线程每隔2s发送一次消息
                    Message msg = new Message();
                    msg.what = MSG_ONE;
                    handler.sendMessage(msg);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    };
 //实现主线程的轮播
 private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what){
            case MSG_ONE:
                //定时变更子项显示
                if(position<5){
                    //变换
                    viewPager.setCurrentItem(position,false);
                    //+1操作
                    position++;
                }else{
                    position = 1;
                    //变换
                    viewPager.setCurrentItem(position,false);
                    position++;
                }
                break;
            default:
                break;
        }
    }
};
//设置为1位置先显示(初始position为2)
viewPager.setCurrentItem(1);
//启动轮播
timer.schedule(timerTask,0);

  在这里,我们设置了定时器先等待2s在变更的模式,而首次已经加载了页面1,因此position应该从2开始,到显示4结束。大于4时就重置为1循环去显示。这样,我们就实现了自动轮播的功能。
  好了,大功告成,让我们看看最终的实现效果吧:
   

circle

  

CATALOG
  1. 1. ViewPager实现循环轮播图
    1. 1.1. 1.利用ViewPager实现滑动切换效果
    2. 1.2. 2.ViewPager实现无限循环滑动效果
      1. 1.2.1. 1.思路分析
      2. 1.2.2. 2.画图分析
      3. 1.2.3. 3.代码实现
      4. 1.2.4. 4.效果演示:
    3. 1.3. 3.ViewPager轮播图中添加小圆点并完成联动
      1. 1.3.1. 1.实现思路
      2. 1.3.2. 2.代码实现
      3. 1.3.3. 3.效果演示
    4. 1.4. 4.ViewPager无限自动轮播的最终实现