ViewPager实现图片无限轮播(上)

有很多APP都有图片轮播效果,可以左右滑动,这种轮播效果一般使用ViewPager实现的

如果没有加图片轮播效果仅仅使用ViewPager
常规方式
这里写图片描述

是无法无限轮播的,到头就不能滑动了

常出现的错误
这里写图片描述

这里写图片描述

错误

The specified child already has a parent. You must call removeView() on the child’s parent first.
这个view是不能被重复添加的

错误位置
这里写图片描述

这个错误一般是加了轮播效果出现的

正确姿势
这里写图片描述

左右都可以无限滑动,不会出现界限与报错

上面是怎么出现这个问题的呢?首先要知道一些概念
- ViewPager相当与一个容器,里面放置着显示的View,通过不断地滑动,显示不同的View
- 这个容器得大小为是  3
- 这样在加载视图的时候会调用两种方法 加载布局和 销毁布局
- 但是如果view的个数在4个或者四个以上就不会出现这样的问题

问题就出现在显示和销毁界面上面
后面会写到怎么会出现这样的问题,以及怎么解决

下面就开始一步步分析这个无限轮播效果是什么做成的
创建一个ViewPager其实是遵循MVC模式的

1.(M)创建一个list用来保存ViewPager显示的View(其实每一个View就是一个ImageView)
2.(V)在创建ViewPager标签,以及显示的每个view的布局
3.(C)创建适配器,将list中的view数据 转换显示到ViewPager当中

创建一个ViewPager,和ItemView的视图

在Activity中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
        <android.support.v4.view.ViewPager
            android:layout_width="match_parent"
            android:layout_height="140dp"
            android:id="@+id/main_view_pager"
            ></android.support.v4.view.ViewPager>

    <!--只有一张图片时没有办法做轮播,填充整个内容,不显示-->
    <ImageView
        android:id="@+id/main_one_iv"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:scaleType="fitXY"
        android:visibility="gone"
        />


</LinearLayout>

这里呢添加了一个ImageView 有个属性是设置不显示,因为如果图片为一张的话就不用添加到ViewPager做轮播效果了

每一个ItemView的布局

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="150dp"
    android:id="@+id/view_banner_iv"
    android:scaleType="fitXY"
    android:contentDescription="@null"
    >

一个ImageView就足够了

最后是将ViewPager控件和每一个ItemView实例化

viewPager = (ViewPager) findViewById(R.id.main_view_pager);
View v = LayoutInflater.from(this).inflate(R.layout.view_banner, null);
                banner_iv= (ImageView) v.findViewById(R.id.view_banner_iv);

这里还没有为ImageView添加背景图片

将ItemView添加到List集合中(在下面的Adapter中会使用到集合)

private List<View> list;
//图片资源是一个数组(有三个资源)
private int images[] = {R.drawable.bana1, R.drawable.bana2, R.drawable.bana3};
private void initViewPagerData() {
        list = new ArrayList<View>();
        int len = images.length;
            for (int i = 0; i < len; i++) {
                View v = LayoutInflater.from(this).inflate(R.layout.view_banner, null);
                banner_iv = (ImageView) v.findViewById(R.id.view_banner_iv);
                banner_iv.setImageResource(images[i]);
                //将每一个View添加到List中
                list.add(v);
            }

    }

创建适配器

public class SecondPagerAdapter extends PagerAdapter {
    private List<View> vList;

    public SecondPagerAdapter(List<View> vList) {
        this.vList = vList;
    }

    @Override
    public int getCount() {
        return vList.size();
    }
    //判断你的每一个数据源对象是否为View对象  Object 为 List数据源
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }
    //初始化Item上的View,将Object返回对象改成View
    //container相当于ViewPager容器
    @Override
    public View instantiateItem(ViewGroup container, int position) {
        //取出要添加的View
        View view=vList.get(position);
        //将View添加到ViewPager
        container.addView(view);
        return view;
    }
    //删除super
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        //找到要删除的对象,取值在0-5
        View view=vList.get(position);
        container.removeView(view);
    }

}

为ViewPager添加适配器

SecondPagerAdapter secondPagerAdapter = new SecondPagerAdapter(list);
viewPager.setAdapter(secondPagerAdapter);

由上面就可以显示常规状态下的viewPager了,只能左右滑动,不能无限轮播(如果当前是第一张是不能向左滑动的,如果是最后一张是不能向右滑动的),并且这样是没有任何错误的

将常规ViewPager显示变为无限轮播模式
因为是无限轮播,所以itemView的显示个数为无限个,在适配器中这里设置为一个int的最大值

@Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

显示数据的时候就不能list.get(position),因为list中没这么多数据

//取出要添加的View,取值保证在0-5
        View view=vList.get(position%(vList.size()));
        //将View添加到ViewPager
        container.addView(view);
//找到要删除的对象,取值在0-5
        View view=vList.get(position%(vList.size()));
        container.removeView(view);

然后再运行~~

报错啦!!!!!

对!就是会报上面的错误,重复添加itemView

为什么会报错呢?
viewPager 的容器大小为3

通过滑动效果可以看出来,当第一个向第二个滑动时,第一个View没有滑动完第二个界面就会显示一部分,因为ViewPager会提前将第二个添加到ViewPager的容器中

为什么有list中四个以上的view就不会报错

1.当有四个View时,比如显示第一个View ,会添加第二个View的界面
2.显示第三个View,第二个和第四个界面都会被添加,因为只能存放三个,这个时候第一个会被销毁
在滑动显示第五个view时,第一个已经被销毁过了,在进行添加第一个样式的时候就不会出现重复添加了

所以如果我们假如要显示1000个itemView,但是list中只有三个view的界面,当第三个要向第四个滑动的时候,itemView需要添加第一个View的样子,但是第一个view没有被销毁过,所以就会重复添加。但是如果我有四个view,该显示第五个itemView的时候(第三个,第四个View是被添加的状态),第一个View已经被销毁了,所以就不会有重复添加了
同样如果只有两个view的话也会出现类似的问题

解决方案

让一个保存了四个以下的view的list,变成4个或以上
那就是重复添加view,让其变成4个或者6个view
1→2→1’→2’→1→2……          1→2→3→1’→2’→3’→1……

在添加数据的时候加一个判断,如果是view只有两个或者三个,就添加到list四个或者六个

int foradd = 1;
        if (len == 2 || len == 3) {
            foradd = 2;
        }
        //重复循环
        for (int j = 0; j < foradd; j++) {
            for (int i = 0; i < len; i++) {
                View v = inflater.inflate(R.layout.view_banner, null);
                one_iv = (ImageView) v.findViewById(R.id.view_banner_iv);
                one_iv.setImageResource(images[i]);
                list.add(v);
            }
        }

这样就不会报错了~~

但是这样第一张的左边还是 不能被滑动的效果
其实我们当前可以不显示第一个itemView,显示一个中间的itemView保证向左向右滑动都不会有不能滑动的状态

//定义ViewPager初始的位置
        view_pager.setCurrentItem(1000 * 6);

这样 一个无限左右轮播效果的图片轮播器就做好了~~

完整代码

Adapter

public class SecondPagerAdapter extends PagerAdapter {
    private List<View> vList;

    public SecondPagerAdapter(List<View> vList) {
        this.vList = vList;
    }

    //想要做无限轮播,加载的数据个数就要是最大
    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }
    //判断你的每一个数据源对象是否为View对象  Object  数据源
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }
    //初始化Item上的View,将Object返回对象改成View
    //container相当于ViewPager容器
    @Override
    public View instantiateItem(ViewGroup container, int position) {
        //取出要添加的View
        View view=vList.get(position%(vList.size()));
        //将View添加到ViewPager
        container.addView(view);
        return view;
    }
    //删除super
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        //找到要删除的对象,取值在0-5
        View view=vList.get(position%(vList.size()));
        container.removeView(view);
    }


}

Activity

public class SecondActivity extends Activity {
    private List<View> list;
    private int images[] = {R.drawable.bana1, R.drawable.bana2, R.drawable.bana3};
    private ImageView banner_iv;
    private ViewPager viewPager;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewPager = (ViewPager) findViewById(R.id.main_view_pager);
        //添加view到list中
        initViewPagerData();
        SecondPagerAdapter secondPagerAdapter = new SecondPagerAdapter(list);
        viewPager.setAdapter(secondPagerAdapter);
        //定义ViewPager初始的位置
        viewPager.setCurrentItem(1000 * 6);

    }
    private void initViewPagerData() {
        list = new ArrayList<View>();
        int len = images.length;
        //如果是两张或者是三张图片循环添加两次
        int foradd = 1;
        if (len == 2 || len == 3) {
            foradd = 2;
        }
        //重复循环
        for (int j = 0; j < foradd; j++) {
            for (int i = 0; i < len; i++) {
                View v = LayoutInflater.from(this).inflate(R.layout.view_banner, null);
                banner_iv = (ImageView) v.findViewById(R.id.view_banner_iv);
                banner_iv.setImageResource(images[i]);
                list.add(v);
            }
        }

    }
    }

这样就完成了一个可以无限左右滑动的ViewPager轮播器的效果了,如上图所示
不知道在出错的地方有没有解释明白~~

下面一篇还加了新的效果,可以自动播放,并且下部有图片指示器,显示当前显示的是第几张view,如图所示

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值