android-viewpager轮播图遇到的问题

推荐:

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的回收,不会导致内存问题。

3、每次初始化下一页太耗时导致显示延迟卡顿,所以可以添加缓存:

mViewPager.setOffscreenPageLimit(3);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值