推荐:
一、ViewPager滑动发生has a parent异常
报错:
java.lang.IllegalStateException:
The specified child already has a parent.
You must call removeView() on the child's parent first.
这种异常是该控件在前面已经添加过一个父控件,当再次滑动重复执行instantiateItem方法,会重复添加,解决方法是先判断其父容器是否存在,如存在,先和此子控件解除关系
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = this.list.get(position % list.size());
//判断其父容器是否存在,如存在,先和此子控件解除关系
ViewPager parent = (ViewPager) view.getParent();
if (parent != null) {
parent.removeView(view);
}
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//destroyItem()方法中可以不写任何东西效果会好一点
}
参考:
当使用ViewPager滑动发生java.lang.IllegalStateException: The specified child already has a parent.异常时的解决方案
Android使用ViewPager实现左右循环滑动及轮播效果
二、两头无限滑动
adapter中:
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = this.list.get(position % list.size());
container.addView(view);
return view;
}
然后设置当前viewpager的item在中间某一个值即可。如下:
mViewPager.setCurrentItem(imgRes.length * 1000);
参考:
Android ViewPager 无限循环左右滑动(可自动) 实现
三、手按住不自动轮播
//通过监听onTouch事件,设置一个标签isLoop;手指按下时isLoop = false,手指抬起后isLoop = true;
mViewPager.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
Toast.makeText(MainActivity.this, "Down", Toast.LENGTH_SHORT).show();
isLoop = false;
break;
case MotionEvent.ACTION_UP:
Toast.makeText(MainActivity.this, "Up", Toast.LENGTH_SHORT).show();
isLoop = true;
break;
}
return false;
}
});
设置是否自动轮播的关键:
//根据isLoop设置是否轮播
mTimer.schedule(new TimerTask() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_VIEWPAGER;
if(isLoop){ //如果isLoop = true 才进行轮播
handler.sendMessage(message);
}
}
}, 1000, 1000);//这里定义了轮播图切换的间隔时间
参考:
四:切换的炫酷效果
直接看张鸿洋的博客:
五、滚动卡顿
使用张鸿洋炫酷的轮播viewpager发现,手动向左滚动时,右侧刚进来的一张图片会卡顿延迟(自动轮播表现不明显)。
1、滑动冲突
参考:Andriod性能优化之列表卡顿——以“简书”APP为例
Android开发者选项——Gpu呈现模式分析
通过开发者模式-Gpu呈现模式分析,发现
后来查看了布局,发现:主界面四个tab上面也是一个viewpager。
原来是viewpager 与 viewpager的fragment中的viewpager滑动冲突了。
然后优化:将主界面四个tab上面改为一个空白viewgroup。替换布局直接切换fragment:add、show、hide。
优化效果:
2、适配器问题
上面优化完毕,但是发现手动左滑,右侧的图片进入时依然会卡顿。
根据鸿洋大神的博客对比发现,我写的适配器的数据源在fragment中new ImageView 好了之后传进adapter。鸿洋是在adapter中new ImageView,按照鸿洋的设计,果然不卡顿了。
原来有问题的代码:
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = this.list.get(position % list.size());
//判断其父容器是否存在,如存在,先和此子控件解除关系
ViewPager parent = (ViewPager) view.getParent();
if (parent != null) {
parent.removeView(view);
}
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//destroyItem()方法中可以不写任何东西效果会好一点
}
估计就是addview前会remove加载过的view,由此造成卡顿。removeView只是从container中移除view,此view不一定会被回收。但是耗费时间。
mViewPager.setOffscreenPageLimit(3);//决定哪些会被回收。
完善后的代码:
public class DiscoverPagerAdapter extends PagerAdapter {
private int[] imgRes;
private Context context;
public DiscoverPagerAdapter(Context context, int[] imgRes) {
this.context = context;
this.imgRes = imgRes;
}
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
ImageView view = new ImageView(context);
view.setScaleType(ImageView.ScaleType.FIT_XY);
view.setImageResource(imgRes[position % imgRes.length]);
container.addView(view);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "position===" + position, Toast.LENGTH_LONG).show();
}
});
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
这种方法在每次初始化一个page时都new一个ImageView,由于setOffscreenPageLimit的回收,不会导致内存问题。
3、每次初始化下一页太耗时导致显示延迟卡顿,所以可以添加缓存:
mViewPager.setOffscreenPageLimit(3);