4.碎片(Fragment)
4.1 什么是碎片
碎片(Fragment)是一种可以嵌入在活动当中的UI片段,3.0版本后引入,它能让程序更加合理和充分的利用大屏幕的空间,在平板上应用的非常广。
碎片同样能包含布局,有生命周期,甚至可直接理解为迷你型的活动。碎片是为了解决app在平板上不能充分利用屏幕空间的问题。
4.2 如何使用
4.2.1 简单使用
在一个活动中添加两个碎片,并让这两个碎片平分活动空间
(1)新建左侧碎片布局left_fragment.xml,添加一个按钮,水平居中
(2)新建右侧碎片布局right_fragment.xml,背景设置绿色,添加一个文本控件
(3)新建一个LeftFragment类,继承自Fragment( android.app.Fragment,该包是面向4.0以上系统的),重写onCreateView()方法
public class LeftFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//加载布局并返回
View view = inflater.inflate(R.layout.left_fragment, null);
return view;
}
}
(4)同理创建RightFragment类
(5)修改activity_main.xml:
<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.jastar.fragmenttest.MainActivity">
<!--
1.使用fragment标签来指定碎片
2.通过android:name来指定碎片类名(要加包名)
-->
<fragment
android:id="@+id/left_fragment"
android:name="com.jastar.fragmenttest.fragment.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"></fragment>
<fragment
android:id="@+id/right_fragment"
android:name="com.jastar.fragmenttest.fragment.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"></fragment>
</LinearLayout>
效果如下:
4.2.2 动态添加碎片
(1)同样的新建另一个碎片布局文件以及其对应的java类
(2)修改activity_main.xml中的右侧碎片布局为:
(3)activity中编写代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取左侧碎片中的按钮并注册点击事件
Button button = (Button) findViewById(R.id.btn_left);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_left:
/**
* 动态添加碎片主要分为5步:
* 1.创建待添加的碎片实例
* 2.通过getFragmentManager()方法获取到FragmentManager
* 3.通过FragmentManager的beginTransaction()开启一个事务
* 4.向容器内加入碎片,一般使用replace方法实现
* 5.通过commit()提交事务
*/
AnotherRightFragment fragment = new AnotherRightFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.right_layout, fragment);
transaction.commit();
break;
default:
break;
}
}
});
}
}
4.2.3 在碎片中模拟返回栈
为了实现点击Back返回按钮,仍然回退到原来碎片的效果,在事务commit之前调用下面的方法即可:
transaction.addToBackStack(null);
参数为用于描述返回栈状态的字符串,一般传入null即可。
注意:需要继承Activity才起作用,而现在都是默认继承AppCompatActivity(这是为什么?还有标题栏也是这种情况)
4.2.4 碎片和活动之间进行通信
(1)在活动中调用碎片的方法
FragmentManager提供了一个findFragmentById()方法来获取到活动中的碎片实例,如下代码:
Fragment fragment=getFragmentManager().findFragmentById(R.id.left_fragment);
(2)在碎片中调用活动的方法
MainActivity activity = (MainActivity) getActivity();
4.3 碎片的生命周期
4.3.1 状态
(1)运行状态:当一个碎片是可见的,并且它所关联的活动处于运行状态时。
(2)暂停状态:当一个活动进入暂停状态时(由于另一个未占满屏幕的活动被添加到了栈顶)。
(3)停止状态:当一个活动进入停止状态时,与之关联的碎片将进入停止状态。或者通过调用 FragmentTransaction 的 remove()、replace()方法将碎片从活动中移除,但有在事务提交之前调用 addToBackStack()方法,这时的碎片也会进入到停止状态。停止状态的碎片同样易被回收。
(4)销毁状态:碎片总是依附于活动,当活动被销毁时,碎片也会被销毁。或者通过调用 FragmentTransaction 的 remove()、replace()方法将碎片从活动中移除,但在事务提交之前并没有调用 addToBackStack()方法,这时的碎片也会进入到销毁状态。
4.3.2 回调
活动中有的回调碎片中几乎都有,并且增加了以下回调:
(1)onAttach():当碎片和活动建立关联的时候调用
(2)onCreateView():为碎片创建视图(加载布局)时调用。
(3)onActivityCreated():确保与碎片相关联的活动一定已经创建完毕的时候调用。
(4)onDestroyView():当与碎片关联的视图被移除的时候调用。
(5)onDetach():当碎片和活动解除关联的时候调用。
4.3.3 生命周期
另外,在碎片中也可以调用onSaveInstanceState()方法来保存数据,保存下来的数据在onCreate()、onCreateView()和 onActivityCreated()这三个方法中都可以重新得到。
4.4 动态加载布局的技巧
为了能够让程序根据设备的分辨率或屏幕大小在运行时能够自动加载哪个布局。
4.4.1 使用限定符
方法:为包含碎片的活动单独建立两个布局文件,一个放在layout文件夹下,如layout/activity_main.xml,另一个起同样的名字放在layout-large文件夹下,如layout-large/activity_main.xml,当程序运行时会根据屏幕大小进行自动选择,屏幕小的加载layout文件夹下的布局,屏幕大的加载layout-large文件夹下的布局,large就是一个限定符。
Android中常见的限定符如下:
4.4.2 使用最小宽度限定符
限定符毕竟是限定符,没有一个明确的大小,比如large到底是多大呢?为了更加灵活加载布局,可以设置最小宽度限定符,同样是新建layout文件夹加后缀的形式。
比如:在res目录下新建layout-sw600dp文件夹,当屏幕宽度大于600dp时,则会加载此文件夹下的布局;否则,默认还是加载layout文件夹下的布局。
注意:最小宽度限定符在Android3.2版本引入。