有很多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,如图所示