提问者:小点点

动态更新ViewPager?


我无法更新ViewPager中的内容。

FragmentPagerAdapter类中方法instantiateItem()和getItem()的正确用法是什么?

我只使用getItem()来实例化和返回我的片段:

@Override
public Fragment getItem(int position) {
    return new MyFragment(context, paramters);
}

这很管用。但我不能改变内容。

所以我发现:ViewPager PagerAdapter没有更新视图

“我的方法是对instantiateItem()方法中的任何实例化视图使用setTag()方法”

现在我想要实现instantiateItem()来实现这一点。但是我不知道我必须返回什么(类型是Object),和getItem(int位置)有什么关系?

我读了参考资料:

>

  • 公共摘要片段getItem(int位置)

    返回与指定位置关联的片段。

    公共对象实例化项(ViewGroup容器,int位置)

    为给定职位创建页面。适配器负责将视图添加到这里给出的容器中,尽管它只需确保在从finishUpdate(ViewGroup)返回时完成此操作。参数

    容器显示页面的包含视图。定位要实例化的页面位置。

    退货

    返回表示新页的对象。这不需要是一个视图,但可以是页面的某个其他容器。

    但我还是不明白。

    这是我的密码。我使用的是支持包V4。

    ViewPagerTest

    public class ViewPagerTest extends FragmentActivity {
        private ViewPager pager;
        private MyFragmentAdapter adapter; 
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.pager1);
    
            pager = (ViewPager)findViewById(R.id.slider);
    
            String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};
    
            adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
            pager.setAdapter(adapter);
    
            ((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    reload();
                }
            });
        }
    
        private void reload() {
            String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
            //adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
            adapter.setData(data);
            adapter.notifyDataSetChanged();
            pager.invalidate();
    
            //pager.setCurrentItem(0);
        }
    }
    

    MyFragmentAdapter

    class MyFragmentAdapter extends FragmentPagerAdapter {
        private int slideCount;
        private Context context;
        private String[] data;
    
        public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
            super(fm);
            this.slideCount = slideCount;
            this.context = context;
            this.data = data;
        }
    
        @Override
        public Fragment getItem(int position) {
            return new MyFragment(data[position], context);
        }
    
        @Override
        public int getCount() {
            return slideCount;
        }
    
        public void setData(String[] data) {
            this.data = data;
        }
    
        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }
    }
    

    MyFragment

    public final class MyFragment extends Fragment {
        private String text;
    
        public MyFragment(String text, Context context) {
            this.text = text;
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.slide, null);
            ((TextView)view.findViewById(R.id.text)).setText(text);
    
            return view;
        }
    }
    

    这里也有人有类似的问题,没有答案http://www.mail-archive.com/android-developers@googlegroups.com/msg200477.html


  • 共3个答案

    匿名用户

    在使用FragmentPagerAdapter或FragmentStatePagerAdapter时,最好只处理GetItem(),而完全不接触InstantiateItem()。PagerAdapter上的InstantiateItem()-DestroyItem()-IsViewFromObject()接口是一个较低级别的接口,FragmentPagerAdapter使用该接口实现简单得多的GetItem()接口。

    在开始讨论这个之前,我应该澄清一下

    如果要切换出正在显示的实际片段,则需要避免使用FragmentPagerAdapter,而使用FragmentStatePagerAdapter。

    这个答案的早期版本错误地使用了FragmentPagerAdapter作为示例--这是行不通的,因为FragmentPagerAdapter从不在片段第一次显示后销毁它。

    我不推荐您链接的文章中提供的setTag()findViewWithTag()变通方法。正如您所发现的,使用setTag()findViewWithTag()不能用于片段,因此不是很好的匹配。

    正确的解决方案是重写getItemposition()。调用NotifyDataSetChanged()时,ViewPager将对其适配器中的所有项调用GetItemPosition(),以查看是否需要将这些项移动到其他位置或删除它们。

    默认情况下,getItemPosition()返回position_unchangement,这意味着,“这个对象在它所在的位置很好,不要破坏或删除它。”返回position_none可以修复该问题,方法是说:“此对象不再是我正在显示的项,删除它。”因此它具有删除和重新创建适配器中的每个项目的效果。

    这是一个完全合法的修复!此修复程序使notifyDataSetChanged的行为与常规适配器类似,无需视图回收。如果您实现了这个修复,并且性能令人满意,那么您就可以参加比赛了。任务完成了。

    如果您需要更好的性能,可以使用更好的GetItemposition()实现。下面是一个分页器从字符串列表中创建片段的示例:

    ViewPager pager = /* get my ViewPager */;
    // assume this actually has stuff in it
    final ArrayList<String> titles = new ArrayList<String>();
    
    FragmentManager fm = getSupportFragmentManager();
    pager.setAdapter(new FragmentStatePagerAdapter(fm) {
        public int getCount() {
            return titles.size();
        }
    
        public Fragment getItem(int position) {
            MyFragment fragment = new MyFragment();
            fragment.setTitle(titles.get(position));
            return fragment;
        }
    
        public int getItemPosition(Object item) {
            MyFragment fragment = (MyFragment)item;
            String title = fragment.getTitle();
            int position = titles.indexOf(title);
    
            if (position >= 0) {
                return position;
            } else {
                return POSITION_NONE;
            }
        }
    });
    

    在此实现中,只显示显示新标题的片段。任何显示仍在列表中的标题的片段都将被移到列表中的新位置,而那些标题根本不在列表中的片段将被销毁。

    如果片段还没有重新创建,但无论如何都需要更新呢?对活动片段的更新最好由片段本身来处理。毕竟,这就是有一个片段的好处--它是自己的控制器。片段可以在onCreate()中向另一个对象添加侦听器或观察器,然后在onDestroy()中删除它,从而管理更新本身。您不必像在ListView或其他AdapterView类型的适配器中那样,将所有更新代码放在GetItem()中。

    最后一点--FragmentPagerAdapter不破坏片段并不意味着getItemPosition在FragmentPagerAdapter中完全无用。您仍然可以使用此回调来重新排序ViewPager中的片段。但是,它永远不会将它们从FragmentManager中完全删除。

    匿名用户

    与其从GetItemPosition()返回Position_None并导致全视图重新创建,不如这样做:

    //call this method to update fragments in ViewPager dynamically
    public void update(UpdateData xyzData) {
        this.updateData = xyzData;
        notifyDataSetChanged();
    }
    
    @Override
    public int getItemPosition(Object object) {
        if (object instanceof UpdateableFragment) {
            ((UpdateableFragment) object).update(updateData);
        }
        //don't return POSITION_NONE, avoid fragment recreation. 
        return super.getItemPosition(object);
    }
    

    您的片段应该实现UpdateAbleFragment接口:

    public class SomeFragment extends Fragment implements
        UpdateableFragment{
    
        @Override
        public void update(UpdateData xyzData) {
             // this method will be called for every fragment in viewpager
             // so check if update is for this fragment
             if(forMe(xyzData)) {
               // do whatever you want to update your UI
             }
        }
    }
    

    和接口:

    public interface UpdateableFragment {
       public void update(UpdateData xyzData);
    }
    

    您的数据类:

    public class UpdateData {
        //whatever you want here
    }
    

    匿名用户

    对于那些仍然面临同样问题的人,我以前在有一个带有7个片段的viewpager时也遇到过同样的问题。默认情况下,这些片段从API服务加载英语内容,但这里的问题是,我想从设置activity更改语言,在完成设置activity后,我想在主activity中的ViewPager刷新片段,以匹配用户选择的语言,并加载阿拉伯语内容,如果用户在这里选择阿拉伯语,我从第一次开始做了什么

    1-必须如上所述使用FragmentStatePagerAdapter。

    2-在mainActivity上,我重写onResume并执行以下操作

    if (!(mPagerAdapter == null)) {
        mPagerAdapter.notifyDataSetChanged();
    }
    

    3-I重写了mPagerAdapter中的GetItemPosition(),并使其返回Position_None

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

    像魅力一样的作品