使用 ViewPager 的主从视图
Master-Detail View using ViewPager
我想更改 Android phone 应用程序的主从实施。目前,用户可以从 ListView
中 select 项目,打开新的 activity。要 select 一个不同的 activity,用户必须 return 到列表。我希望用户使用 ViewPager
左右滑动来翻阅文档,而不是这种 pogo-sticking。可能有很多文档,所以我想一次最多加载 3 页 - 当前页面、上一页和下一页。来回翻页应该左右添加和删除页面。我创建了一个实现 FragmentStatePagerAdapter
的适配器,可以很好地处理静态内容(例如 TextViews)。删除页面似乎也可以正常工作(此处未包括)。但是当我添加例如EditText
内容在分页时从一页复制到下一页。
下面是适配器和 activity 的代码。我有两个问题:
- 我的适配器有什么问题导致
EditText
从一个片段意外复制到下一个片段?
- 这是我的第一次尝试,它可能远非最佳实施。但我发现这是一个如此常见的用例,以至于我几乎觉得会有一个现成的框架。这可以更容易地实现吗?
寻呼机适配器:
public class DetailPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragments;
private final static String TAG = "DetailPagerAdapter";
public DetailPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
public void addItem(Fragment fragment) {
mFragments.add(fragment);
notifyDataSetChanged();
}
public void removeItem(int position) {
mFragments.remove(position);
notifyDataSetChanged();
}
public void insertItem(int position, Fragment fragment) {
mFragments.add(position, fragment);
notifyDataSetChanged();
}
}
PagingActivity 基础Class:
public abstract class PagingActivity
extends AppCompatActivity
implements ViewPager.OnPageChangeListener {
protected ViewPager mViewPager;
DetailPagerAdapter mViewPagerAdapter;
protected ArrayList<String> mAllItemIds;
private String mPreviousItemId;
private String mCurrentItemId;
private String mNextItemId;
private boolean mMuteOnPageSelected = false;
protected abstract Fragment getNewPageFragment(String id);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<Fragment> initialFragments = new ArrayList<>();
int currentItemIndex = mAllItemIds.indexOf(mCurrentItemId);
int pageSelection = 1;
// Add previous view.
if (currentItemIndex > 0) {
mPreviousItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) - 1);
initialFragments.add(getNewPageFragment(mPreviousItemId));
} else {
pageSelection = 0;
mPreviousItemId = null;
}
// Add current view.
initialFragments.add(getNewPageFragment(mCurrentItemId));
// Add next view.
if (currentItemIndex < mAllItemIds.size() - 1) {
mNextItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) + 1);
initialFragments.add(getNewPageFragment(mNextItemId));
} else {
mNextItemId = null;
}
mViewPagerAdapter = new DetailPagerAdapter(getSupportFragmentManager(), initialFragments);
mViewPager.setAdapter(mViewPagerAdapter);
mViewPager.setCurrentItem(pageSelection);
mViewPager.addOnPageChangeListener(this);
}
@Override
public void onPageSelected(int position) {
if (!mMuteOnPageSelected) {
mCurrentItemId = ((PagingFragment) (mViewPagerAdapter.getItem(mViewPager.getCurrentItem()))).getItemId();
int currentItemIndex = mAllItemIds.indexOf(mCurrentItemId);
// Navigated to the right.
if (position == mViewPagerAdapter.getCount() - 1) {
// Add next if not already pointing at the last available item.
if (currentItemIndex < mAllItemIds.size() - 1) {
mNextItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) + 1);
mViewPagerAdapter.addItem(getNewPageFragment(mNextItemId));
} else {
mNextItemId = null;
}
// If it succeeds remove first item.
int itemCount = mViewPagerAdapter.getCount();
if ((itemCount > 3) || ((itemCount == 3) && (currentItemIndex == mAllItemIds.size() - 1))) {
mMuteOnPageSelected = true;
mViewPagerAdapter.removeItem(0);
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
}
// Navigated to the left.
else if (position == 0) {
// Add item on the left if not already pointing at the first available item.
if (currentItemIndex > 0) {
mPreviousItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) - 1);
mViewPagerAdapter.insertItem(0, getNewPageFragment(mPreviousItemId));
} else {
mPreviousItemId = null;
}
// Check if last item needs to be removed and selection updated.
int itemCount = mViewPagerAdapter.getCount();
if (itemCount == 3) {
if (currentItemIndex == 0) {
// Points to the first of two items.
// -> do not change selection
// -> remove rightmost item.
mViewPagerAdapter.removeItem(itemCount - 1);
} else if (currentItemIndex == mAllItemIds.size() - 2) {
// Will point to the middle of 3 items.
// -> nothing to remove
// -> select middle page.
mMuteOnPageSelected = true;
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
} else if (itemCount > 3) {
// Pager contains 4 items, first item selected.
// -> remove rightmost item
// -> select middle page.
mMuteOnPageSelected = true;
mViewPagerAdapter.removeItem(itemCount - 1);
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
}
mViewPagerAdapter.notifyDataSetChanged();
}
}
}
第二个问题是关键:是的,至少当前状态可以通过让适配器处理所有项数组来更容易地实现。 FragmentStatePagerAdapter
一次只加载所需数量的片段,因此它可以处理我在 activity.
中完成的所有手动工作
寻呼机适配器
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<String> mAllItemIds;
public MyPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mAllItemIds = ...
}
@Override
public int getCount() {
return mAllItemIds.size();
}
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(mAllItemIds.get(position));
}
public void removeItem(int position) {
// add needed code here to remove item also from source
// ...
mAllItemIds.remove(position);
notifyDataSetChanged();
}
}
Activity
public abstract class PagingActivity extends AppCompatActivity {
protected ViewPager mViewPager;
MyPagerAdapter mViewPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = (ViewPager)findViewById(R.id.viewPager);
mViewPagerAdapter = new MyPagerAdapter(this, getSupportFragmentManager());
mViewPager.setAdapter(mViewPagerAdapter);
}
private void deleteItem() {
mViewPagerAdapter.removeItem(mViewPager.getCurrentItem());
}
}
我想更改 Android phone 应用程序的主从实施。目前,用户可以从 ListView
中 select 项目,打开新的 activity。要 select 一个不同的 activity,用户必须 return 到列表。我希望用户使用 ViewPager
左右滑动来翻阅文档,而不是这种 pogo-sticking。可能有很多文档,所以我想一次最多加载 3 页 - 当前页面、上一页和下一页。来回翻页应该左右添加和删除页面。我创建了一个实现 FragmentStatePagerAdapter
的适配器,可以很好地处理静态内容(例如 TextViews)。删除页面似乎也可以正常工作(此处未包括)。但是当我添加例如EditText
内容在分页时从一页复制到下一页。
下面是适配器和 activity 的代码。我有两个问题:
- 我的适配器有什么问题导致
EditText
从一个片段意外复制到下一个片段? - 这是我的第一次尝试,它可能远非最佳实施。但我发现这是一个如此常见的用例,以至于我几乎觉得会有一个现成的框架。这可以更容易地实现吗?
寻呼机适配器:
public class DetailPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragments;
private final static String TAG = "DetailPagerAdapter";
public DetailPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
public void addItem(Fragment fragment) {
mFragments.add(fragment);
notifyDataSetChanged();
}
public void removeItem(int position) {
mFragments.remove(position);
notifyDataSetChanged();
}
public void insertItem(int position, Fragment fragment) {
mFragments.add(position, fragment);
notifyDataSetChanged();
}
}
PagingActivity 基础Class:
public abstract class PagingActivity
extends AppCompatActivity
implements ViewPager.OnPageChangeListener {
protected ViewPager mViewPager;
DetailPagerAdapter mViewPagerAdapter;
protected ArrayList<String> mAllItemIds;
private String mPreviousItemId;
private String mCurrentItemId;
private String mNextItemId;
private boolean mMuteOnPageSelected = false;
protected abstract Fragment getNewPageFragment(String id);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
List<Fragment> initialFragments = new ArrayList<>();
int currentItemIndex = mAllItemIds.indexOf(mCurrentItemId);
int pageSelection = 1;
// Add previous view.
if (currentItemIndex > 0) {
mPreviousItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) - 1);
initialFragments.add(getNewPageFragment(mPreviousItemId));
} else {
pageSelection = 0;
mPreviousItemId = null;
}
// Add current view.
initialFragments.add(getNewPageFragment(mCurrentItemId));
// Add next view.
if (currentItemIndex < mAllItemIds.size() - 1) {
mNextItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) + 1);
initialFragments.add(getNewPageFragment(mNextItemId));
} else {
mNextItemId = null;
}
mViewPagerAdapter = new DetailPagerAdapter(getSupportFragmentManager(), initialFragments);
mViewPager.setAdapter(mViewPagerAdapter);
mViewPager.setCurrentItem(pageSelection);
mViewPager.addOnPageChangeListener(this);
}
@Override
public void onPageSelected(int position) {
if (!mMuteOnPageSelected) {
mCurrentItemId = ((PagingFragment) (mViewPagerAdapter.getItem(mViewPager.getCurrentItem()))).getItemId();
int currentItemIndex = mAllItemIds.indexOf(mCurrentItemId);
// Navigated to the right.
if (position == mViewPagerAdapter.getCount() - 1) {
// Add next if not already pointing at the last available item.
if (currentItemIndex < mAllItemIds.size() - 1) {
mNextItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) + 1);
mViewPagerAdapter.addItem(getNewPageFragment(mNextItemId));
} else {
mNextItemId = null;
}
// If it succeeds remove first item.
int itemCount = mViewPagerAdapter.getCount();
if ((itemCount > 3) || ((itemCount == 3) && (currentItemIndex == mAllItemIds.size() - 1))) {
mMuteOnPageSelected = true;
mViewPagerAdapter.removeItem(0);
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
}
// Navigated to the left.
else if (position == 0) {
// Add item on the left if not already pointing at the first available item.
if (currentItemIndex > 0) {
mPreviousItemId = mAllItemIds.get(mAllItemIds.indexOf(mCurrentItemId) - 1);
mViewPagerAdapter.insertItem(0, getNewPageFragment(mPreviousItemId));
} else {
mPreviousItemId = null;
}
// Check if last item needs to be removed and selection updated.
int itemCount = mViewPagerAdapter.getCount();
if (itemCount == 3) {
if (currentItemIndex == 0) {
// Points to the first of two items.
// -> do not change selection
// -> remove rightmost item.
mViewPagerAdapter.removeItem(itemCount - 1);
} else if (currentItemIndex == mAllItemIds.size() - 2) {
// Will point to the middle of 3 items.
// -> nothing to remove
// -> select middle page.
mMuteOnPageSelected = true;
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
} else if (itemCount > 3) {
// Pager contains 4 items, first item selected.
// -> remove rightmost item
// -> select middle page.
mMuteOnPageSelected = true;
mViewPagerAdapter.removeItem(itemCount - 1);
mViewPager.setCurrentItem(1);
mMuteOnPageSelected = false;
}
}
mViewPagerAdapter.notifyDataSetChanged();
}
}
}
第二个问题是关键:是的,至少当前状态可以通过让适配器处理所有项数组来更容易地实现。 FragmentStatePagerAdapter
一次只加载所需数量的片段,因此它可以处理我在 activity.
寻呼机适配器
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<String> mAllItemIds;
public MyPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mAllItemIds = ...
}
@Override
public int getCount() {
return mAllItemIds.size();
}
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(mAllItemIds.get(position));
}
public void removeItem(int position) {
// add needed code here to remove item also from source
// ...
mAllItemIds.remove(position);
notifyDataSetChanged();
}
}
Activity
public abstract class PagingActivity extends AppCompatActivity {
protected ViewPager mViewPager;
MyPagerAdapter mViewPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = (ViewPager)findViewById(R.id.viewPager);
mViewPagerAdapter = new MyPagerAdapter(this, getSupportFragmentManager());
mViewPager.setAdapter(mViewPagerAdapter);
}
private void deleteItem() {
mViewPagerAdapter.removeItem(mViewPager.getCurrentItem());
}
}