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函数中做个判断,确保不会出现添加之后又被移除的情况出现,改好之后就非常完美了。
填了一个坑,心里舒畅多了。