ast*_*etz 134 android android-viewpager fragmentpageradapter
我正在尝试从ViewPager动态添加和删除片段,添加工作没有任何问题,但删除不能按预期工作.
每次我想删除当前项目时,最后一项将被删除.
我还尝试使用FragmentStatePagerAdapter或在适配器的getItemPosition方法中返回POSITION_NONE.
我究竟做错了什么?
这是一个基本的例子:
MainActivity.java
public class MainActivity extends FragmentActivity implements TextProvider {
private Button mAdd;
private Button mRemove;
private ViewPager mPager;
private MyPagerAdapter mAdapter;
private ArrayList<String> mEntries = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mEntries.add("pos 1");
mEntries.add("pos 2");
mEntries.add("pos 3");
mEntries.add("pos 4");
mEntries.add("pos 5");
mAdd = (Button) findViewById(R.id.add);
mRemove = (Button) findViewById(R.id.remove);
mPager = (ViewPager) findViewById(R.id.pager);
mAdd.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
addNewItem();
}
});
mRemove.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
removeCurrentItem();
}
});
mAdapter = new MyPagerAdapter(this.getSupportFragmentManager(), this);
mPager.setAdapter(mAdapter);
}
private void addNewItem() {
mEntries.add("new item");
mAdapter.notifyDataSetChanged();
}
private void removeCurrentItem() {
int position = mPager.getCurrentItem();
mEntries.remove(position);
mAdapter.notifyDataSetChanged();
}
@Override
public String getTextForPosition(int position) {
return mEntries.get(position);
}
@Override
public int getCount() {
return mEntries.size();
}
private class MyPagerAdapter extends FragmentPagerAdapter {
private TextProvider mProvider;
public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
super(fm);
this.mProvider = provider;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(mProvider.getTextForPosition(position));
}
@Override
public int getCount() {
return mProvider.getCount();
}
}
}
Run Code Online (Sandbox Code Playgroud)
TextProvider.java
public interface TextProvider {
public String getTextForPosition(int position);
public int getCount();
}
Run Code Online (Sandbox Code Playgroud)
MyFragment.java
public class MyFragment extends Fragment {
private String mText;
public static MyFragment newInstance(String text) {
MyFragment f = new MyFragment(text);
return f;
}
public MyFragment() {
}
public MyFragment(String text) {
this.mText = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment, container, false);
((TextView) root.findViewById(R.id.position)).setText(mText);
return root;
}
}
Run Code Online (Sandbox Code Playgroud)
activity_main.xml中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="add new item" />
<Button
android:id="@+id/remove"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="remove current item" />
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)
fragment.xml之
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/position"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="35sp" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)
Lou*_*uth 286
ViewPager不会使用上面的代码删除您的片段,因为它会将多个视图(或您的案例中的片段)加载到内存中.除了可见视图外,它还将视图加载到可见视图的任一侧.这提供了从视图到视图的平滑滚动,使ViewPager非常酷.
要达到您想要的效果,您需要做一些事情.
将FragmentPagerAdapter更改为FragmentStatePagerAdapter.这样做的原因是FragmentPagerAdapter会将它加载的所有视图永久保存到内存中.FragmentStatePagerAdapter处理位于当前和可遍历视图之外的视图.
覆盖适配器方法getItemPosition(如下所示).当我们调用mAdapter.notifyDataSetChanged();
ViewPager时,询问适配器以确定在定位方面发生了哪些变化.我们使用此方法表示所有内容都已更改,因此重新处理所有视图定位.
这是代码......
private class MyPagerAdapter extends FragmentStatePagerAdapter {
//... your existing code
@Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
}
Run Code Online (Sandbox Code Playgroud)
Tim*_*Rae 93
Louth的解决方案还不足以让我的工作正常,因为现有的碎片并没有被破坏.在这个答案的推动下,我发现解决方案是覆盖片段的预期位置发生变化时提供新的唯一ID 的getItemId(int position)
方法FragmentPagerAdapter
.
private class MyPagerAdapter extends FragmentPagerAdapter {
private TextProvider mProvider;
private long baseId = 0;
public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
super(fm);
this.mProvider = provider;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(mProvider.getTextForPosition(position));
}
@Override
public int getCount() {
return mProvider.getCount();
}
//this is called when notifyDataSetChanged() is called
@Override
public int getItemPosition(Object object) {
// refresh all fragments when data set changed
return PagerAdapter.POSITION_NONE;
}
@Override
public long getItemId(int position) {
// give an ID different from position when position has been changed
return baseId + position;
}
/**
* Notify that the position of a fragment has been changed.
* Create a new ID for each position to force recreation of the fragment
* @param n number of items which have been changed
*/
public void notifyChangeInPosition(int n) {
// shift the ID returned by getItemId outside the range of all previous fragments
baseId += getCount() + n;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,例如,如果删除单个选项卡或对订单进行一些更改,则应在调用notifyChangeInPosition(1)
之前调用notifyDataSetChanged()
,这将确保将重新创建所有片段.
覆盖getItemPosition():
当notifyDataSetChanged()
被调用时,适配器调用notifyChanged()
的方法ViewPager
,它是联系在一起的.在ViewPager
随后检查由适配器返回的值getItemPosition()
对每个项目,除去那些返回项目POSITION_NONE
(见源代码),然后重新填充.
覆盖getItemId():
这是防止适配器在重新ViewPager
填充时重新加载旧片段所必需的.您可以通过查看instantiateItem()的源代码来轻松理解其工作原理FragmentPagerAdapter
.
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
Run Code Online (Sandbox Code Playgroud)
如您所见,getItem()
只有在片段管理器找不到具有相同Id的现有片段时才会调用该方法.对我来说,似乎是一个错误,即旧的片段在notifyDataSetChanged()
调用之后仍然附着,但是文档ViewPager
确实明确说明:
请注意,此课程目前正在进行早期设计和开发.API可能会在以后的兼容库更新中发生变化,需要在针对较新版本编译时更改应用程序的源代码.
因此,希望在未来版本的支持库中不需要此处给出的解决方法.
Vas*_*hev 13
我的工作解决方案从视图寻呼机中删除片段页面
public class MyFragmentAdapter extends FragmentStatePagerAdapter {
private ArrayList<ItemFragment> pages;
public MyFragmentAdapter(FragmentManager fragmentManager, ArrayList<ItemFragment> pages) {
super(fragmentManager);
this.pages = pages;
}
@Override
public Fragment getItem(int index) {
return pages.get(index);
}
@Override
public int getCount() {
return pages.size();
}
@Override
public int getItemPosition(Object object) {
int index = pages.indexOf (object);
if (index == -1)
return POSITION_NONE;
else
return index;
}
}
Run Code Online (Sandbox Code Playgroud)
当我需要通过索引删除一些页面时,我这样做
pages.remove(position); // ArrayList<ItemFragment>
adapter.notifyDataSetChanged(); // MyFragmentAdapter
Run Code Online (Sandbox Code Playgroud)
这是我的适配器初始化
MyFragmentAdapter adapter = new MyFragmentAdapter(getSupportFragmentManager(), pages);
viewPager.setAdapter(adapter);
Run Code Online (Sandbox Code Playgroud)
Kat*_*hah 10
该片段必须已被删除,但问题是viewpager保存状态
尝试
myViewPager.setSaveFromParentEnabled(false);
Run Code Online (Sandbox Code Playgroud)
没有任何效果,但这解决了这个问题!
干杯!
归档时间: |
|
查看次数: |
90574 次 |
最近记录: |