碎片(Fragment)的基本使用

一、Fragment 初探

1、诞生的原因

因为屏幕大小差距过大,一些界面在手机上看起来非常美观,但在平板上看起来可能会有控件被过分拉长、元素之间空隙过大等情况。为了让界面在平板更好地展示,Android 自3.0版本开始引入了碎片的概念。
在这里插入图片描述

2、定义

那碎片是什么呢?碎片是一种可以嵌入在Activity当中的UI片段。碎片和Activity很像,同样都能包含布局,同样都有自己的生命周期。

注意:
1、Fragment不能独立存在,必须嵌入到Activity中
2、Fragment具有自己的生命周期,接收它自己的事件,并可以在Activity运行时被添加或删除
3、Fragment的生命周期直接受所在的Activity的影响。如:当Activity暂停时,它拥有的所有Fragment都暂停

二、Fragment 的使用方式

我们先新建一个项目,名为 FragmentTest ,然后一起来学习一下如何使用碎片吧!(虽然碎片起初是为了兼容平板而存在,但是在手机上也应用很广泛,所以在这里我还是使用了手机模拟器,感兴趣的同学也可以用平板模拟器,碎片的使用方法也是一样的,可参考《第一行代码》)

1、静态加载碎片

我们先在Activity的布局文件 activity_main.xml 里写一个简单的Button控件

<Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button"
        android:textSize="15sp" />

接着我们新建一个碎片布局 first_fragment.xml ,并放置了一个 TextView 用于显示文本,为了等会更好地看到效果,我们将这个布局的背景色设置成别的颜色(我这里是水色)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00FFFF"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is the first fragment"
        android:textSize="25sp" />

</LinearLayout>

接着我们新建一个 FirstFragment 类,并让它继承 Fragment 。此时会有两个不同包下的 Fragment 让我们选择

一个是AndroidX库中的androidx.fragment.app.Fragment ,一个是系统内置的android.app.Fragment ,这里我们选择AndroidX库中的Fragment ,因为它可以让Fragment的特性在所有Android系统版本中保持一致,而系统内置的Fragment在Android 9.0版本中已被废弃。

然后我们重写onCreateView()方法,在这个方法里通过LayoutInflater的inflate()方法将刚刚定义的first_fragment布局加载进来

public class FirstFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.first_fragment, container, false);
    }
}

inflate() 方法带有三个参数:
inflater:想要扩展的布局的资源 ID
container:布局将插入到的父级 ViewGroup(来自 Activity 的布局)
savedInstanceState:保存的状态,在恢复fragment时,提供上一片段实例相关数据的 Bundle
如果第三个参数为true那么返回可能就不是View,当为false的时候返回就是View
在这里布尔值为 false,因为系统已将扩展布局插入 container,而传递 true值会在最终布局中创建一个多余的视图组

接下来我们去修改 activity_main.xml 中的代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button"
        android:textSize="15sp" />

    <fragment
        android:id="@+id/first_fragment"
        android:name="com.example.fragmenttest.FirstFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

我们使用了< fragment > 标签在布局中添加Fragment,这里还需要通android:name属性来显式声明要添加的Fragment类名,注意一定要将类的包名也加上。在这里还使用了weight属性,将剩下来的屏幕空间全部给了fragment
✌✌ 静态加载碎片到这里就写好了,现在可以运行一下程序看看效果了

2、动态添加碎片

上面这个例子只是碎片的简单用法,在真正的项目中几乎没有什么实际的作用,接下来我们学习厉害一点的,在程序运行时动态地添加碎片到活动当中。

我们在前面代码的基础上继续完善,首先,新建一个布局文件second_fragment.xml ,和前面的first_fragment.xml 基本相同,将它的背景色和显示的文字稍加修改一下即可,便于区分一下这是新的碎片

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFF00"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is the second fragment"
        android:textSize="25sp" />

</LinearLayout>

然后新建 SecondFragment 类,和前面一样的套路啦

public class SecondFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.second_fragment, container, false);
    }
}

接下来修改 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button"
        android:textSize="15sp" />

    <FrameLayout
        android:id="@+id/fragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

可以看到,我们将fragment换成FrameLayout(帧布局),这是安卓中最简单的一种布局,所有的控件默认都会摆放在布局的左上角,同一时刻只能看到最上面的控件,后续添加的控件会覆盖前一个。由于这里仅需要在布局里放入一个Fragment,不需要任何定位和嵌套,因此非常适合使用FrameLayout。

✎✎ 重点来啦!接着我们来看看如何实现动态添加碎片的功能,完善一下java文件

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = findViewById(R.id.button);
        button.setOnClickListener(this);
        replaceFragment(new FirstFragment()); //初始化,一开始显示的碎片为FirstFragment
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.button:
                replaceFragment(new SecondFragment()); //当点击按钮后,动态改变碎片,此时显示的碎片为SecondFragment
                break;
            default:
                break;
        }
    }

    private void replaceFragment(Fragment fragment) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.fragment, fragment);
        transaction.commit();
    }
}

我们先实例化Button,并注册一个点击事件,点击button时,会调用replaceFragment()方法将下侧碎片替换成另一个。FragmentManager能够实现管理activity中fragment;FragmentTransaction对fragment进行添加,移除,替换,以及执行其他动作。

动态添加碎片步骤:
1、创建待添加Fragment的实例
2、调用getSupportFragmentManager()方法获取FragmentManager实例
3、调用beginTransaction()方法开启一个事务
4、使用replace()方法向容器内添加或替换Fragment,需要传入容器的id和待添加的Fragment实例
5、调用commit()方法提交事务

✌✌ 现在我们可以重新运行一下程序,看看效果啦!

3、在碎片中模拟返回栈

换言之,就是返回到之前的上一个碎片。
接着上面的运行结果,我们已经点击过了按钮,此时屏幕上显示的是第二个碎片,若这时按下Back键,你会发现,咦?怎么直接退出了,我只是想回到上一个碎片,那怎么办呢?这时我们可以使用FragmentTransaction提供的addToBackStack()方法,传入一个用于描述返回栈状态的参数,一般传入null即可。

private void replaceFragment(Fragment fragment) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.fragment, fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }

现在我们再来运行一下程序看看,是不是按下Back键后,返回到第一个碎片,继续按下Back键,第一个碎片会消失,再次按下Back键后才会退出?

4、碎片和活动之间的交互

在Activity中调用Fragment里的方法:先得到相应Fragment的实例,再调用Fragment里的方法(findFragnentById()方法,专门用于从布局中获取碎片的实例)

FirstFragment firstFragment = getSupportFragmentManager()
    .findFragmentById(R.id.first_fragment);

在Fragment中调用Activity里的方法:调用getActivity() 方法来得到和当前碎片相关联的活动实例,再调用Activity里的方法

MainActivity activity =  getActivity();

在这里我就不举例子详细介绍了,想要继续了解的同学可以自己看看相关博客或者《第一行代码》呀!

三、Fragment 的生命周期

Fragment的生命周期和Activity的生命周期很像,在这里我就不详细讲解啦,感兴趣的同学可以自己去了解一下


OK,讲完啦!但这只是碎片的基础知识,进一步的学习和应用需要你们自己去探索哦!最后,悄悄问一句,你的冬令营作品开始做了吗?✿期待看到大家的作品哦✿

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>