碎片(Fragment)是一种可以嵌入在活动当中的UI手段,它能让程序更加合理和充分地利用大屏幕的空间,在平板上应用广泛。碎片有自己的生命周期,可以包含布局,可以称为迷你型活动。活动中是不能嵌套活动的,但是碎片可以嵌套在活动中。
1.碎片的简单用法
在一个活动中添加两个碎片,让这两个碎片平分活动空间。
(1)新建左侧,右侧布局
left_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<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>
right_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff0000">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Hello,World!"
android:textSize="24sp"
android:textColor="#000000"/>
</LinearLayout>
(2)新建LeftFragment类,继承Fragment
需要注意的是,Fragment有两个包供你选择,一个是系统内置的android.app.Fragment,另一个是support库中的androidx.fragment.app.Fragment,建议使用support库中的Fragment,因为它可以让碎片在所有Android系统版本中保存功能一致性,比如说在Fragment中嵌套使用Fragment(Android 4.2系统开始支持),如果选择系统内置的包,那么4.2系统之前的设备运行程序会崩溃。
重写onCreateView()方法,通过LayoutInflater的inflater()方法将定义的left_fragment布局动态加载进来。
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class LeftFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.left_fragment,container,false);
return view;
}
}
同样的,新建LeftFragment类,继承Fragment,将右侧布局动态加载进来。
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class RightFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.right_fragment,container,false);
return view;
}
}
(3)在activity_main布局中添加碎片
通过android:name属性来显式指明要添加的碎片类名,注意要加上类的包名。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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"/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.fragmenttest.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
2.动态添加碎片
在碎片的简单用法基础上添加代码:
(1)新建碎片布局another_fight_fragment.xml,新建AnotherRightFragment类继承Fragment,并将刚刚创建好的布局文件加载进来。
another_fight_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#fff000"
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="24sp"
android:text="Today is a beautiful day!"/>
</LinearLayout>
AnotherRightFragment
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class AnotherRightFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.another_right_fragment,container,false);
return view;
}
}
(2)在activity_main布局中将右侧碎片替换成FrameLayout布局。
<FrameLayout
android:id="@+id/right_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
(3)动态添加碎片主要分5步
- 创建待添加的碎片实例;
- 获取FragmentManager,在活动中可以直接通过 调用getSupportFragmentManager()方法得到;
- 开启一个事物,通过调用beginTransaction()方法开启;
- 向容器内添加或替换碎片,一般使用replace()方法实现,需要传入容器的id和待添加的碎片实例;
- 提交事物,调用commit()方法来完成。
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.button:
replaceFragment(new AnotherRightFragment());
break;
default:
break;
}
}
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.right_layout,fragment);
transaction.addToBackStack(null);//按下Back键可以回到上一个碎片,如果没有这句,按下Back键程序会直接退出
transaction.commit();
}
}
运行程序
按下Button
3.动态加载布局的技巧
3.1.使用限定符
(1)修改FragmentTest项目的activity_main.xml文件,让他变为单页模式。只留下左侧碎片,让它充满这个父布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
(2)在res目录下新建layout-large文件夹,在这个文件夹下新建布局activity_main.xml,使它成为双页模式。large是一个限定符,那些屏幕被认为是large的设备会自动加载layout-large文件夹下的布局,小屏幕的设备还是加载layout文件夹下 的布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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"/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.fragmenttest.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"/>
</LinearLayout>
将replaceFragment()方法里的代码注释掉。在平板模拟器上运行程序:
在设计模拟器上运行程序:
-
Android常见限定符
屏幕特征:大小
限定符 | 描述 |
---|---|
small | 提供给小屏幕设备的资源 |
normal | 提供给中等屏幕设备的资源 |
large | 提供给大屏幕设备的资源 |
xlarge | 提供给超大屏幕设备的资源 |
屏幕特征:分辨率
限定符 | 描述 |
---|---|
ldpi | 提供给低分辨率设备的资源(120dpi以下) |
mdpi | 提供给中等分辨率设备的资源(120dpi~160dpi) |
hdpi | 提供给高分辨率设备的资源(160dpi~240dpi) |
xhdpi | 提供给超高分辨率设备的资源(240dpi~320dpi) |
xxhdpi | 提供给超超高分辨率设备的资源(320dpi~480dpi) |
屏幕特征:方向
限定符 | 描述 |
---|---|
land | 提供给横屏设置的资源 |
port | 提供给竖屏设置的资源 |
3.2.使用最小宽度限定符
最小宽度限定符允许我们对屏幕的宽度指定一个最小值(以dp为单位),然后以这个最小值为临界点,屏幕宽度 大于这个值的设备就加载一个布局,屏幕宽度小于这个值的设备就加载另一个布局。
在res目录下新建layout-sw600dp文件夹,在这个文件夹下新建布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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"/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.fragmenttest.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"/>
</LinearLayout>