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 ...
随机推荐
- 最大流算法之Dinic
引言: 在最大流(一)中我们讨论了关于EK算法的原理与代码实现,此文将讨论与EK算法同级别复杂度(O(N^2M))的算法--Dinic算法. Dinic算法用到的思想是图的分层结构,通过BFS将每一个 ...
- (转)html中 cookie设置
box=="checkBox '是否记住用户密码'": window.onload=function init() { var box = getCookie(" ...
- 遇见未知的CSS
1.1 CSS中你可能会疑问的几个问题 1.1.1 在CSS中为什么要有层叠 在CSS中可能会有多个样式表同时影响同一个元素的某个属性,设计这个功能的主要原因有两个,解决模块化和作者.用户.用户代理样 ...
- 使用java API操作hdfs--通过filesystem API 来读取数据
上面的Path的包是导入错误了,nio中的包是抽象类,是无法创建的,所以换地方更改. 修改之后,指定jar包之后,编译成功,如下,并进行文件的读取操作,依然是成功啦:
- python基础--异常,对象和迭代器
异常处理 面向对象 迭代器和生成器 python异常处理 下面代码触发了一个FileNotFoundError >>> open("notexist.txt") ...
- Unity C# 一些关于Camera的心得!
本文原创,转载请注明出处:http://www.cnblogs.com/AdvancePikachu/p/6856374.html 首先,总结了下最近工作中关于摄像机漫游的功能, 脚本如下: Tran ...
- js中的sort方法
js中原生的sort()采用快排和插入排序算法,根据比较器对数组排序. 默认是将数组元素转为字符串,然后根据Unicode字符集编号的大小排序. charCodeAt(index) 返回指定位置字符的 ...
- Python之向日志输出中添加上下文信息
除了传递给日志记录函数的参数(如msg)外,有时候我们还想在日志输出中包含一些额外的上下文信息.比如,在一个网络应用中,可能希望在日志中记录客户端的特定信息,如:远程客户端的IP地址和用户名.这里我们 ...
- php-fpm 与 fastCgi的浅谈
首先,CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者. web server(比如说nginx)只是内容的分发者.比如,如果请求/index.h ...
- laravel5.2之logout注销账号无效
问题描述:laravel5.2的框架,使用框架auth用户认证后,进行账号注销退出的时候,无法实现. 只有清除浏览器缓存,才能实现账号退出. 解决办法: 改变路由 Route::get('auth/l ...