替换片段A ViewPager内 [英] Replace Fragment inside a ViewPager

查看:204
本文介绍了替换片段A ViewPager内的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图用FragmentPagerAdapter使用片段与ViewPager。 我正在寻找的实现是更换一个片段,定位在ViewPager的第一页,用一个又一个。

寻呼机由两页组成。第一个是FirstPagerFragment,第二个是SecondPagerFragment。点击的第一页的一个按钮。我想,以取代与NextFragment的FirstPagerFragment。

下面有我的code。

 公共类FragmentPagerActivity扩展FragmentActivity {

    静态最终诠释NUM_ITEMS = 2;

    MyAdapter mAdapter;
    ViewPager mPager;

    @覆盖
    保护无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.fragment_pager);

        mAdapter =新MyAdapter(getSupportFragmentManager());

        mPager =(ViewPager)findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);

    }


    / **
     *寻呼机适配器
     * /
    公共静态类MyAdapter扩展FragmentPagerAdapter {
        公共MyAdapter(FragmentManager FM){
            超(FM);
        }

        @覆盖
        公众诠释getCount将(){
            返回NUM_ITEMS;
        }

        @覆盖
        公共片段的getItem(INT位置){

            如果(位置== 0){
                返回FirstPageFragment.newInstance();
            } 其他 {
                返回SecondPageFragment.newInstance();
            }

        }
    }


    / **
     *第二个页面片段
     * /
    公共静态类SecondPageFragment扩展片段{

        公共静态SecondPageFragment的newInstance(){
            SecondPageFragment F =新SecondPageFragment();
            返回F;
        }

        @覆盖
        公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
            //Log.d("D​​EBUG,onCreateView);
            返回inflater.inflate(R.layout.second,集装箱,假);

        }
    }

    / **
     *第一页面片段
     * /
    公共静态类FirstPageFragment扩展片段{

        Button按钮;

        公共静态FirstPageFragment的newInstance(){
            FirstPageFragment F =新FirstPageFragment();
            返回F;
        }

        @覆盖
        公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
            //Log.d("D​​EBUG,onCreateView);
            查看根= inflater.inflate(R.layout.first,集装箱,假);
            按钮=(按钮)root.findViewById(R.id.button);
            button.setOnClickListener(新OnClickListener(){

                @覆盖
                公共无效的onClick(视图v){
                    FragmentTransaction反= getFragmentManager()的BeginTransaction()。
                                    trans.replace(R.id.first_fragment_root_id,NextFragment.newInstance());
                    trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
                    trans.addToBackStack(空);
                    trans.commit();

                }

            });

            返回根;
        }

        / **
     *在第一页下页片段
     * /
    公共静态类NextFragment扩展片段{

        公共静态NextFragment的newInstance(){
            NextFragment F =新NextFragment();
            返回F;
        }

        @覆盖
        公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
            //Log.d("D​​EBUG,onCreateView);
            返回inflater.inflate(R.layout.next,集装箱,假);

        }
    }
}
 

...这里的XML文件

fragment_pager.xml

 < XML版本=1.0编码=UTF-8&GT?;
< LinearLayout中的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
        机器人:方向=垂直机器人:填充=4dip
        机器人:重力=center_horizo​​ntal
        机器人:layout_width =match_parent机器人:layout_height =match_parent>

    < android.support.v4.view.ViewPager
            机器人:ID =@ + ID /寻呼机
            机器人:layout_width =match_parent
            机器人:layout_height =match_parent
            机器人:layout_weight =1>
    < /android.support.v4.view.ViewPager>

< / LinearLayout中>
 

first.xml

 < XML版本=1.0编码=UTF-8&GT?;
< LinearLayout中的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
  机器人:ID =@ + ID / first_fragment_root_id
  机器人:方向=垂直
  机器人:layout_width =match_parent
  机器人:layout_height =match_parent>

  <按钮机器人:ID =@ + ID /按钮
     机器人:layout_width =WRAP_CONTENT机器人:layout_height =WRAP_CONTENT
     机器人:文本=下一个/>

< / LinearLayout中>
 

现在的问题...我应该在

使用的ID

  trans.replace(R.id.first_fragment_root_id,NextFragment.newInstance());
 

如果我用R.id.first_fragment_root_id,更换工作,但层次查看器显示一个奇怪的现象,如下图所示。

目前的开头的情况

更换后的情况是

正如你所看到的有什么不对,我希望找到后,我更换片段显示为第一张照片相同的状态。

解决方案

目前,这并不需要修改 ViewPager 来源$ C ​​$ c和<$另一种解决方案C $ C> FragmentStatePagerAdapter ,以及它的工作原理与使用人提供的 FragmentPagerAdapter 基类。

我想先回答笔者的了解,他应该使用的标识问题;它是容器的ID,即图寻呼机本身的ID。然而,正如你可能已经注意到自己,使用该ID在code使任何事情发生。我将解释为什么:

首先,使 ViewPager 重新填充的网页,您需要调用 notifyDataSetChanged()驻留在基类的适配器。

其次, ViewPager 使用 getItemPosition()抽象的方法来检查哪些网页应该被销毁,这应该是保留。此函数的默认实现总是返回 POSITION_UNCHANGED ,这将导致 ViewPager 来保存所有当前的页面,因此没有附加的新的一页。因此,为了使片段置换工作, getItemPosition()需要在你的适配器被覆盖,并且不能返回 POSITION_NONE 调用时有一个古老的,被隐藏,片段作为参数。<​​/ P>

这也意味着你的适配器,总是需要知道,应该显示在位置0, FirstPageFragment NextFragment 。这样做的一个方法是创建 FirstPageFragment ,当它是时候切换片段将被调用时提供的监听器。我觉得这是一件好事,但是,让你的片段适配器处理所有片段交换机和调用 ViewPager FragmentManager

三, FragmentPagerAdapter 缓存使用的片段通过它是从位置导出,所以,如果有一个片段在位置0名称,则它不会被即使更换这个类是新的。有两个解决方案,但最简单的方法是使用 FragmentTransaction 删除()的功能,这将删除其标签为好。

这是一个大量的文字,这里是code应该在你的情况是:

 公共类MyAdapter扩展FragmentPagerAdapter
{
    静态最终诠释NUM_ITEMS = 2;
    私人最终FragmentManager mFragmentManager;
    私人片段mFragmentAtPos0;

    公共MyAdapter(FragmentManager FM)
    {
        超(FM);
        mFragmentManager = FM;
    }

    @覆盖
    公共片段的getItem(INT位置)
    {
        如果(位置== 0)
        {
            如果(mFragmentAtPos0 == NULL)
            {
                mFragmentAtPos0 = FirstPageFragment.newInstance(新FirstPageFragmentListener()
                {
                    公共无效onSwitchToNextFragment()
                    {
                        。mFragmentManager.beginTransaction()删除(mFragmentAtPos0).commit();
                        mFragmentAtPos0 = NextFragment.newInstance();
                        notifyDataSetChanged();
                    }
                });
            }
            返回mFragmentAtPos0;
        }
        其他
            返回SecondPageFragment.newInstance();
    }

    @覆盖
    公众诠释getCount将()
    {
        返回NUM_ITEMS;
    }

    @覆盖
    公众诠释getItemPosition(Object对象)
    {
        如果(的instanceof FirstPageFragment和放大器的对象;&安培; mFragmentAtPos0的instanceof NextFragment)
            返回POSITION_NONE;
        返回POSITION_UNCHANGED;
    }
}

公共接口FirstPageFragmentListener
{
    无效onSwitchToNextFragment();
}
 

希望这可以帮助任何人!

I'm trying to use Fragment with a ViewPager using the FragmentPagerAdapter. What I'm looking for to achieve is to replace a fragment, positioned in the first page of the ViewPager, with another one.

The pager is composed by two pages. The first one is the FirstPagerFragment, the second one is the SecondPagerFragment. Clicking on a button of the first page. I'd like to to replace the FirstPagerFragment with the NextFragment.

There is my code below.

public class FragmentPagerActivity extends FragmentActivity {

    static final int NUM_ITEMS = 2;

    MyAdapter mAdapter;
    ViewPager mPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_pager);

        mAdapter = new MyAdapter(getSupportFragmentManager());

        mPager = (ViewPager) findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);

    }


    /**
     * Pager Adapter
     */
    public static class MyAdapter extends FragmentPagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return NUM_ITEMS;
        }

        @Override
        public Fragment getItem(int position) {

            if(position == 0) {
                return FirstPageFragment.newInstance();
            } else {
                return SecondPageFragment.newInstance();
            }

        }
    }


    /**
     * Second Page FRAGMENT
     */
    public static class SecondPageFragment extends Fragment {

        public static SecondPageFragment newInstance() {
            SecondPageFragment f = new SecondPageFragment();
            return f;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            //Log.d("DEBUG", "onCreateView");
            return inflater.inflate(R.layout.second, container, false);

        }
    }

    /**
     * FIRST PAGE FRAGMENT
     */
    public static class FirstPageFragment extends Fragment {

        Button button;

        public static FirstPageFragment newInstance() {
            FirstPageFragment f = new FirstPageFragment();
            return f;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            //Log.d("DEBUG", "onCreateView");
            View root = inflater.inflate(R.layout.first, container, false);
            button = (Button) root.findViewById(R.id.button);
            button.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    FragmentTransaction trans = getFragmentManager().beginTransaction();
                                    trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());
                    trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
                    trans.addToBackStack(null);
                    trans.commit();

                }

            });

            return root;
        }

        /**
     * Next Page FRAGMENT in the First Page
     */
    public static class NextFragment extends Fragment {

        public static NextFragment newInstance() {
            NextFragment f = new NextFragment();
            return f;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            //Log.d("DEBUG", "onCreateView");
            return inflater.inflate(R.layout.next, container, false);

        }
    }
}

...and here the xml files

fragment_pager.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:padding="4dip"
        android:gravity="center_horizontal"
        android:layout_width="match_parent" android:layout_height="match_parent">

    <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1">
    </android.support.v4.view.ViewPager>

</LinearLayout>

first.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/first_fragment_root_id"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <Button android:id="@+id/button"
     android:layout_width="wrap_content" android:layout_height="wrap_content"
     android:text="to next"/>

</LinearLayout>

Now the problem... which ID should I use in

trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());

?

If I use R.id.first_fragment_root_id, the replacement works, but Hierarchy Viewer shows a strange behavior, as below.

At the beginning the situation is

after the replacement the situation is

As you can see there is something wrong, I expect to find the same state shown as in the first picture after I replace the fragment.

解决方案

There is another solution that does not need modifying the source code of ViewPager and FragmentStatePagerAdapter, and it works with the FragmentPagerAdapter base class that was used by the author.

I'd like to start by answering the author's question about which ID he should use; it is the ID of the container, i.e. the ID of the view pager itself. However, as you probably noticed yourself, using that ID in your code causes nothing to happen. I will explain why:

First of all, to make ViewPager repopulate the pages, you need to call notifyDataSetChanged() that resides in the base class of your adapter.

Second, ViewPager uses the getItemPosition() abstract method to check which pages should be destroyed and which should be kept. The default implementation of this function always returns POSITION_UNCHANGED, which causes ViewPager to keep all current pages, and consequently not attaching your new page. Thus, to make fragment replacement work, getItemPosition() needs to be overridden in your adapter and must return POSITION_NONE when called with an old, to be hidden, fragment as argument.

This also means that your adapter always needs to be aware of which fragment that should be displayed in position 0, FirstPageFragment or NextFragment. One way of doing this is supplying a listener when creating FirstPageFragment, which will be called when it is time to switch fragments. I think this is a good thing though, to let your fragment adapter handle all fragment switches and calls to ViewPager and FragmentManager.

Third, FragmentPagerAdapter caches the used fragments by a name which is derived from the position, so if there was a fragment at position 0, it will not be replaced even though the class is new. There are two solutions, but the simplest is to use the remove() function of FragmentTransaction, which will remove its tag as well.

That was a lot of text, here is code that should work in your case:

public class MyAdapter extends FragmentPagerAdapter
{
    static final int NUM_ITEMS = 2;
    private final FragmentManager mFragmentManager;
    private Fragment mFragmentAtPos0;

    public MyAdapter(FragmentManager fm)
    {
        super(fm);
        mFragmentManager = fm;
    }

    @Override
    public Fragment getItem(int position)
    {
        if (position == 0)
        {
            if (mFragmentAtPos0 == null)
            {
                mFragmentAtPos0 = FirstPageFragment.newInstance(new FirstPageFragmentListener()
                {
                    public void onSwitchToNextFragment()
                    {
                        mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit();
                        mFragmentAtPos0 = NextFragment.newInstance();
                        notifyDataSetChanged();
                    }
                });
            }
            return mFragmentAtPos0;
        }
        else
            return SecondPageFragment.newInstance();
    }

    @Override
    public int getCount()
    {
        return NUM_ITEMS;
    }

    @Override
    public int getItemPosition(Object object)
    {
        if (object instanceof FirstPageFragment && mFragmentAtPos0 instanceof NextFragment)
            return POSITION_NONE;
        return POSITION_UNCHANGED;
    }
}

public interface FirstPageFragmentListener
{
    void onSwitchToNextFragment();
}

Hope this helps anyone!

这篇关于替换片段A ViewPager内的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆