碎片:
Fragment(碎片)是一种可以嵌入在Activity中的UI片段,他能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用的非常广泛。
基本使用方法:
首先,需要创建碎片的布局:
left_frag.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ffff"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="this is a left frag"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
然后,创建类继承自Fragment类,并重写onCreateView方法,返回我们刚才写好的布局:
package com.example.fragmenttest;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class LeftFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.left_frag,container);
return view;
}
}
最后,我们在Activity布局里面引用碎片:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/left_frag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:name="com.example.fragmenttest.LeftFragment"
/>
<fragment
android:id="@+id/right_frag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:name="com.example.fragmenttest.RightFragment"
/>
</LinearLayout>
注意这里的RightFragment布局代码基本与LeftFragment一致,不再给出。
效果图如下:
动态添加碎片时发现的小问题:
当我尝试动态添加的时候报了如下错误:
指定的子view已经有了父布局,你必须先移除他的父布局,其实我前面写Frament类引入布局的时候埋下了伏笔
View view=inflater.inflate(R.layout.left_frag,container);
这里inflate函数,第三个参数表示是否将当前资源id的布局加到第二个参数对应的父布局上。而默认情况下,若第二个参数不为空,第三个参数默认为true。因此,我们为了能够动态添加碎片,第三个参数应当手动传入false。
View view=inflater.inflate(R.layout.left_frag,container,false);
动态添加碎片:
在发现问题之后,我们就可以正常来写动态添加碎片的代码了。
首先,修改Activity布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/left_frag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:name="com.example.fragmenttest.LeftFragment"
/>
<FrameLayout
android:id="@+id/fl_main"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
</LinearLayout>
在处理 Fragment 时(尤其是在运行时添加 Fragment 时),需遵循的一个重要原则是,您的 Activity 布局必须包含一个可以插入 Fragment 的容器 View。
然后,开始写动态添加的代码:
private void addFragment() {
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.add(R.id.fl_main,new RightFragment());
transaction.commit();
}
最后,再写一个替换碎片的代码:
private void replaceFragment() {
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.replace(R.id.fl_main,new AnotherFragment());
transaction.addToBackStack("mTask");
transaction.commit();
}
效果图:
与上面直接在布局里面添加一样,然后我们再来调用替换函数,得到以下结果
transaction.addToBackStack(“mTask”);这句话会将碎片添加到返回栈,这样当我们点击手机Back键会回到上一个碎片,而不是直接退出程序。
Fragment与Activity之间通信:
碎片可通过 getActivity() 访问 FragmentActivity 实例,并轻松执行在 Activity 布局中查找视图等任务(请不要在onCreateView中执行如下语句,因为此时Activity还未创建完成,会出现空指针异常,可以在onActivityCreated中执行):
View listView = getActivity().findViewById(R.id.list);
同样,您的 Activity 也可使用 findFragmentById() 或 findFragmentByTag(),通过从 FragmentManager 获取对 Fragment 的引用来调用片段中的方法。例如:
FrameLayout mFragment=getSupportFragmentManager().findFragmentById(R.id.right_frag);
碎片的生命周期:
碎片必须始终托管在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。例如,当 Activity 暂停时,Activity 的所有片段也会暂停;当 Activity 被销毁时,所有片段也会被销毁。
当Activity处于运行状态时,碎片的生命周期图
通常,您至少应实现以下生命周期方法:
onCreate()
系统会在创建片段时调用此方法。当片段经历暂停或停止状态继而恢复后,如果您希望保留此片段的基本组件,则应在您的实现中将其初始化。
onCreateView()
系统会在片段首次绘制其界面时调用此方法。如要为您的片段绘制界面,您从此方法中返回的 View 必须是片段布局的根视图。如果片段未提供界面,您可以返回 null。
onPause()
系统会将此方法作为用户离开片段的第一个信号(但并不总是意味着此片段会被销毁)进行调用。通常,您应在此方法内确认在当前用户会话结束后仍然有效的任何更改(因为用户可能不会返回)。
碎片还有几个额外的生命周期回调,用于处理与 Activity 的唯一交互,从而执行构建和销毁片段界面等操作。这些额外的回调方法是:
onAttach()
在片段已与 Activity 关联时进行调用(Activity 传递到此方法内)。
onCreateView()
调用它可创建与片段关联的视图层次结构。
onActivityCreated()
当 Activity 的 onCreate() 方法已返回时进行调用。
onDestroyView()
在移除与片段关联的视图层次结构时进行调用。
onDetach()
在取消片段与 Activity 的关联时进行调用。