一、碎片的概念(Fragment)
1、碎片:是一种可以嵌入在活动当中的UI片段,他能让程序更加合理和充分地利用大屏幕的空间。
2、碎片可以被认为是迷你型的活动,在一个活动中可以引用多个碎片,这样就可以充分利用活动界面空间
二、碎片的使用
2.1 碎片的创建和实现
1、新建一个左侧碎片布局left_fragment.xml和右侧碎片布局right_fragment,并添加一些控件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Button"
/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#00ff00"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="20sp"
android:text="This is right fragment"
/>
</LinearLayout>
2、分别创建一个LeftFragment类和RightFragment类,均继承Fragment类,重写onCreateView()方法,这样就创造了两个碎片
public class LeftFragment extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.left_fragment,container,false);
return view;
}
}
public class RightFragment extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.right_fragment,container,false);
return view;
}
}
3、在主活动布局activity_main.xml中实现代码
<fragment
android:id="@+id/left_fragment"
android:name="com.example.testfragment.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight = "1"/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.testfragment.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight = "1"/>
android:name 用于显示指明要添加的碎片的类在包下所处的位置
2.2 动态地添加碎片
1、在上述操作的基础上,再新建一个another_right_fragment.xml布局文件,添加控件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#ffff00"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
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>
2、新建一个AnotherRightFragment类作为另一个右侧碎片,继承Fragment,实现代码
public class AnotherRightFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.another_right_fragment,container,false);
return view;
}
}
3、在activity_main.xml中,实现代码
<fragment
android:id="@+id/left_fragment"
android:name="com,example.fragmenttest.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight = "1"/>
<FrameLayout
android:id="@+id/right_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight = "1">
</FrameLayout>
我们将平板中的右侧碎片换成一个FrameLayout布局
4、在主活动中,动态添加碎片
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(this);
replaceFragment(new RightFragment());//换前碎片,直接在屏幕上显示
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.botton:
replaceFragment(new AnotherRightFragment());//换前碎片,点击按钮后显示
break;
default:
break;
}
}
private void replaceFragment(Fragment fragment){
//2、构造placeFragment()方法,获取FragmentManager,在活动中调用getSupportFragmentManager()方法得到
FragmentManager fragmentManager = getSupportFragmentManager();
//3、开启一个事务,调用beginTransaction();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//4、向容器内添加或替换碎片,用replace()实现
fragmentTransaction.replace(R.id.right_layout,fragment);
//5、调用commit()方法提交事务
fragmentTransaction.commit();
}
}
1、创建一个replaceFragment()方法,在onCreate()方法中调用该方法并传入一个Fragment对象,动态添加对象的实例
2、构造placeFragment()方法,获取FragmentManager,在活动中调用getSupportFragmentManager()方法得到
3、开启一个事务,调用beginTransaction();
4、向容器内添加或替换碎片,用replace()实现
5、调用commit()方法提交事务
2.3 在碎片中模拟返回栈
在一般情况下,碎片中摁下Back键,程序会直接退出;如若想实现摁下back键回到碎片前一个碎片,即实现返回栈功能,则需要在replaceFragment()
方法提交事务前添加下面这一行代码:
fragmentTransaction.addToBackStack(null);
//该方法可以接受一个名字用于描述返回栈的状态,此时摁下back键,程序会回到前一个碎片界面
三、碎片的声明周期
3.1 碎片的状态和回调
1、状态
- 运行状态 :当一个碎片可见时,且所关联的活动正处于运行状态时,该碎片也处于运行状态
- 暂停状态:当一个活动进入暂停状态,与他相关联的可见碎片就会进入暂停状态
- 停止状态:当一个活动进入停止状态,与它相关联的碎片就会进入停止状态
- 销毁状态:活动被销毁时,碎片也会跟着被销毁
2、回调方法
- onAttach():当碎片和活动建立关联时调用
- onCreateView():为碎片创建视图时调用
- onActivityCreated():确保与碎片相关联的活动一定已经创建完毕时调用
- onDestroyView():当与碎片关联的视图被移除时调用
- onDetach():当碎片与活动解除关联时调用
3、碎片完整的生命周期示意图:
四、动态加载布局的技巧
4.1 使用限定符
限定符:用于判断程序应该使用单页模式还是双页模式
举例实现:
1、修改activity_main.xml中的代码,只保留左侧碎片且让他充满整个父布局
<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_fragment"
android:name="com.example.testfragment.LeftFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
2、在res目录下新建layout_large文件夹,在这个文件夹下新建一个布局,且名字也叫做activity_main.xml,代码如下:
<?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_fragment"
android:name="com.example.testfragment.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.testfragment.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
3、通过比较,发现第一个同名布局文件只包含了一个碎片,即单页模式
;第二个同名布局文件包含了两个碎片,即双页模式
。其中layout-large文件夹下的large是个限定符,那些屏幕被认为时large的设备就会自动加载layout-large文件夹下的布局,反之也是一样。因此若是在手机模拟器上运行,则会引用第一个布局文件,若是在平板模拟器上运行,则会引用第二个布局文件
4、Android系统中一些常见的限定符参考博客 常见限定符
4.2 最小宽度限定符的使用
最小宽度限定符允许我们对屏幕的宽度指定一个最小值(以dp为基本单位),然后以这个最小值为临界点,屏幕宽度大于这个值的设备就加载一个布局,反之就加载小于这个宽度的布局,具体设置方法,在layout文件后面加上后缀-sw600dp
(以600dp为界限)即可。