我正在使用兼容性库中的ViewPager。我已经成功地让它显示几个视图,我可以通过页面。
但是,我很难弄清楚如何用一组新的视图更新ViewPager。
我已经尝试了各种各样的事情,比如调用mAdapter.notifyDataSetChanged(), mviewpage .invalidate(),甚至在每次我想使用新的数据列表时创建一个全新的适配器。
没有任何帮助,textviews保持不变,从原始数据。
更新:
我做了一个小测试项目,我几乎能够更新视图。我将在下面粘贴这个类。
然而,似乎没有更新的是第二个视图,“B”仍然存在,它应该在按下更新按钮后显示“Y”。
public class ViewPagerBugActivity extends Activity {
private ViewPager myViewPager;
private List<String> data;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
data = new ArrayList<String>();
data.add("A");
data.add("B");
data.add("C");
myViewPager = (ViewPager) findViewById(R.id.my_view_pager);
myViewPager.setAdapter(new MyViewPagerAdapter(this, data));
Button updateButton = (Button) findViewById(R.id.update_button);
updateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
updateViewPager();
}
});
}
private void updateViewPager() {
data.clear();
data.add("X");
data.add("Y");
data.add("Z");
myViewPager.getAdapter().notifyDataSetChanged();
}
private class MyViewPagerAdapter extends PagerAdapter {
private List<String> data;
private Context ctx;
public MyViewPagerAdapter(Context ctx, List<String> data) {
this.ctx = ctx;
this.data = data;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object instantiateItem(View collection, int position) {
TextView view = new TextView(ctx);
view.setText(data.get(position));
((ViewPager)collection).addView(view);
return view;
}
@Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager) collection).removeView((View) view);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
}
@Override
public void startUpdate(View arg0) {
}
@Override
public void finishUpdate(View arg0) {
}
}
}
我想,我有ViewPager的逻辑。
如果我需要刷新一组页面并基于新的数据集显示它们,我调用notifyDataSetChanged()。
然后,ViewPager对getItemPosition()进行多次调用,将Fragment作为对象传递给那里。这个片段可以来自旧数据集(我想要丢弃的数据集),也可以来自新数据集(我想要显示的数据集)。因此,我重写了getItemPosition(),在那里我必须以某种方式确定我的片段是来自旧数据集还是来自新数据集。
In my case I have a 2-pane layout with a list of top items on the left pane and a swipe view (ViewPager) on the right. So, I store a link to my current top item inside my PagerAdapter and also inside of each instantiated page Fragment.
When the selected top item in the list changes, I store the new top item in PagerAdapter and call notifyDataSetChanged(). And in the overridden getItemPosition() I compare the top item from my adapter to the top item from my fragment.
And only if they are not equal, I return POSITION_NONE.
Then, PagerAdapter reinstantiates all the fragments that have returned POSITION_NONE.
请注意。存储顶部项id而不是引用可能是一个更好的主意。
下面的代码片段有点示意图,但我从实际工作的代码中改编了它。
public class SomeFragment extends Fragment {
private TopItem topItem;
}
public class SomePagerAdapter extends FragmentStatePagerAdapter {
private TopItem topItem;
public void changeTopItem(TopItem newTopItem) {
topItem = newTopItem;
notifyDataSetChanged();
}
@Override
public int getItemPosition(Object object) {
if (((SomeFragment) object).getTopItemId() != topItem.getId()) {
return POSITION_NONE;
}
return super.getItemPosition(object);
}
}
感谢之前所有的研究人员!
我使用Tablayout与ViewPagerAdapter。为了在片段之间传递数据或在片段之间进行通信,使用下面的代码,它工作得非常好,并在片段出现时刷新它。第二段点击按钮里面写下面的代码。
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text=e1.getText().toString(); // get the text from EditText
// move from one fragment to another fragment on button click
TabLayout tablayout = (TabLayout) getActivity().findViewById(R.id.tab_layout); // here tab_layout is the id of TabLayout which is there in parent Activity/Fragment
if (tablayout.getTabAt(1).isSelected()) { // here 1 is the index number of second fragment i-e current Fragment
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
Intent i = new Intent("EDIT_TAG_REFRESH");
i.putExtra("MyTextValue",text);
lbm.sendBroadcast(i);
}
tablayout.getTabAt(0).select(); // here 0 is the index number of first fragment i-e to which fragment it has to moeve
}
});
下面是必须在第一个片段(在我的情况下)i-e中接收片段的代码。
MyReceiver r;
Context context;
String newValue;
public void refresh() {
//your code in refresh.
Log.i("Refresh", "YES");
}
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(context).unregisterReceiver(r);
}
public void onResume() {
super.onResume();
r = new MyReceiver();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(r,
new IntentFilter("EDIT_TAG_REFRESH"));
} // this code has to be written before onCreateview()
// below code can be written any where in the fragment
private class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
PostRequestFragment.this.refresh();
String action = intent.getAction();
newValue=intent.getStringExtra("MyTextValue");
t1.setText(newValue); // upon Referesh set the text
}
}
alvarolb给出的答案绝对是最好的方法。基于他的回答,实现这一点的一个简单方法是简单地按位置存储活动视图:
SparseArray<View> views = new SparseArray<View>();
@Override
public Object instantiateItem(View container, int position) {
View root = <build your view here>;
((ViewPager) container).addView(root);
views.put(position, root);
return root;
}
@Override
public void destroyItem(View collection, int position, Object o) {
View view = (View)o;
((ViewPager) collection).removeView(view);
views.remove(position);
view = null;
}
然后,一旦覆盖notifyDataSetChanged方法,您就可以刷新视图…
@Override
public void notifyDataSetChanged() {
int key = 0;
for(int i = 0; i < views.size(); i++) {
key = views.keyAt(i);
View view = views.get(key);
<refresh view with new data>
}
super.notifyDataSetChanged();
}
实际上,您可以在instantiateItem和notifyDataSetChanged中使用类似的代码来刷新视图。在我的代码中,我使用了完全相同的方法。
我有同样的问题,我的解决方案是使用FragmentPagerAdapter覆盖FragmentPagerAdapter#getItemId(int位置):
@Override
public long getItemId(int position) {
return mPages.get(position).getId();
}
默认情况下,此方法返回项目的位置。我认为ViewPager检查itemId是否被更改,只有当它被更改时才重新创建页面。但是未覆盖的版本返回与itemId相同的位置,即使页面实际上不同,ViewPager没有定义页面被替换并需要重新创建。
要使用此功能,每个页面都需要长id。通常,它应该是唯一的,但我建议,对于这种情况,它应该不同于相同页面的前一个值。因此,在适配器或随机整数(具有广泛的分布)中使用连续计数器是可能的。
我认为这是更一致的方式,而不是使用标签的视图作为解决方案,在这个主题中提到。但可能不是所有情况都适用。