美文网首页TECH_ANDROID
Fragment复用和Fragment独立Toorbar Men

Fragment复用和Fragment独立Toorbar Men

作者: 阿敏其人 | 来源:发表于2016-11-26 13:49 被阅读936次

    本文出自 “阿敏其人” 简书博客,转载或引用请注明出处。

    Toorbar现在已经被广泛使用了,但是多个Fragment之间使用Toorbar的使用可能会遇到menu消失的问题,单就本来这点不必成文,但是一想到好像还没有写过关Fragment声明周期的和复用的文章,就干脆记录一下算了,后面如果需要拿起来参考也算可以。

    文章分三点进行描述,第一点说的是Fragment的生命周期,大可忽略之,第二点说的是如何利用add和hide避免重复创建Fragment,老生常谈也可忽略之,第三点说是让每一个Toolbar对应不同的Toolbar的menu,这个还是可以稍微参考一下的。

    一、以事务replace方式简述生命周期

    先上图,再代码,后分析

    gif依次12341.gif

    上代码

    Activity

    public class StyleFirstActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {
        private RadioGroup mRbTab;
        private RadioButton mRbOne;
        private RadioButton mRbTwo;
        private RadioButton mRbThree;
        private RadioButton mRbFour;
        private OneFragment oneFragment;
        private TwoFragment twoFragment;
        private ThreeFragment threeFragment;
        private FourFragment fourFragment;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mRbTab = (RadioGroup) findViewById(R.id.mRbTab);
            mRbOne = (RadioButton) findViewById(R.id.mRbOne);
            mRbTwo = (RadioButton) findViewById(R.id.mRbTwo);
            mRbThree = (RadioButton) findViewById(R.id.mRbThree);
            mRbFour = (RadioButton) findViewById(R.id.mRbFour);
            mRbTab.setOnCheckedChangeListener(this);
            commitOneFrag();
        }
        // MainActivty实现接口的必须复写的方法
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            FragmentManager fm = getSupportFragmentManager(); // getSupportFragmentManager(); 才是v4的
            FragmentTransaction transaction = fm.beginTransaction();  // Fragment的事务
            switch (checkedId) {
                case R.id.mRbOne:
                    if (oneFragment == null) {
                        oneFragment = new OneFragment();
                    }
                    transaction.replace(R.id.mFlWaitReplace, oneFragment);
                    break;
                case R.id.mRbTwo:
                    if (twoFragment == null) {
                        twoFragment = new TwoFragment();
                    }
                    transaction.replace(R.id.mFlWaitReplace, twoFragment);
                    break;
                case R.id.mRbThree:
                    if (threeFragment == null) {
                        threeFragment = new ThreeFragment();
                    }
                    transaction.replace(R.id.mFlWaitReplace, threeFragment);
                    break;
                case R.id.mRbFour:
                    if (fourFragment == null) {
                        fourFragment = new FourFragment();
                    }
                    transaction.replace(R.id.mFlWaitReplace, fourFragment);
                    break;
            }
            transaction.commit();
        }
        private void commitOneFrag() {
            OneFragment oneFrag = new OneFragment();
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.mFlWaitReplace, oneFrag);
            ft.commit();
        }
    }
    

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:tools="http://schemas.android.com/tools"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:background="#fff2f2f2"
                  tools:context=".activity.StyleFirstActivity"
                  android:orientation="vertical"
        >
        <FrameLayout
            android:id="@+id/mFlWaitReplace"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            ></FrameLayout>
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#ffdddddd"
            />
        <RadioGroup
            android:id="@+id/mRbTab"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_gravity="center_vertical"
            android:orientation="horizontal" >
            <RadioButton
                android:id="@+id/mRbOne"
                style="@style/tab_style"
                android:drawableTop="@drawable/ic1"
                android:text="首页" />
            <RadioButton
                android:id="@+id/mRbTwo"
                style="@style/tab_style"
                android:drawableTop="@drawable/ic2"
                android:text="社区" />
            <RadioButton
                android:id="@+id/mRbThree"
                style="@style/tab_style"
                android:drawableTop="@drawable/ic3"
                android:text="购物车" />
            <RadioButton
                android:id="@+id/mRbFour"
                style="@style/tab_style"
                android:drawableTop="@drawable/ic4"
                android:text="我的" />
        </RadioGroup>
    </LinearLayout>
    

    .
    .
    .
    Fragment,四个都类似,以为OneFragmemt为例子

    public class OneFragment extends Fragment {
        private View rootView;
        @Nullable
        @Override
        public View onCreateView(LayoutInflater infater, ViewGroup container, Bundle savedInstanceState) {
            Log.d(GeneralConst.TAG,"OneFragment --- onCreateView");
            rootView = View.inflate(getActivity(), R.layout.fragment_one, null);
            initView();
            return rootView;
        }
        private void initView() {
            rootView.findViewById(R.id.mTvOne).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(getActivity(),"FragmentOne的Tv点击",Toast.LENGTH_SHORT).show();
                }
            });
        }
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            Log.d(GeneralConst.TAG,"OneFragment --- onAttach");
        }
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(GeneralConst.TAG,"OneFragment --- onCreate");
        }
        @Override
        public void onStart() {
            super.onStart();
            Log.d(GeneralConst.TAG,"OneFragment --- onStart");
        }
        @Override
        public void onResume() {
            super.onResume();
            Log.d(GeneralConst.TAG,"OneFragment --- onResume");
        }
        @Override
        public void onPause() {
            super.onPause();
            Log.d(GeneralConst.TAG,"OneFragment --- onPause");
        }
        @Override
        public void onStop() {
            super.onStop();
            Log.d(GeneralConst.TAG,"OneFragment --- onStop");
        }
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            Log.d(GeneralConst.TAG,"OneFragment --- onDestroyView");
        }
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.d(GeneralConst.TAG,"OneFragment --- onDestroy");
        }
        @Override
        public void onDetach() {
            super.onDetach();
            Log.d(GeneralConst.TAG,"OneFragment --- onDetach");
        }
    }
    

    Fragment和Activity的生命周期较为相似了。
    只是Fragment有几个Activity中没有的新方法,这里需要重点介绍一下:

    • onAttach方法:Fragment和Activity建立关联的时候调用。
    • onCreateView方法:为Fragment加载布局时调用。
    • onActivityCreated方法:当Activity中的onCreate方法执行完后调用。
    • onDestroyView方法:Fragment中的布局被移除时调用。
    • onDetach方法:Fragment和Activity解除关联的时候调用。

    进入该Activity,依次点击第一,第二,第三,第四,第一个Fragment

    现在对点击进行分析:

    执行了5个生命周期方法,对比其他的这里只是,这里这是执行了5个,原因是因为我们一进入这个Activity默认就进入了第一个Activity,然后我们再次点击了第一个,相当于重复点击了两次第一个。

    11-23 08:30:28.712 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onAttach
    
    11-23 08:30:28.712 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onCreate
    
    11-23 08:30:28.712 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onCreateView
    
    11-23 08:30:28.712 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onStart
    
    11-23 08:30:28.712 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onResume
    
    --- 分割线 ---
    
    11-23 08:30:31.269 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onAttach
    
    11-23 08:30:31.269 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onCreate
    
    11-23 08:30:31.269 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onPause
    
    11-23 08:30:31.269 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onStop
    
    11-23 08:30:31.269 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onDestroyView
    
    11-23 08:30:31.269 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onDestroy
    
    11-23 08:30:31.269 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onDetach
    
    11-23 08:30:31.269 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onCreateView
    
    11-23 08:30:31.270 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onStart
    
    11-23 08:30:31.270 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onResume
    
    --- 分割线 ---
    
    11-23 08:30:32.350 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onAttach
    
    11-23 08:30:32.350 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onCreate
    
    11-23 08:30:32.350 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onPause
    
    11-23 08:30:32.350 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onStop
    
    11-23 08:30:32.350 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onDestroyView
    
    11-23 08:30:32.350 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onDestroy
    
    11-23 08:30:32.350 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onDetach
    
    11-23 08:30:32.350 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onCreateView
    
    11-23 08:30:32.351 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onStart
    
    11-23 08:30:32.351 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onResume
    
    --- 分割线 ---
    
    11-23 08:30:33.033 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onAttach
    
    11-23 08:30:33.033 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onCreate
    
    11-23 08:30:33.033 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onPause
    
    11-23 08:30:33.033 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onStop
    
    11-23 08:30:33.033 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onDestroyView
    
    11-23 08:30:33.033 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onDestroy
    
    11-23 08:30:33.033 11279-11279/com.amqr.testfragment D/FragTest: TwoFragment --- onDetach
    
    11-23 08:30:33.033 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onCreateView
    
    11-23 08:30:33.035 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onStart
    
    11-23 08:30:33.035 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onResume
    
    --- 分割线 ---
    
    11-23 08:30:33.699 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onAttach
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onCreate
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onPause
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onStop
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onDestroyView
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onDestroy
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: ThreeFragment --- onDetach
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onCreateView
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onStart
    
    11-23 08:30:33.700 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onResume
    
    --- 分割线 ---
    
    11-23 08:30:34.833 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onAttach
    
    11-23 08:30:34.833 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onCreate
    
    11-23 08:30:34.833 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onPause
    
    11-23 08:30:34.833 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onStop
    
    11-23 08:30:34.833 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onDestroyView
    
    11-23 08:30:34.833 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onDestroy
    
    11-23 08:30:34.834 11279-11279/com.amqr.testfragment D/FragTest: FourFragment --- onDetach
    
    11-23 08:30:34.834 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onCreateView
    
    11-23 08:30:34.839 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onStart
    
    11-23 08:30:34.839 11279-11279/com.amqr.testfragment D/FragTest: OneFragment --- onResume
    
    

    如上,我们看的出来,以这种方式构建,每次点击切换到一个Fragment,至少都会执行5个方法

    onAttach
    
    onCreate
    
     onCreateView
    
    onStart
    
    onResume
    

    如果是切换那么会相应交织着上一个被销毁的过程(正因为上一个被销毁,所以我们点击新的Fragment才会有重新创建)

    这里关键是明白一点,我们这里的新切换的Fragment都会有一个onCreate和onCreateView过程,这在大多数情况下不是我们想要的,对于页面复杂的Fragment是比较消耗内存的,这不是我们想看到的。

    产生这个问题的主要原因是我们采用了replace()方法来替换Fragment。

    关于这个老生常谈的问题就到此为止。

    关于Fragment生命周期可以参考Android Fragment完全解析,关于碎片你所需知道的一切

    二、利用事务的add和hide复用Fragment

    一样,一图二码三分析

    复用12341332.gif

    Activity

    public class StyleSecondActivity extends AppCompatActivity{
        private Button[] mTabs;
        // ======== 四个TAB
        private OneFragment sOneFragment;
        private TwoFragment sTwoFragment;
        private ThreeFragment sThreeFragment;
        private FourFragment sFourFragment;
        private Fragment[] fragments;
        private int index;
        private int currentTabIndex;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_style_second);
            mTabs = new Button[4];
            mTabs[0] = (Button) findViewById(R.id.mBtOneFragment);
            mTabs[1] = (Button) findViewById(R.id.mBtTwoFragment);
            mTabs[2] = (Button) findViewById(R.id.mBtThreeFragment);
            mTabs[3] = (Button) findViewById(R.id.mBtFourFragment);
            // select first tab
            mTabs[0].setSelected(true);
            // 实例化Tab
            sOneFragment = new OneFragment();
            sTwoFragment = new TwoFragment();
            sThreeFragment = new ThreeFragment();
            sFourFragment = new FourFragment();
            fragments = new Fragment[]{sOneFragment, sTwoFragment,  sThreeFragment, sFourFragment};
            // 一开始只把 第一个 和 第二个 Fragment添加到事务里面,(方便切换时有数据)
            // 然后默认展示第一个,第二个隐藏起来
            getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, sOneFragment)
                    .add(R.id.fragment_container, sTwoFragment).hide(sTwoFragment).show(sOneFragment)
                    .commit();
        }
        /**
         * 每一个按钮都带有android:onClick="onTabClicked"
         * 不采用常规的复写onClick而采用这种方式,是为了统一操作这些按钮
         * @param view
         */
        public void onTabClicked(View view) {
            switch (view.getId()) {
                case R.id.mBtOneFragment:
                    index = 0;
                    break;
                case R.id.mBtTwoFragment:
                    index = 1;
                    break;
                case R.id.mBtThreeFragment:
                    index = 2;
                    break;
                case R.id.mBtFourFragment:
                    index = 3;
                    break;
            }
            if (currentTabIndex != index) { // 切换了Fragment
                FragmentTransaction trx = getSupportFragmentManager().beginTransaction();
                trx.hide(fragments[currentTabIndex]); // 隐藏原来的
                if (!fragments[index].isAdded()) { // 如果当前的没有被添加到FragmentTransaction,添加之
                    trx.add(R.id.fragment_container, fragments[index]);
                }
                trx.show(fragments[index]).commit(); // 添加事务,切换Fragment
            }
            mTabs[currentTabIndex].setSelected(false);
            mTabs[index].setSelected(true);
            currentTabIndex = index;
        }
    }
    

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:id="@+id/mainLayout"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                     >
        <LinearLayout
            android:id="@+id/main_bottom"
            android:layout_width="match_parent"
            android:layout_height="52dp"
            android:layout_alignParentBottom="true"
            android:background="@color/gray1"
            android:gravity="center_vertical"
            android:orientation="horizontal" >
            <RelativeLayout
                android:id="@+id/btn_container_conversation"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" >
                <Button
                    android:id="@+id/mBtOneFragment"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@color/transparent"
                    android:drawableTop="@drawable/ic1"
                    android:onClick="onTabClicked"
                    android:paddingBottom="2dip"
                    android:paddingTop="7dip"
                    android:scaleType="matrix"
                    android:text="诗词"
                    android:textColor="@color/em_main_botton_text_color"
                    android:textSize="10sp" />
            </RelativeLayout>
            <RelativeLayout
                android:id="@+id/btn_container_address_list"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" >
                <Button
                    android:id="@+id/mBtTwoFragment"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@color/transparent"
                    android:drawableTop="@drawable/ic2"
                    android:onClick="onTabClicked"
                    android:paddingBottom="2dip"
                    android:paddingTop="7dip"
                    android:scaleType="matrix"
                    android:text="歌赋"
                    android:textColor="@color/em_main_botton_text_color"
                    android:textSize="10sp" />
    、
            </RelativeLayout>
            <RelativeLayout
                android:id="@+id/btn_info"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" >
                <Button
                    android:id="@+id/mBtThreeFragment"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@color/gray1"
                    android:drawableTop="@drawable/ic3"
                    android:onClick="onTabClicked"
                    android:paddingBottom="2dip"
                    android:paddingTop="7dip"
                    android:scaleType="matrix"
                    android:text="春秋"
                    android:textColor="@color/em_main_botton_text_color"
                    android:textSize="10sp" />
            </RelativeLayout>
            <RelativeLayout
                android:id="@+id/btn_container_me"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" >
                <Button
                    android:id="@+id/mBtFourFragment"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@color/transparent"
                    android:drawableTop="@drawable/ic4"
                    android:onClick="onTabClicked"
                    android:paddingBottom="2dip"
                    android:paddingTop="7dip"
                    android:scaleType="matrix"
                    android:text="大学"
                    android:textColor="@color/em_main_botton_text_color"
                    android:textSize="10sp" />
            </RelativeLayout>
        </LinearLayout>
        <RelativeLayout
            android:id="@+id/fragment_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/main_bottom" />
    </RelativeLayout>
    

    这里的布局我调整了一下,这样的布局使用了后期需要添加比如小红点之类的特殊需求

    至于Fragment,同第一大点,就不附加了。

    .
    .
    .

    分析

    运行,然会我们分别点击 1234 1332 ,(1代表第一个Fragment)

    11-23 09:45:28.081 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onAttach
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onCreate
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onAttach
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onCreate
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onCreateView
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onCreateView
    11-23 09:45:28.083 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onStart
    11-23 09:45:28.083 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onStart
    11-23 09:45:28.083 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onResume
    11-23 09:45:28.083 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onResume
    --- 分割线 ---
    11-23 09:45:32.124 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onAttach
    11-23 09:45:32.124 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onCreate
    11-23 09:45:32.124 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onCreateView
    11-23 09:45:32.125 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onStart
    11-23 09:45:32.125 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onResume
    
    --- 分割线 ---
    
    11-23 09:45:33.003 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onAttach
    11-23 09:45:33.003 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onCreate
    11-23 09:45:33.004 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onCreateView
    11-23 09:45:33.004 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onStart
    11-23 09:45:33.004 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onResume
    

    我们一旦进入Activity,首先因为代码的关系,我们先让Fragment的事务添加进入第一个和第二个Fragment

    所以在什么都没有点击的情况下,先执行了

    11-23 09:45:28.081 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onAttach
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onCreate
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onAttach
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onCreate
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onCreateView
    11-23 09:45:28.082 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onCreateView
    11-23 09:45:28.083 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onStart
    11-23 09:45:28.083 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onStart
    11-23 09:45:28.083 16526-16526/com.amqr.testfragment D/FragTest: OneFragment --- onResume
    11-23 09:45:28.083 16526-16526/com.amqr.testfragment D/FragTest: TwoFragment --- onResume
    

    然会我们点击分别点击1和2,日志没有变化,这就对了,这就是我们想要的结果

    我们点击3的时候,日志输出了

    11-23 09:45:32.124 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onAttach
    11-23 09:45:32.124 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onCreate
    11-23 09:45:32.124 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onCreateView
    11-23 09:45:32.125 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onStart
    11-23 09:45:32.125 16526-16526/com.amqr.testfragment D/FragTest: ThreeFragment --- onResume
    

    我们点击4的时候,日志产生的结果是

    11-23 09:45:33.003 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onAttach
    
    11-23 09:45:33.003 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onCreate
    
    11-23 09:45:33.004 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onCreateView
    
    11-23 09:45:33.004 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onStart
    
    11-23 09:45:33.004 16526-16526/com.amqr.testfragment D/FragTest: FourFragment --- onResume
    

    (因为3和4我们之前还没有添加进入事务里面)

    再后来,我们分别切换到1、3、3和4的时候,日志无变化,这也对了。

    因为我们采取的是add和hide,添加和隐藏嘛。

    .
    .
    .

    三、每一个Fragment对应一个Toolbar和menu

    一图二码三分析

    nemu.gif

    gif说明:第二个Fragment弹出菜单的的红色是因为模拟器的关系,真机完美运行你懂得。

    上代码
    Activity
    以这种add和hide的方式就不会每次都执行onCreateView,避免效果必要的内存。

    /**
     *
     * 整体思路,一进入Activity只add进入头两个Fragment,而且hide第二个,展示第一个
     * 以后如果切换到任意的Fragment,那么先判断事务里面有没有这个Fragment,
     * 无则加之,然后隐藏上一个,展示当前新切换到的
     * 有则隐藏上一个,展示当前的新切换到的
     */
    public class StyleSecondActivity extends AppCompatActivity {
    
        private Button[] mTabs;
    
        // ======== 四个TAB
        private OneFragment sOneFragment;
        private TwoFragment sTwoFragment;
        private ThreeFragment sThreeFragment;
        private FourFragment sFourFragment;
    
    
        private Fragment[] fragments;
        private int index;
        private int currentTabIndex;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_style_second);
    
            mTabs = new Button[4];
            mTabs[0] = (Button) findViewById(R.id.mBtOneFragment);
            mTabs[1] = (Button) findViewById(R.id.mBtTwoFragment);
            mTabs[2] = (Button) findViewById(R.id.mBtThreeFragment);
            mTabs[3] = (Button) findViewById(R.id.mBtFourFragment);
    
    
    
            // select first tab
            mTabs[0].setSelected(true);
    
            // 实例化Tab
            sOneFragment = new OneFragment();
            sTwoFragment = new TwoFragment();
            sThreeFragment = new ThreeFragment();
            sFourFragment = new FourFragment();
    
            fragments = new Fragment[]{sOneFragment, sTwoFragment,  sThreeFragment, sFourFragment};
    
            // 一开始只把 第一个 和 第二个 Fragment添加到事务里面,(方便切换时有数据)
            // 然后默认展示第一个,第二个隐藏起来
            getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, sOneFragment)
                    .add(R.id.fragment_container, sTwoFragment).hide(sTwoFragment).show(sOneFragment)
                    .commit();
        }
    
        /**
         * 每一个按钮都带有android:onClick="onTabClicked"
         * 不采用常规的复写onClick而采用这种方式,是为了统一操作这些按钮
         * @param view
         */
        public void onTabClicked(View view) {
            switch (view.getId()) {
                case R.id.mBtOneFragment:
                    index = 0;
                    break;
                case R.id.mBtTwoFragment:
                    index = 1;
                    break;
    
                case R.id.mBtThreeFragment:
                    index = 2;
                    break;
                case R.id.mBtFourFragment:
                    index = 3;
                    break;
            }
            if (currentTabIndex != index) { // 切换了Fragment
                FragmentTransaction trx = getSupportFragmentManager().beginTransaction();
    
                trx.hide(fragments[currentTabIndex]); // 隐藏原来的
                if (!fragments[index].isAdded()) { // 如果当前的没有被添加到FragmentTransaction,添加之
                    trx.add(R.id.fragment_container, fragments[index]);
                }
                trx.show(fragments[index]).commit(); // 添加事务,切换Fragment
            }
            mTabs[currentTabIndex].setSelected(false);
            mTabs[index].setSelected(true);
            currentTabIndex = index;
        }
    
    }
    

    .
    .
    .
    两个Fragment

    SpcOneFragment

    public class SpcOneFragment extends Fragment {
        private View rootView;
        private Toolbar mToolBar;
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            Log.d(GeneralConst.TAG,"SpcOneFragment --- onCreateView");
            rootView = View.inflate(getActivity(), R.layout.fragment_spc_one, null);
            initView();
            setHasOptionsMenu(true); // 让Fragment的菜单按钮生效
            return rootView;
        }
        private void initView() {
            rootView.findViewById(R.id.mTvOne).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(getActivity(),"SpcOneFragment的Tv点击",Toast.LENGTH_SHORT).show();
                }
            });
    
    
            mToolBar = (Toolbar) rootView.findViewById(R.id.mToolBar);
            mToolBar.setTitle("拥抱世界");
            ((AppCompatActivity) getActivity()).setSupportActionBar(mToolBar); // 这样切换后Fragment会失效
    
            mToolBar.setOverflowIcon(getResources().getDrawable(R.drawable.icon_menu)); // 指定菜单按钮图标
            mToolBar.inflateMenu(R.menu.menu_diy);
    
            //mToolBar.inflateMenu(R.menu.menu_diy);
            mToolBar.setOnMenuItemClickListener(onMenuItemClick); // 菜单按钮点击监听
    
            mToolBar.setNavigationIcon(R.drawable.arrow_left); // 返回箭头
            mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    getActivity().finish();
                }
            });
    
        }
    
        // 创建关联菜单
        // 下面这里先clean后inflate这么写是为了避免Fragment和Activity同是带有Toolbar,再加重复的东西
        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            //((AppCompatActivity) getActivity()).getMenuInflater().inflate(R.menu.menu_diy, menu);
    
            menu.clear();
            inflater.inflate(R.menu.menu_diy, menu);
            super.onCreateOptionsMenu(menu, inflater);
    
    
        }
    
        // 菜单的点击回调
        private Toolbar.OnMenuItemClickListener onMenuItemClick = new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                switch (menuItem.getItemId()) {
                    case R.id.item_hello:
                        Toast.makeText(getActivity(),"白衣少年",Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.item_boy:
                        Toast.makeText(getActivity(),"少年,热闹海岸线",Toast.LENGTH_SHORT).show();
                        break;
                }
    
                return true;
            }
        };
    
    }
    

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    xmlns:app="http://schemas.android.com/apk/res-auto"
        >
        <android.support.v7.widget.Toolbar
            android:id="@+id/mToolBar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:elevation="4dp"
            android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            >
        </android.support.v7.widget.Toolbar>
    
        <TextView
            android:id="@+id/mTvOne"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_gravity="center"
            android:text="SpcOneFragment"
            android:textSize="20dp" />
        
    </RelativeLayout>
    

    menu文件

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          xmlns:tools="http://schemas.android.com/tools"
          tools:context=".MainActivity" >
    
        <item android:id="@+id/item_hello"
              android:title="你好"
              android:orderInCategory="90"
              app:showAsAction="never" />
    
        <item android:id="@+id/item_boy"
              android:title="少年"
              android:orderInCategory="90"
              app:showAsAction="never" />
    </menu>
    

    另外一个Fragment就不附代码了,类似。

    分析阶段:

    我们想让每个Fragment都对应有自己的menu,就要注意下面几步
    1、在onCreateView里面执行
    setHasOptionsMenu(true); // 让Fragment的菜单按钮生效
    而且最好是在所有Toolbar相关操作的前面,不然可能不生效

    2、在onCreateOptionsMenu方法里面使用
    inflater.inflate(R.menu.menu_diy, menu);
    这样方式去加载menu文件,而不是
    ((AppCompatActivity)getActivity()).getMenuInflater().inflate(R.menu.menu_diy, menu);

    嗯,大概就是这样啦。

    如果你想说为什么我第二个Fragment可以这样子背景、颜色位置,两个Fragment的溢出菜单的样式可以自定义,那么请你看下我的style文件和关于Fragment的布局文件

    style文件,重点看AppTheme3和OverflowMenuStyle

    <resources>
    
        <!-- Base application theme. -->
        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
        </style>
    
        <style name="AppTheme2" parent="Theme.AppCompat.Light.NoActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
    
        </style>
        <style name="AppTheme3" parent="Theme.AppCompat.Light.NoActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>  <!--溢出菜单样式-->
    
        </style>
    
        <!-- Toolbar 溢出菜单的样式 -->
        <style name="OverflowMenuStyle" parent="@style/Widget.AppCompat.PopupMenu.Overflow">
            <!-- 是否覆盖锚点,默认为true,即盖住Toolbar -->
            <item name="overlapAnchor">false</item>
            <!-- 弹出层背景颜色 -->
            <item name="android:popupBackground">@color/flow_bg</item>
            <!-- 弹出层垂直方向上的偏移,即在竖直方向上距离Toolbar的距离,值为负则会盖住Toolbar -->
            <item name="android:dropDownVerticalOffset">0dp</item>
    
            <!-- 弹出层水平方向上的偏移,即距离屏幕左边的距离,负值会导致右边出现空隙 -->
            <item name="android:dropDownHorizontalOffset">-10dp</item>
            <item name="actionMenuTextColor">@color/flow_text_color</item> <!--  指定字体颜色-->
            <item name="android:textColorPrimary">@color/flow_text_color</item> <!--指定之日颜色-->
        </style>
    
    
        <!--主页底部导航按钮的样式-->
        <style name="tab_style">
            <item name="android:layout_width">match_parent</item>
            <item name="android:layout_height">wrap_content</item>
            <item name="android:layout_gravity">center_vertical</item>
            <item name="android:layout_weight">1</item>
            <item name="android:background">@android:color/transparent</item>
            <item name="android:button">@null</item>
            <item name="android:gravity">center</item>
            <item name="android:textColor">@drawable/selector_tab_text_color</item>
            <item name="android:textSize">10sp</item>
        </style>
        
    </resources>
    

    .
    .
    .

    然后你看一下我第二个Fragment的布局文件

    Paste_Image.png

    机智如你,必然明了。

    本文至此完。


    代码链接

    git Link
    csdn Link

    相关文章

      网友评论

        本文标题:Fragment复用和Fragment独立Toorbar Men

        本文链接:https://www.haomeiwen.com/subject/sgxgpttx.html