使用 ViewPager 的主从视图

Master-Detail View using ViewPager

我想更改 Android phone 应用程序的主从实施。目前,用户可以从 ListView 中 select 项目,打开新的 activity。要 select 一个不同的 activity,用户必须 return 到列表。我希望用户使用 ViewPager 左右滑动来翻阅文档,而不是这种 pogo-sticking。可能有很多文档,所以我想一次最多加载 3 页 - 当前页面、上一页和下一页。来回翻页应该左右添加和删除页面。我创建了一个实现 FragmentStatePagerAdapter 的适配器,可以很好地处理静态内容(例如 TextViews)。删除页面似乎也可以正常工作(此处未包括)。但是当我添加例如EditText 内容在分页时从一页复制到下一页。

下面是适配器和 activity 的代码。我有两个问题:

  1. 我的适配器有什么问题导致 EditText 从一个片段意外复制到下一个片段?
  2. 这是我的第一次尝试,它可能远非最佳实施。但我发现这是一个如此常见的用例,以至于我几乎觉得会有一个现成的框架。这可以更容易地实现吗?

寻呼机适配器:

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());
    }
}