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实现无限轮播踩坑记的更多相关文章
- 踩石行动:ViewPager无限轮播的坑
2016-6-19 前言 View轮播效果在app中很常见,一想到左右滑动的效果就很容易想到使用ViewPager来实现.对于像我们常说的banner这样的效果,具备无限滑动的功能是可以用ViewPa ...
- ViewPager无限轮播与自定义切换动画
一直在寻求一个能用得长久的ViewPager,寻寻觅觅终于发现,ViewPager有这一个就够了. 注:并非完全原创 先看一下效果: 淡入淡出: 旋转: 无限轮播的ViewPager 主要设计思路(以 ...
- 利用RecyclerView实现无限轮播广告条
代码地址如下:http://www.demodashi.com/demo/14771.html 前言: 公司产品需要新增悬浮广告条的功能,要求是可以循环滚动,并且点击相应的浮条会跳转到相应的界面,在实 ...
- 【踩坑记】从HybridApp到ReactNative
前言 随着移动互联网的兴起,Webapp开始大行其道.大概在15年下半年的时候我接触到了HybridApp.因为当时还没毕业嘛,所以并不清楚自己未来的方向,所以就投入了HybridApp的怀抱. Hy ...
- ViewPage实现无限轮播画廊效果
1. 效果图 2. 布局文件 主要使用的 android:clipChildren的意思:是否限制子View在其范围内.再父布局和viewpager中设置该属性 ,要显示三个界面 ,还要设置marg ...
- iOS 两种不同的图片无限轮播
代码地址如下:http://www.demodashi.com/demo/11608.html 前记 其实想写这个关于无限轮播的记录已经很久很久了,只是没什么时间,这只是一个借口,正如:时间就像海绵, ...
- Android实现广告页图片无限轮播
一.概述 对于一个联网的Android应用, 首页广告无限轮播基本已经成为标配了. 那么它是怎么实现的呢? 有几种实现方式呢? 二.无限轮播的实现 1.最常规的手段是用 ViewPager来实现 2. ...
- Spark踩坑记——Spark Streaming+Kafka
[TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...
- Spark踩坑记——数据库(Hbase+Mysql)
[TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...
随机推荐
- MyEclipse(8.5以上的版本) 安装js的开发插件aptana
最近在学习js,想在MyEclipse(MyEclipse 10) 上面安装一个js的开发的插件aptana. MyEclipse 8.5以后的版本的安装的方法: 1.下载aptana_update_ ...
- [angularjs] MVC + Web API + AngularJs 搭建简单的 CURD 框架
MVC + Web API + AngularJs 搭建简单的 CURD 框架 GitHub 地址:https://github.com/liqingwen2015/Wen.MvcSinglePage ...
- JavaScript中var变量引用function与直接声明function
今天在h5开发app的过程中遇到了一个js问题,function的执行问题 在js中声明函数function有这两种方法 var A=function(){...} 或者 function A(){. ...
- Github+yeoman+gulp-angular初始化搭建angularjs前端项目框架
在上篇文章里面我们说到了Github账号的申请与配置 那么当你有了Github账号并创建了一个自己的Github项目之后,首要的当然是搭建自己的项目框架啦! 本人对自己的定位是web前端狗,常用开发框 ...
- CSS清除浮动各种方法
当容器的高度为auto,且容器的内容中有浮动(float为left或right)的元素,在这种情况下,容器的高度不能自动伸长以适应内容的高度,使得内容溢出到容器外面而影响(甚至破坏)布局的现象.这个现 ...
- [大数据]-Elasticsearch5.3.1+Kibana5.3.1从单机到分布式的安装与使用<1>
一.Elasticsearch,Kibana简介: Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎.无论在开源还是专有领域, Lucene可以被认为是迄今为止最先 ...
- vue2.0 组件通信
组件通信: 子组件要想拿到父组件数据 props 子组件不允许直接给父级的数据, 赋值操作如果想更改,父组件每次穿一个对象给子组件, 对象之间引用. 例子: <script> window ...
- 支付宝app支付服务器签名代码(C#)
1,引入支付宝的sdk(AopSdk) 支付宝接口文档网站可下载,注意下载C#版本: 2,代码写的比较简单 public static string RSASign(string OrderNo,de ...
- python 爬取淘宝的模特照片
前段时间花了一部分时间学习下正则表达式,总觉得利用正则要做点什么事情,所以想通过爬取页面的方式把一些美女的照片保存下来,其实过程很简单. 1.首先读取页面信息: 2.过滤出来照片的url地址: 3.通 ...
- 深入Android RxJava 2
这篇文章是根据Jake Wharton在GOTO CopenHagen 2016上的讲话整理的. 下一个版本(2.0)的RxJava还在开发中.虽然observable.订阅管理和背压(backpre ...