ViewPager做轮播广告栏的问题总结

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) {
    if (position > mViews.size() - 1) {
        position = position % mViews.size();
    }
    View view = mViews.get(position);
    ViewGroup parent = (ViewGroup) view.getParent();
    if (parent != null) {
        parent.removeView(view);
    }
    container.addView(view);
    return view;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    if (position > mViews.size() - 1) {
        position = position % mViews.size();
    }
    View view = mViews.get(position);
    ViewGroup vp = (ViewGroup) view.getParent();
    if (vp == null) {
        container.removeView(mViews.get(position));
    }
}
这里我的viewPager绑定的是一个View的集合,为了实现无限轮播这个功能,我将适配器的getCount()方法返回Integer.MAX_VALUE,这样之后如果你面两个函数里的内容是这样写的,那么如果你一直朝一个方向滑动,基本上就可以实现无限轮播了

@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (position > mViews.size() - 1) {
        position = position % mViews.size();
    }
    View view = mViews.get(position);
    container.addView(view);
    return view;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    if (position > mViews.size() - 1) {
        position = position % mViews.size();
    }
    View view = mViews.get(position);
    container.removeView(mViews.get(position));  
}
但是如果你顺着相反的方向滑动的话,就会出现上面标题红色字体的错误,大体意思是说这个子View已经有了一个父容器,你必须先从它的父容器中将这个子view给移除掉,那么为什么会出现这个错误呢?我们知道ViewPager是默认可以缓存三个界面的,即当前显示的界面和它相邻的两个界面,下面我画一副图来解释为什么会出现这个问题。


      现在假设我们适配器绑定的集合里面一共是有三个view,view0,view1和view2,默认显示的是view0,那么当加载view0的时候就会顺便把view1也加载了,当滑动到view1的时候又会把view2加载了,那么当滑动到view2的时候,由于ViewPager默认只能缓存三个视图,因此它会先执行destroyItem方法把view0给remove掉,然后执行instantiateItem继续加载下一个视图view0(View4),由于我们在加载时是取了余的,因此view0又被加载进去了。没毛病是吧?(记住此时view0已经被加载进去了)

    那么重点来了,当我们再反向滑动时,滑动到view1时,此时会先执行instantiateItem方法将view0加载进去,再调用destroyItem方法将view4(也就是view0)移除掉 

  也就是说你沿不同的方向滑动viewPager时,调用这两个函数的先后顺序是不一样的,这个问题我也是在打印log日志的时候发现的


   好了,那么了解这个之后,我们再接着上面的说,当返回滑动到view1的时候,会先调用instantiateItem方法去添加view0,那么前面我们不是将view0添加进去了吗,现在再重复添加,自然就报这个错误了,好了那么现在我们已经知道问题出在哪里了,那么该怎么解决?

   没错,跟你想的一样,我们做个判断,如果它已经被加载进去了,我们就先从它的父容器中将它移除掉,然后再添加

    ViewGroup parent = (ViewGroup)view.getParent(); if(parent!=null) parent.removeView(view); container.add(view);

    必须要强转成ViewGroup类型,因为ViewParent是没有移除的这个方法的

    那么现在这样改之后,你无论怎样左右滑动都不会报错了,但是还有个小问题,你会发现向右滑动时会出现空白视图的情况,这是因为向右滑动时我们是先添加,再移除,由于取余的关系,我们添加和移除的都是同一个视图,这样就导致了这个视图最终没有被添加进去,而出现的滑动过程中空视图的情况。因此我们还需在destroyItem函数中做个判断,确保不会出现添加之后又被移除的情况出现,改好之后就非常完美了。

    填了一个坑,心里舒畅多了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值