【问题标题】:Android ViewPager prepend new ViewAndroid ViewPager 前置新视图
【发布时间】:2013-10-14 15:31:49
【问题描述】:

我想在我的 ViewPager 的第一页中添加一个新视图。 我的适配器如下所示:

public class PagerAdapter extends FragmentPagerAdapter {

    private final List<Fragment> fragments;

    public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }

    @Override
    public Fragment getItem(int index) {
        return fragments.get(index);
    }

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

    public void add(int i, ImageFileObject imageFile) {
        ImageViewFragment f = new ImageViewFragment();
        f.setImage(imageFile);
        fragments.add(0, f);
        notifyDataSetChanged();
    }

    public void add(ImageFileObject imageFile) {
        ImageViewFragment f = new ImageViewFragment();
        f.setImage(imageFile);
        fragments.add(f);
        notifyDataSetChanged();
    }

}

但是当调用 add(0, aImageFile) 时,该项目不会添加到片段列表中。 (它甚至没有附加)。

有什么想法吗?

【问题讨论】:

标签: android android-viewpager


【解决方案1】:

更新:您在评论中描述的问题是真实的,我在第一次测试时错过了它。在分析了FragmentPagerAdapter 的源代码后,我意识到我们需要做的就是Override getItemId(),使其不会为不同的片段项返回相同的 id。例如。当前的默认实现只会将位置作为片段的 id 返回,这不适用于这种情况:

 public long getItemId(int position) {
    return position;
}

我正在更新这个答案,请看一下。和以前一样,我已经测试过这段代码,你描述的问题现在没有发生。


您唯一需要的是List 中自己保留对片段的引用,这是由FragmentPagerAdapter 为您完成的。据我所知,这也不是一个好习惯。而且即使您按照其他答案的建议从getItemPosition() 返回POSITION_NONE,您最终也会遇到异常

原因:java.lang.IllegalStateException: Can't change tag of fragment.

这是因为您试图通过在第 0 个索引处添加一个片段(这会导致其他片段重新定位)来重新定位 Fragments 在您的List 中,并且ViewPager 根据位置分配标签。

记住这一切,这里有一个经过测试且工作修改过的适配器:

public class PagerAdapter extends FragmentPagerAdapter {
public static class FragmentInfo {
    public String classz;
    public ImageFileObject imageFile;


    public static long IDS;
    public long id;

    public FragmentInfo(){
        id = IDS++;
    } 
}



private final List<FragmentInfo> fragments;
private Context context;

public PagerAdapter(FragmentManager fm, List<FragmentInfo> fragments,
        Context context) {
    super(fm);
    this.fragments = fragments;
    this.context = context;
}

@Override
public Fragment getItem(int index) {
    FragmentInfo info = fragments.get(index);
    ImageViewFragment frag = (ImageViewFragment) Fragment.instantiate(
            context, info.classz, /* null arguments*/ null);
    frag.setImage(info.imageFile);
    return frag;
}

@Override
public long getItemId(int position) {
    return fragments.get(position).id;
} 

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

@Override
public int getItemPosition(Object object) {
    return POSITION_NONE;
}

public void add() {
    FragmentInfo f = new FragmentInfo();
    f.classz = ImageViewFragment.class.getName();
    fragments.add(0, f);
    notifyDataSetChanged();
}
}

请相应地更改您的代码。

【讨论】:

  • 虽然使用您的代码在添加到开头时不会引发任何错误,但它仍然不起作用。添加之前可见的页面保留相同的索引,只有以前未加载的页面获得更新的索引。例如,如果我在第 0 页并且我“添加”一个页面,我不能向左滚动,因为当前索引为 0,而向右滚动会给出第 0 页的副本,因为创建了一个新实例第 1 页,现在是上一页 0...
  • 我不明白你在说什么。您是说使用这种技术只会不断重复第 0 页吗?你确定吗?您如何检测到向右滚动会产生第 0 页的副本?
  • 问题是,该方法不会更新已经显示的页面。因此,例如,如果我在第 10 页,添加一个页面,然后移动到尚未实例化的第 11 页,它将显示第 10 页(这是正确的,因为我在索引 11 处请求一个页面,由于前置页面现在是第 10 页),问题是索引 10 上的页面仍然是第 10 页,因为它没有重新实例化。
【解决方案2】:

问题实际上出在 notifyDataSetChanged 上。只需添加到您的适配器:

public int getItemPosition(Object object) {
    return POSITION_NONE;
}

但是,当适配器实际上再次尝试调用getItem 时,我认为您会遇到其他问题。这些问题将出现在“Fragment Already added”的行中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多