LoopingViewPager icon indicating copy to clipboard operation
LoopingViewPager copied to clipboard

IllegalStateException in ViewPager with Views

Open trofimchyk opened this issue 11 years ago • 20 comments

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.

trofimchyk avatar Nov 27 '13 11:11 trofimchyk

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;
}

HeGanjie avatar May 15 '14 15:05 HeGanjie

I have the same problem, after trying many ways, still could not solve the problem.

ihenk avatar Sep 25 '14 09:09 ihenk

@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;
}

HeGanjie avatar Sep 25 '14 09:09 HeGanjie

:+1: 谢谢!这个问题折腾我一天了,终于搞定了。我有试过InfiniteViewPager,但是只支持四个Item以上才行,用了很多方法修改还是不行。同时,我也用了很多方法改LoopViewPager,但是还是没有成功。看你地址是佛山,所以就直接用中文了... :)

ihenk avatar Sep 25 '14 10:09 ihenk

@HeGanjie 你的方法好像有一些问题,我多次尝试后发现,会存在图片加载错位...

ihenk avatar Sep 25 '14 12:09 ihenk

@ihenk 贴代码看一下,又或者是你的 getCount() 有问题?

@Override
public int getCount() { return looperItems.size(); }

@Override
public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; }

HeGanjie avatar Sep 25 '14 12:09 HeGanjie

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;
}

}

ihenk avatar Sep 25 '14 12:09 ihenk

@HeGanjie 我用的是ImageLoader加载图片,options有设置默认图片的,所以这一块不会有问题...

ihenk avatar Sep 25 '14 12:09 ihenk

@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 avatar Sep 25 '14 12:09 ihenk

@ihenk 你先换回 android.support.v4.view.ViewPager,调通之后再替换回这个库。

HeGanjie avatar Sep 25 '14 13:09 HeGanjie

@HeGanjie 我试过了,用Android自带的ViewPager任何问题的...

ihenk avatar Sep 25 '14 13:09 ihenk

@HeGanjie 你有修改LoopPagerAdapterWrapper及LoopViewPager本身吗?

ihenk avatar Sep 25 '14 13:09 ihenk

@ihenk 没有哦 :confounded:

HeGanjie avatar Sep 25 '14 13:09 HeGanjie

@HeGanjie 你那里有这个单独的DEMO吗?如果有的话,不知道是否方便发送一份至[email protected] (不方便的话,也没有关系的,还是谢谢你 :) )。主要这个已经搞了我一天了,今天其他什么也没有干,实在是不甘心>_< ...

ihenk avatar Sep 25 '14 13:09 ihenk

@HeGanjie 我发现一个规律是,如果未循环滚动的话,图片一直会显示正常,一旦循环滚动,就不正常了....

ihenk avatar Sep 25 '14 14:09 ihenk

@ihenk container.addView(view) 改成 container.addView(v, 0) 试试

HeGanjie avatar Sep 25 '14 14:09 HeGanjie

@HeGanjie 我找到原因了,

// mVpPictureHeader.setAdapter(new LoopPagerAdapterWrapper(adapter));之前用得是这包话,写错了
mVpPictureHeader.setAdapter(adapter);//正确

ihenk avatar Sep 25 '14 14:09 ihenk

can not call adapter.notifyDataSetChanged(), using setAdapter(new Adapter()) for instead

TracyZhangLei avatar Nov 06 '15 13:11 TracyZhangLei

@TracyZhangLei Thank you very much !

OtzOrz avatar Dec 21 '16 03:12 OtzOrz

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);
}

goldingking avatar May 25 '17 08:05 goldingking