ViewPager实现无限轮播踩坑记
Posted 一名Android小生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ViewPager实现无限轮播踩坑记相关的知识,希望对你有一定的参考价值。
最近笔者想通过ViewPager来实现一个广告Banner,并实现无限轮播的效果,但是在这个过程中踩了不少的坑,听我慢慢道来。如果大家有遇到和我一样的情况,可以参考我的解决方法,没有那就更好,如果针对我的解决方法,有啥更好的方案,欢迎和我分享
使用ViewPager实现无限轮播代码
MainActivity代码
public class MainActivity extends AppCompatActivity { private ViewPager mViewPager; private TextView mTvDesTitle; private LinearLayout mPointContainer; private List<ImageView> mImageViewList; private String[] mDesTitles; private int[] mImageIds; private int previousSelectPos = 0;//用于记录上一次选中的小圆点位置 private boolean isRunning = false;//定义一个标记,用于判断是否轮播 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); initData(); initAdapter(); //实现ViewPager的无限轮播 new Thread() { @Override public void run() { isRunning = true; while (isRunning) { try { Thread.sleep(2 * 1000);//每隔2s切换一次 } catch (InterruptedException e) { e.printStackTrace(); } //更新ViewPager的显示,更新UI要在主线程实现 runOnUiThread(new Runnable() { @Override public void run() { mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1); } }); } } }.start(); } private void initViews() { mViewPager = (ViewPager) findViewById(R.id.view_pager); mTvDesTitle = (TextView) findViewById(R.id.tv_des_title); mPointContainer = (LinearLayout) findViewById(R.id.ll_point_container); } private void initData() { //初始化轮播图片 mImageIds = new int[]{R.drawable.bannerone, R.drawable.bannertwo, R.drawable.bannerthree}; //初始化描述标题 mDesTitles = new String[]{"描述标题1", "描述标题2", "描述标题3"}; //初始化ImageView集合 mImageViewList = new ArrayList<>(); //for循环,添加ImageView和小圆点 ImageView imageView; View pointView; LinearLayout.LayoutParams layoutParams; for (int i = 0; i < mImageIds.length; i++) { //添加ImageView imageView = new ImageView(this); imageView.setBackgroundResource(mImageIds[i]); mImageViewList.add(imageView); //添加小圆点 pointView = new View(this); pointView.setBackgroundResource(R.drawable.point_selector); //设置小圆点的布局参数,宽和高 layoutParams = new LinearLayout.LayoutParams(dp2px(5), dp2px(5)); //设置enable状态,默认都是false 灰色。 pointView.setEnabled(false); if (i != 0) { layoutParams.leftMargin = dp2px(10); } //将小圆点添加到LinearLayout中 mPointContainer.addView(pointView, layoutParams); } } private void initAdapter() { mViewPager.setAdapter(new BannerAdapter()); //设置默认显示第一个标题 mTvDesTitle.setText(mDesTitles[0]); //设置第一个小圆点为白色 mPointContainer.getChildAt(0).setEnabled(true); //设置在中间某个位置 int pos = Integer.MAX_VALUE / 2 - (Integer.MAX_VALUE / 2 % mImageViewList.size()); mViewPager.setCurrentItem(pos);//可以实现左右无限轮播 //ViewPager设置滑动监听 mViewPager.addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { /* //滑到某个位置 mTvDesTitle.setText(mDesTitles[position]); //将上一次选中的置为false mPointContainer.getChildAt(previousSelectPos).setEnabled(false); //新选中的置为true mPointContainer.getChildAt(position).setEnabled(true); //更新选中的记录 previousSelectPos = position;*/ //实现无限轮播,positon会变,要更新位置 //滑到某个位置 int newPosition = position % mImageViewList.size(); mTvDesTitle.setText(mDesTitles[newPosition]); //将上一次选中的置为false mPointContainer.getChildAt(previousSelectPos).setEnabled(false); //新选中的置为true mPointContainer.getChildAt(newPosition).setEnabled(true); //更新选中的记录 previousSelectPos = newPosition; } @Override public void onPageScrollStateChanged(int state) { } }); } class BannerAdapter extends PagerAdapter { @Override public int getCount() { //return mImageViewList.size(); //实现无限轮播 return Integer.MAX_VALUE; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { //ImageView imageView = mImageViewList.get(position); //container.addView(imageView); //return imageView; //实现无限轮播 final int newPosition = position % mImageViewList.size(); ImageView imageView = mImageViewList.get(newPosition); /** * 我在轮播的时候同时手动滑动, java.lang.IllegalStateException: * The specified child already has a parent. You must call removeView() on the child‘s parent first. */ imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "你点击了"+newPosition, Toast.LENGTH_SHORT).show(); } }); container.addView(imageView); return imageView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { //这一句在只有三张图片的时候出现了滑动出现空白情况 container.removeView((View) object); } } /** * px转dp */ public int px2dp(float pxValue) { float scale = this.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } /** * dp转px */ public int dp2px(float dpValue) { final float scale = this.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } @Override protected void onDestroy() { super.onDestroy(); isRunning = false; } }
布局文件
<?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.zhiji.bannerdemo.MainActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="180dp"> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v4.view.ViewPager> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_alignParentBottom="true" android:paddingTop="5dp" android:paddingBottom="6dp" android:gravity="center_horizontal" android:background="#66000000"> <TextView android:id="@+id/tv_des_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:textColor="#fff" android:textSize="16sp" android:text="Hello World!" /> <LinearLayout android:id="@+id/ll_point_container" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:orientation="horizontal"> </LinearLayout> </LinearLayout> </RelativeLayout> </RelativeLayout>
小圆点
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <corners android:radius="5dp" /> <solid android:color="@android:color/darker_gray" /> </shape> <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <corners android:radius="5dp"/> <solid android:color="@android:color/white"/> </shape> <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/point_white" android:state_enabled="true" /> <item android:drawable="@drawable/point_gray" android:state_enabled="false" /> </selector>
踩坑分析
1.笔者轮播图片使用了三张,也就是三张图片的轮回切换,上面代码基本实现了无限轮播的效果
但是运行过程中,在它自身无限自动轮播的同时,我同时手动进行了向左或者向右滑动,这时候程序崩溃了,报错如下:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child‘s parent first.
询问度娘后,也参考了网上的一些方案,最终解决方案如下:
@Override public Object instantiateItem(ViewGroup container, int position) { //ImageView imageView = mImageViewList.get(position); //container.addView(imageView); //return imageView; //实现无限轮播 final int newPosition = position % mImageViewList.size(); ImageView imageView = mImageViewList.get(newPosition); imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "你点击了"+newPosition, Toast.LENGTH_SHORT).show(); } }); //新增的代码,用于解决上面提出的错误 ViewGroup parent= (ViewGroup) imageView.getParent(); if(parent!=null){ parent.removeView(imageView); } container.addView(imageView); return imageView; }
加上上面的代码后,笔者在滑动的时候确实不会发生崩溃了,但是左右滑动得时候,会出现一块空白区域,很是苦恼,最终询问度娘看了网友的一些解决方案,方案如下
@Override public void destroyItem(ViewGroup container, int position, Object object) { //这一句在只有三张图片的时候出现了滑动出现空白情况 //新增,将下面这行代码去除就可以解决上面的问题 //container.removeView((View) object); }
好了。使用上面的方案后,确实不会发生白块的现象了。但是很纳闷,这个问题是为什么呢???接着笔者又把三张轮播图换成了4张、5张。神奇的现象发生了,竟然没有出现上面的两种错误问题。
总结
ViewPager实现无限轮播,图片在三张及以下,使用的时候要注意,出现笔者的问题可参考我的解决方案,如果大家有更好的方案,或者针对我的问题,能指出我的问题所在,很是感谢。滑动图片如果在3上以上就可以直接使用我上面的代码。
以上是关于ViewPager实现无限轮播踩坑记的主要内容,如果未能解决你的问题,请参考以下文章