本文出自 “阿敏其人” 简书博客,转载或引用请注明出处。
Toorbar现在已经被广泛使用了,但是多个Fragment之间使用Toorbar的使用可能会遇到menu消失的问题,单就本来这点不必成文,但是一想到好像还没有写过关Fragment声明周期的和复用的文章,就干脆记录一下算了,后面如果需要拿起来参考也算可以。
文章分三点进行描述,第一点说的是Fragment的生命周期,大可忽略之,第二点说的是如何利用add和hide避免重复创建Fragment,老生常谈也可忽略之,第三点说是让每一个Toolbar对应不同的Toolbar的menu,这个还是可以稍微参考一下的。
一、以事务replace方式简述生命周期
先上图,再代码,后分析
上代码
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
一样,一图二码三分析
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>
这里的布局我调整了一下,这样的布局使用了后期需要添加比如小红点之类的特殊需求
注意:
android:id="@+id/fragment_container"
的view应该是FrameLayout,勘误
至于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
一图二码三分析
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的布局文件
机智如你,必然明了。
本文至此完。
代码链接