我无法更新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
在使用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;
}
像魅力一样的作品