android-viewpager轮播图遇到的问题

来源:互联网 发布:二次视频解析接口源码 编辑:程序博客网 时间:2024/05/29 04:01

推荐:

android-ViewPager的轮播

一、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自动轮播,手指按住停止轮播

四:切换的炫酷效果

直接看张鸿洋的博客:

巧用ViewPager 打造不一样的广告轮播切换效果

GitGub地址

五、滚动卡顿

使用张鸿洋炫酷的轮播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的回收,不会导致内存问题。

原创粉丝点击