Ixx*_*Ixx 303 android android-fragments android-viewpager
我无法更新ViewPager中的内容.
一个问题:FragmentPagerAdapter类中的方法instantiateItem()和getItem()的关系和正确用法是什么?
我只使用getItem()实例化并返回我的片段:
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
Run Code Online (Sandbox Code Playgroud)
这很好用(但据说我不能改变内容).
所以我发现了这个:ViewPager PagerAdapter没有更新View
特别是在其中讨论了方法instantiateItem():
"我的方法是对instantiateItem()方法中的任何实例化视图使用setTag()方法"
所以现在我想实现instantiateItem()才能做到这一点.但我不知道我必须返回那里(return是Object)和getItem(int position)的关系是什么?
目前我正在使用getItem来实例化Fragment,这是错的吗?但是,我是否必须将片段放在实例变量中,或者根本不实现getItem()......?我只是不明白.
我试过阅读参考资料:
public abstract Fragment getItem(int position)
返回与指定位置关联的片段.
public Object instantiateItem(ViewGroup容器,int位置)
创建给定位置的页面.适配器负责将视图添加到此处给出的容器,但它必须确保在从finishUpdate(ViewGroup)返回时完成此操作.参数
容器包含将在其中显示页面的View.position要实例化的页面位置.
返回
返回表示新页面的Object.这不需要是View,但可以是页面的其他容器.
......但我仍然不明白它们是如何相关的以及我必须做些什么.
这是我的代码.我正在使用支持包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);
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这也是有类似问题的人,没有答案......
http://www.mail-archive.com/android-developers@googlegroups.com/msg200477.html
Bil*_*ips 589
使用FragmentPagerAdapter或FragmentStatePagerAdapter时,最好只处理getItem()
而不是触摸instantiateItem()
.PagerAdapter上的instantiateItem()
- destroyItem()
- isViewFromObject()
接口是FragmentPagerAdapter用来实现更简单getItem()
接口的低级接口.
在进入这个之前,我应该澄清一下
如果要切换显示的实际片段,则需要避免使用FragmentPagerAdapter并使用FragmentStatePagerAdapter.
这个答案的早期版本错误地使用了FragmentPagerAdapter作为它的例子 - 这将无法工作,因为FragmentPagerAdapter在第一次显示片段后永远不会破坏片段.
我不建议您链接的帖子中提供的解决方法setTag()
和findViewWithTag()
解决方法.正如您所发现的那样,使用setTag()
和findViewWithTag()
不使用片段,所以它不是一个很好的匹配.
正确的解决方案是覆盖getItemPosition()
.当notifyDataSetChanged()
被调用时,ViewPager呼吁getItemPosition()
在其适配器的所有项目,看他们是否需要移动到不同的位置或删除.
默认情况下,getItemPosition()
返回POSITION_UNCHANGED
,表示"此对象很好,不要销毁或删除它".返回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;
}
}
});
Run Code Online (Sandbox Code Playgroud)
通过此实现,将仅显示显示新标题的片段.显示仍在列表中的标题的任何片段将被移动到列表中的新位置,并且将销毁具有不再在列表中的标题的片段.
如果片段尚未重新创建,但仍需要更新,该怎么办?生命片段的更新最好由片段本身处理.毕竟这是拥有片段的优势 - 它是它自己的控制器.片段可以将侦听器或观察者添加到其他对象中onCreate()
,然后将其删除onDestroy()
,从而管理更新本身.您不必getItem()
像在ListView或其他AdapterView类型的适配器中那样放置所有更新代码.
最后一件事 - 只是因为FragmentPagerAdapter没有破坏片段并不意味着getItemPosition在FragmentPagerAdapter中完全没用.您仍然可以使用此回调来重新排序ViewPager中的片段.但它永远不会从FragmentManager中完全删除它们.
M-W*_*eEh 136
而不是返回的POSITION_NONE
距离getItemPosition()
,造成众目睽睽娱乐,这样做:
//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);
}
Run Code Online (Sandbox Code Playgroud)
你的片段应该实现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
}
}
}
Run Code Online (Sandbox Code Playgroud)
和界面:
public interface UpdateableFragment {
public void update(UpdateData xyzData);
}
Run Code Online (Sandbox Code Playgroud)
你的数据类:
public class UpdateData {
//whatever you want here
}
Run Code Online (Sandbox Code Playgroud)
Zia*_*ish 20
对于那些仍然遇到我之前遇到的同样问题的人,当我有一个包含7个片段的ViewPager时.这些片段的默认值是从api服务加载英语内容但这里的问题是我想从设置活动更改语言,在完成设置活动后我希望主活动中的ViewPager刷新片段以匹配用户的语言选择并且如果用户在这里选择阿拉伯语,那么加载阿拉伯语内容,这是我第一次做的工作
1-您必须使用如上所述的FragmentStatePagerAdapter.
2-on mainActivity我重写onResume并执行以下操作
if (!(mPagerAdapter == null)) {
mPagerAdapter.notifyDataSetChanged();
}
Run Code Online (Sandbox Code Playgroud)
3-i覆盖了mPagerAdapter中的getItemPosition()并使其返回POSITION_NONE.
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
Run Code Online (Sandbox Code Playgroud)
像魅力一样工作
osc*_*cat 14
我遇到了这个问题,终于在今天解决了,所以我写下了我所学到的东西,我希望它对那些不熟悉Android ViewPager
并且像我一样更新的人有所帮助.我FragmentStatePagerAdapter
在API级别17使用,目前只有2个片段.我认为必定有些不正确的地方,请指正,谢谢.
必须将序列化数据加载到内存中.这可以使用CursorLoader
/ AsyncTask
/ 来完成Thread
.它是否自动加载取决于您的代码.如果您使用的是CursorLoader
,它会自动加载,因为有一个注册的数据观察者.
在您调用之后viewpager.setAdapter(pageradapter)
,将getCount()
不断调用适配器来构建片段.因此,如果正在加载数据,则getCount()
可以返回0,因此您不需要为没有显示的数据创建虚拟片段.
加载数据后,适配器将不会自动构建片段,因为getCount()
它仍为0,因此我们可以设置要返回的实际加载的数据getCount()
,然后调用适配器notifyDataSetChanged()
.ViewPager
开始通过内存中的数据创建片段(只是前2个片段).这是在notifyDataSetChanged()
返回之前完成的.然后ViewPager
你需要正确的片段.
如果数据库和内存中的数据都已更新(直写),或者只更新内存中的数据(写回),或者只更新数据库中的数据.在最后两种情况下,如果数据没有自动从数据库加载到内存(如上所述).在ViewPager
和寻呼机转接器只是处理内存中的数据.
因此,当内存中的数据更新时,我们只需要调用适配器notifyDataSetChanged()
.由于片段已经创建,因此onItemPosition()
将在notifyDataSetChanged(?
返回之前调用适配器.没有什么需要做的getItemPosition()
.然后更新数据.
cza*_*aku 12
在代码中尝试destroyDrawingCache()
使用ViewPager notifyDataSetChanged()
.
Sam*_*awy 10
经过挫折小时,尝试所有上述解决方案来克服这个问题,也像其他类似的问题,尝试了许多解决方案本,这个和这个,所有与我没能解决这个问题,使ViewPager
摧毁旧的Fragment
,并填补了pager
用新Fragment
的.我已经解决了以下问题:
1)使ViewPager
类扩展FragmentPagerAdapter
如下:
public class myPagerAdapter extends FragmentPagerAdapter {
Run Code Online (Sandbox Code Playgroud)
2)为创建一个项目ViewPager
是存储title
和fragment
如下:
public class PagerItem {
private String mTitle;
private Fragment mFragment;
public PagerItem(String mTitle, Fragment mFragment) {
this.mTitle = mTitle;
this.mFragment = mFragment;
}
public String getTitle() {
return mTitle;
}
public Fragment getFragment() {
return mFragment;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public void setFragment(Fragment mFragment) {
this.mFragment = mFragment;
}
}
Run Code Online (Sandbox Code Playgroud)
3)使ViewPager
我的FragmentManager
实例的构造函数将它存储在我class
的下面:
private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;
public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
super(fragmentManager);
mFragmentManager = fragmentManager;
mPagerItems = pagerItems;
}
Run Code Online (Sandbox Code Playgroud)
4)创建重新设置该方法adapter
通过删除所有以前的用新的数据数据fragment
从fragmentManager
自身直接使adapter
设置新fragment
如下又从新的列表:
public void setPagerItems(ArrayList<PagerItem> pagerItems) {
if (mPagerItems != null)
for (int i = 0; i < mPagerItems.size(); i++) {
mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit();
}
mPagerItems = pagerItems;
}
Run Code Online (Sandbox Code Playgroud)
5)从容器中Activity
或Fragment
不用新数据重新初始化适配器.使用以下新数据通过方法设置新数据setPagerItems
:
ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>();
pagerItems.add(new PagerItem("Fragment1", new MyFragment1()));
pagerItems.add(new PagerItem("Fragment2", new MyFragment2()));
mPagerAdapter.setPagerItems(pagerItems);
mPagerAdapter.notifyDataSetChanged();
Run Code Online (Sandbox Code Playgroud)
我希望它有所帮助.
由于某种原因,没有一个答案对我有用,所以我必须覆盖restoreState方法而不在我的fragmentStatePagerAdapter中调用super.码:
private class MyAdapter extends FragmentStatePagerAdapter {
// [Rest of implementation]
@Override
public void restoreState(Parcelable state, ClassLoader loader) {}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
263493 次 |
最近记录: |