使用 FragmentActivity 中的 viewPager 更改方向

Posted

技术标签:

【中文标题】使用 FragmentActivity 中的 viewPager 更改方向【英文标题】:Orientation change with viewPager inside FragmentActivity 【发布时间】:2013-02-14 23:42:39 【问题描述】:

我正在尝试构建一个以纵向和横向模式显示书籍的应用。所以很明显有1页以纵向显示,2页以横向显示。每种模式都很好,但是当我将方向从纵向更改为横向时,viewPager 尝试从纵向模式获取 2 页,而不是尝试从横向模式获取 2 个双页... 事实上FragmentStatePagerAdapter 保留了在纵向创建的 2 个片段,并在为横向模式创建 2 个双页之前使用它们。如果我在纵向模式下再次切换,FragmentStatePagerAdapter 使用之前在横向模式下创建的 2 个片段,所以我再次看到 1 个双页而不是 1 个单页等。如果我继续切换方向,我得到一个 OutOfMemoryError,因为 FragmentStatePagerAdapter 从来没有在方向改变时刷新它的碎片。

为了便于理解,这里有 2 个用例:

我以纵向模式启动 viewPager 我看到第 1 页 ok 我向右滑动,我看到第 2 页 ok 我向右滑动,我看到第 3 页 ok 我将屏幕旋转到横向模式 我看错了第 3 页 我向右滑动,我看到第 4 页错误

我向右滑动,我看到第 5 页和第 6 页 ok

我以纵向模式启动 viewPager

我看到第 1 页 ok 我向右滑动,我看到第 2 页 ok 我向右滑动,我看到第 3 页 ok 我向右滑动,我看到第 4 页 ok 我向右滑动,我看到第 5 页 ok 我将屏幕旋转到横向模式 我看错了第 5 页 我向左滑动,我看到第 4 页错误

我向左滑动,我看到第 2 页和第 3 页 ok

public class PlayerFragmentActivity extends FragmentActivity 
private Intent mIntent;
private ViewPager mPortraitPager;
private ViewPager mLandscapePager;
private Boolean mIsLandscape;
private String mKey;
private int mNbPages;
private int mNbDoublePages;
private PageFactory mPageFactory;
private DoublePageFactory mDoublePageFactory;
private PagerAdapter mPagerAdapter;

@Override
protected void onStop()
    super.onStop();
    mPagerAdapter = null;
    mDoublePageFactory = null;
    mPageFactory = null; 


@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_activity_player);
    mIntent = getIntent();
    mKey = mIntent.getStringExtra("key");
    mNbPages = mIntent.getIntExtra("nbPages", 0);
    mNbDoublePages = DoublePageFactory.getDoublePageNumFromPageNum(mNbPages);

    Resources res = getResources();
    mIsLandscape = (res.getConfiguration().orientation == 1) ? false : true;
    mPortraitPager = (ViewPager) findViewById(R.id.portraitPager);
    mLandscapePager = (ViewPager) findViewById(R.id.landscapePager);

    mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());

    if (mIsLandscape) 
        mDoublePageFactory = new DoublePageFactory(this, mKey, mNbPages, res.getInteger(R.integer.nb_page_columns), res.getInteger(R.integer.nb_page_columns));
        mPortraitPager.setVisibility(View.GONE);
        mLandscapePager.setAdapter(mPagerAdapter);
        mPortraitPager.setAdapter(null);
     else 
        mPageFactory = new PageFactory(this, mKey, this.mNbPages, res.getInteger(R.integer.nb_page_columns), res.getInteger(R.integer.nb_page_columns));
        mLandscapePager.setVisibility(View.GONE);
        mPortraitPager.setAdapter(mPagerAdapter);
        mLandscapePager.setAdapter(null);
    



public class MyPagerAdapter extends FragmentStatePagerAdapter 

    public MyPagerAdapter(FragmentManager fm) 
        super(fm);
    

    @Override
    public Fragment getItem(int position) 
        Bundle args = new Bundle();
        if(mIsLandscape)
            Fragment doublePageFragment = new DoublePageFragment();
            args.putInt(DoublePageFragment.ARG_DOUBLEPAGE_NUM, position + 1);
            doublePageFragment.setArguments(args);
            return doublePageFragment;
        else
            Fragment pageFragment = new PageFragment();
            args.putInt(PageFragment.ARG_PAGE_NUM, position + 1);
            pageFragment.setArguments(args);
            return pageFragment;
        
    

    @Override
    public int getCount() 
        return (mIsLandscape) ? mNbDoublePages:mNbPages;

    

            /* j'ai essayé cette méthode mais ça ne fonctionne pas :( */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) 
            FragmentManager manager = ((Fragment) object).getFragmentManager();
            FragmentTransaction trans = manager.beginTransaction();
            trans.remove((Fragment) object);
            trans.commit();

        super.destroyItem(container, position, object);
    

    @Override
    public int getItemPosition(Object object)
        return PagerAdapter.POSITION_NONE;
    

    @Override
    public CharSequence getPageTitle(int position) 
        return "p." + position + 1;
    


public boolean isLandscape() 
    return mIsLandscape;


public ImageView getSinglePage(int position) 
    return mPageFactory.getPage(position);



public LinearLayout getDoublePage(int position) 
    return mDoublePageFactory.getDoublePage(position);




public class PageFragment extends Fragment     
private PlayerFragmentActivity mPlayerFragmentActivity;
public static final String ARG_PAGE_NUM = "page_number";
public static final String ARG_WOBOOK_DIRECTORY = "book_directory";
public static final String ARG_NB_PAGE_COLUMNS = "nb_page_columns";
public static final String ARG_NB_PAGE_ROWS = "nb_page_rows";

@Override
public ImageView onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    mPlayerFragmentActivity = ((PlayerFragmentActivity) getActivity());
    return mPlayerFragmentActivity.getSinglePage(getArguments().getInt(ARG_PAGE_NUM));


@Override
public void onStop()
    super.onStop();
    mPlayerFragmentActivity = null;

public class DoublePageFragment extends Fragment 
private PlayerFragmentActivity mPlayerFragmentActivity;
public static final String ARG_DOUBLEPAGE_NUM = "double_page_number";
public static final String ARG_WOBOOK_DIRECTORY = "book_directory";
public static final String ARG_NB_PAGE_COLUMNS = "nb_page_columns";
public static final String ARG_NB_PAGE_ROWS = "nb_page_rows";

@Override
public LinearLayout onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    mPlayerFragmentActivity = ((PlayerFragmentActivity) getActivity());
    return mPlayerFragmentActivity.getDoublePage(getArguments().getInt(ARG_DOUBLEPAGE_NUM));


@Override
public void onStop()
    super.onStop();
    mPlayerFragmentActivity = null;


我读到框架中的 FragmentManager 负责保存状态并恢复寻呼机创建的任何活动片段。所以我猜当方向改变时,FragmentManager 会说

嘿!我已经创建了 2 个项目,所以我不需要创建新闻, 让他们得到他们

但实际上它从旧的方向模式中获取了 2 个项目(页面/双页)。所以我需要找到一种方法来在方向发生变化时删除 FragmentManager 保存的片段。

我还测试了this method。问题似乎与this one有关

最好的问候

【问题讨论】:

你是如何解决这个问题的? 【参考方案1】:

尝试将方向限制为纵向或横向模式。因为我们只能在精确模式下使用视图寻呼机。

【讨论】:

以上是关于使用 FragmentActivity 中的 viewPager 更改方向的主要内容,如果未能解决你的问题,请参考以下文章

无法解析扩展 FragmentActivity 的类中的方法 getActivity()

Adobe AIR ANE 中的 FragmentActivity

从 fragmentActivity 刷新片段 UI

尽管 setHasOptionsMenu(true),ActionBar 图标不会显示在 FragmentActivity

Activity、AppCompatActivity、FragmentActivity 和 ActionBarActivity:啥时候使用?

使用 FragmentActivity 的 getSupportActionBar