文章目录
- 为什么要使用碎片(Fragment)
- 实例
- 布局文件
- Fragment
- Activity
- 动态添加碎片
- 布局文件
- Fragment
- Activity
- 碎片通信
- Fragment
- 布局文件
- Activity
- 生命周期
为什么要使用碎片(Fragment)
我们在手机上看新闻可能是这样的:
- RecyclerView 显示了一组新闻标题
- 点击一个新闻后会跳转到新界面显示详细内容
但当设备屏幕很大时,我们完全可以将 RecyclerView 和 详细内容 分别放在两个 碎片 中,然后引入同一个 活动:
Fragment 的定义为小活动,同样具有生命周期,但比一个 Activity 更细化的管理空间。
实例
布局文件
定义两个布局文件:
left_fragment.xml
:
<LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"><Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="Button"/></LinearLayout>
right_fragment.xml
:
<LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"android:background="#00ff00"android:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"><TextViewandroid:id="@+id/tx1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:textSize="20sp"android:text="This is right fragment"/></LinearLayout>
fragment_layout.xml
:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><fragmentandroid:id="@+id/left_fragment"android:name="com.example.activitytest.Fragment.LeftFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/><fragmentandroid:id="@+id/right_fragment"android:name="com.example.activitytest.Fragment.RightFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/>
</LinearLayout>
Fragment
LeftFragment.java
:
public class LeftFragment extends Fragment {@Override// 重写Fragment中onCreateView方法public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentreturn inflater.inflate(R.layout.left_fragment, container, false);}
}
RightFragment.java
:
public class RightFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentreturn inflater.inflate(R.layout.right_fragment, container, false);}
}
Activity
FragmentActivity.java
:
public class FragmentActivity extends AppCompatActivity {protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.fragment_layout);}
}
运行结果:
动态添加碎片
Fragment 碎片的真正强大的地方在于可以在程序运行过程中动态地添加到活动中,下面将做一个点击按钮切换右边碎片的案例:
布局文件
rightfrag_two.xml
:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:background="#ffff00"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/tx2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:textSize="20sp"android:text="This is another right fragment"/>
</LinearLayout>
修改 fragment_layout.xml
,将右侧碎片替换成一个 FrameLayout 布局:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><fragmentandroid:id="@+id/left_fragment"android:name="com.example.activitytest.Fragment.LeftFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/><!--<fragmentandroid:id="@+id/right_fragment"android:name="com.example.activitytest.Fragment.RightFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/>--><FrameLayoutandroid:id="@+id/right_layout"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"/>
</LinearLayout>
Fragment
public class RightFragTwo extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.rightfrag_two, container, false);}
}
Activity
修改 FragmentActivity.java
,实现通过点击 左侧 Button 按钮来动态替换 RightFragment 和 RightFragTwo 两个碎片:
public class FragmentActivity extends AppCompatActivity implements View.OnClickListener {int type = 1; // 辅助判断当前right_layout的布局是RightFragment还是RightFragTwoprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.fragment_layout);Button button1 = findViewById(R.id.button_1); // fragment_layout.xml中replaceFragment(new RightFragment());button1.setOnClickListener(this);}private void replaceFragment(Fragment fragment){// 获取碎片管理器FragmentManager supportFragmentManager = getSupportFragmentManager();// 获取事务,beginTransaction开启一个事务FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();// 提供 容器id 和 待添加的碎片实例,实现像容器内动态替换碎片fragmentTransaction.replace(R.id.right_layout, fragment);// 提交事务fragmentTransaction.commit();}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.button_1:if(type == 1){replaceFragment(new RightFragTwo());type = 2;}else{replaceFragment(new RightFragment());type = 1;}break;}}
}
此时虽然实现了动态替换,但是会发现直接点击 Back 会退出程序,可以使用 fragmentTransaction.replace(R.id.right_fragment, fragment);
方法,它可以接受一个名字用于描述返回栈的状态,一般传入 null
即可:
碎片通信
碎片通信又可细分为 碎片和活动之间进行通信、碎片和碎片之间通信。这里实现前者的一个实例:
Fragment
修改一下 RightFragment.java
,在其中添加一个 TextView 成员,用于在其它类中管理 TextView 的内容:
public class RightFragment extends Fragment {public TextView textView;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentView view = inflater.inflate(R.layout.right_fragment, container, false);textView = view.findViewById(R.id.tx1);return view;}
}
布局文件
在 left_fragment.xml
中再添加一个 button_2:
<Buttonandroid:id="@+id/button_2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="send"/>
其作用是更改 RightFragment.java
中 TextView 的内容。为了实现这一功能,我们需要修改 FragmentActivity.java
文件:
Activity
创建 button_2
的实例 button2
,并设置监听事件:
在 onClick
方法中完善点击 button2
之后的操作:
- 通过
findFragmentById
方法获取并创建相应碎片的实例 - 通过设置该实例更改 TextView 控件的内容
运行结果:
生命周期
碎片的生命周期内有四种状态:
- 运行状态: 当一个碎片是可见的,并且所关联的活动也是正在处于运行状态的时候,该碎片处于运行状态。
- 暂停状态: 当一个活动处于暂停状态时(另一个未占满屏幕的活动处于栈顶),与它相关联的可见碎片也处于暂停状态。
- 停止状态: 当一个活动处于停止状态时,与它相关联的碎片也会进入到停止状态,或者调用了 FragmentTransaction 的
remove()
、replace()
方法将碎片从活动中移除,并且在事务提交之前调用addToBackStack()
方法,这时碎片也会进入到停止状态。进入到停止状态的碎片对用户来说是完全不可见的,也有可能会被系统回收。 - 销毁状态: 当活动被销毁时,与它相关联的碎片也会进入到销毁状态,或者调用了 FragmentTransaction 的
remove()
、replace()
方法将碎片从活动中移除,并且在事务提交之前没有调用addToBackStack()
方法,碎片也会进入到销毁状态。
活动中有的回调方法碎片中几乎都有,且提供了一些附加的回调方法:
- onAttach(): 当碎片和活动建立关联的时候调用
- onCreateView(): 为碎片创建视图(加载布局)时调用
- onActivityCreated(): 确保与碎片相关联的活动一定已经创建完毕的时候调用
- onDestroyView(): 当与碎片关联的视图被移除的时候调用
- onDetach(): 当碎片和活动解除关联的时候调用