LoopingViewPager
LoopingViewPager copied to clipboard
IllegalStateException in ViewPager with Views
IllegalStateException (java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.) when navigate from the last page to the first page or from the first page to the last page.
Cache the 2 extra view, this works for me:
private final List<ImageView> looperViews = new ArrayList<ImageView>(8);
SparseArray<ImageView> cache = new SparseArray<ImageView>(2);
@Override
public void destroyItem(ViewGroup container, int pos, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int pos) {
ImageView page = looperViews.get(pos);
if (page.getParent() != null) {
ImageView cachedView = (ImageView) cache.get(pos);
if (cachedView == null) {
cachedView = createView(page.getDrawable());
cache.put(pos, cachedView);
}
container.addView(cachedView, 0);
return cachedView;
} else {
container.addView(page, 0);
return page;
}
}
private ImageView createView(Drawable drawable) {
ImageView imgView = (ImageView) inflater.inflate(R.layout.looping_item, null);
imgView.setImageDrawable(drawable);
return imgView;
}
I have the same problem, after trying many ways, still could not solve the problem.
@ihenk This is my current solution. I don't save views, it will create when it needed:
public final List<Map<String, Object>> looperItems;
@Override
public void destroyItem(ViewGroup container, int pos, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int pos) {
final ImageView v = new ImageView(ctx);
v.setScaleType(ScaleType.FIT_XY);
Map<String, Object> map = looperItems.get(pos);
if (map == null) {
v.setImageResource(R.drawable.img_ad_default);
} else {
String imgUrl = map.get("titleImg");
Picasso.with(ctx).load(imgUrl).error(R.drawable.img_ad_default).into(v);
}
container.addView(v, 0);
return v;
}
:+1: 谢谢!这个问题折腾我一天了,终于搞定了。我有试过InfiniteViewPager,但是只支持四个Item以上才行,用了很多方法修改还是不行。同时,我也用了很多方法改LoopViewPager,但是还是没有成功。看你地址是佛山,所以就直接用中文了... :)
@HeGanjie 你的方法好像有一些问题,我多次尝试后发现,会存在图片加载错位...
@ihenk 贴代码看一下,又或者是你的 getCount()
有问题?
@Override
public int getCount() { return looperItems.size(); }
@Override
public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; }
public class NetworkViewPagerAdapter extends PagerAdapter {
private List<String> mUrls;
private DisplayImageOptions options;
protected ImageLoader imageLoader;
private ImageLoadingListener animateFirstListener;
public NetworkViewPagerAdapter(List<String> urls) {
super();
if (urls != null) {
this.mUrls = urls;
} else {
this.mUrls = new ArrayList<String>();
}
options = DefaultDisplayImageOptions
.getDefaultDisplayImageOptions(EduApplication.getInstance());
animateFirstListener = new DefaultAnimateFirstDisplayListener();
imageLoader = ImageLoader.getInstance();
}
@Override
public int getCount() {
return mUrls.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView view = new ImageView(EduApplication.getInstance());
view.setScaleType(ScaleType.FIT_XY);
view.setId(position);
imageLoader.displayImage(mUrls.get(position), view, options,
animateFirstListener);
container.addView(view);
return view;
}
}
@HeGanjie 我用的是ImageLoader加载图片,options有设置默认图片的,所以这一块不会有问题...
@HeGanjie public class DefaultDisplayImageOptions { public static DisplayImageOptions getDefaultDisplayImageOptions( Context context) { //返回图片加载前的默认值 return new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.ic_default) .showImageForEmptyUri(R.drawable.ic_default) .showImageOnFail(R.drawable.ic_default) .cacheInMemory(true) .cacheOnDisk(true) .considerExifParams(true) .displayer( new RoundedBitmapDisplayer(context.getResources() .getDimensionPixelSize(R.dimen.icon_rounded))) .build(); }
}
@ihenk 你先换回 android.support.v4.view.ViewPager
,调通之后再替换回这个库。
@HeGanjie 我试过了,用Android自带的ViewPager任何问题的...
@HeGanjie 你有修改LoopPagerAdapterWrapper及LoopViewPager本身吗?
@ihenk 没有哦 :confounded:
@HeGanjie 你那里有这个单独的DEMO吗?如果有的话,不知道是否方便发送一份至[email protected] (不方便的话,也没有关系的,还是谢谢你 :) )。主要这个已经搞了我一天了,今天其他什么也没有干,实在是不甘心>_< ...
@HeGanjie 我发现一个规律是,如果未循环滚动的话,图片一直会显示正常,一旦循环滚动,就不正常了....
@ihenk container.addView(view)
改成 container.addView(v, 0)
试试
@HeGanjie 我找到原因了,
// mVpPictureHeader.setAdapter(new LoopPagerAdapterWrapper(adapter));之前用得是这包话,写错了
mVpPictureHeader.setAdapter(adapter);//正确
can not call adapter.notifyDataSetChanged(), using setAdapter(new Adapter()) for instead
@TracyZhangLei Thank you very much !
The instantiateItem callback need return a new object but a reference to the same project twice, for there is reuse somewhere. Just the first one and last position need to be reused, so we can return a new object for those.
in the instantiateItem method of your adapter, you can write like this:
if (position == 0) {
first = new TextView(context);
first.setText("" + position);
container.addView(first);
return first;
} else if (position == NUM_ITEMS - 1) {
last = new TextView(context);
last.setText("" + position);
container.addView(last);
return last;
} else {
container.addView(views.get(position));
return views.get(position);
}