Fragment的入门使用到进阶

Fragment是什么?

碎片(Fragment)是一种可以嵌入在活动中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用得非常广泛。
同样的界面在手机上显示可能很好看,在平板上就未必了,因为平板的屏幕非常大,手机的界面放在平板上可能会有过分被拉长、控件间距过大等情况。这个时候更好的体验效果是在Activity中嵌入"小Activity",然后每个"小Activity"又可以拥有自己的布局。因此,我们今天的主角Fragment登场了。

Fragment的简单用法

这里我们准备先写一个最简单的碎片示例来练练手,在一个活动当中添加两个碎片并让这两个碎片平分活动空间。
新建一个左侧碎片布局fragment_a.xml代码如下:

<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="@color/blue"
    android:gravity="center"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/fragment_a"
        android:textSize="18sp"
        android:textStyle="bold"
        android:textColor="@color/mid_night_blue"
        />
</LinearLayout>

这个布局非常简单,只放置了一个按钮,并让它水平居中显示。然后新建右侧碎片布局fragment_b.xml,代码如下所示:

<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="@color/dark_orange"
    android:gravity="center"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/fragment_b"
        android:textSize="18sp"
        android:textStyle="bold"
        android:textColor="@color/mid_night_blue"
        />

</LinearLayout>

这里的颜色和string自己配下,直接在color.xml和string.xml添加你喜欢的颜色就好,这里我推荐下我走颜色的网址:
颜色选择器

接着新建一个FragmentA类,并让它继承自Fragment。继承的Fragment是androidx下的。以后建议都用androidx下包的控件。
现在编写一下FragmentA中的代码,如下所示:

class FragmentA : Fragment() {
    
    

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
    
    
        return View.inflate(context, R.layout.fragment_a,null)
    }
}

这里仅仅是重写了Fragment的onCreateView()方法,然后在这个方法中通过LayoutInflater的inflate()方法将刚才定义的left_fragment布局动态加载进来,整个方法简单明了。接着用同样的方法建立一个FragmentB,代码如下:

class FragmentB : Fragment() {
    
    

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
    
    
        return View.inflate(context, R.layout.fragment_b,null)
    }
}

接下来修改activity_main.xml中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    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">

    <FrameLayout
        android:id="@+id/fragment_a"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/fragment_b"
        app:layout_constraintTop_toTopOf="parent"
        />
    <FrameLayout
        android:id="@+id/fragment_b"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toRightOf="@id/fragment_a"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

看清楚这里是两个FrameLayout,不是fragment,通常我们在开发的时候都是动态来打开fragment的,这里就不介绍静态方法了,如果想了解,直接在布局里面添加两个fragment布局就好,id需要对应起来。

接下来还要对MainActivity中进行一番操作:

class MainActivity : AppCompatActivity() {
    
    

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var fragmentA = FragmentA()
        var fragmentB = FragmentB()
        supportFragmentManager.beginTransaction().add(R.id.fragment_a,fragmentA).commitAllowingStateLoss()
        supportFragmentManager.beginTransaction().add(R.id.fragment_b,fragmentB).commitAllowingStateLoss()
    }
}

看到效果如下

在这里插入图片描述
动态添加碎片主要分为5步:

(1)创建待添加的碎片示例。

(2)获取FragmentManager,在活动中可以直接通过getSupportFragmentManager()方法得到。

(3)开启一个事务,通过调用beginTransaction()方法开启。

(4)向容器内添加或替换碎片,一般使用add()方法实现,需要传入容器的id和待添加的碎片实例。

(5)提交事务,调用commit()方法来完成。

这样就完成了在活动中动态添加碎片的功能。

Fragment的生命周期

class FragmentA : Fragment() {
    
    

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
    
    
        Log.e("FragmentCurrentLife", "onCreateView")
        return View.inflate(context, R.layout.fragment_a,null)
    }

    override fun onAttach(context: Context) {
    
    
        super.onAttach(context)
        Log.e("FragmentCurrentLife", "onAttach")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        Log.e("FragmentCurrentLife", "onCreate")
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
    
    
        super.onActivityCreated(savedInstanceState)
        Log.e("FragmentCurrentLife", "onActivityCreated")
    }

    override fun onStart() {
    
    
        super.onStart()
        Log.e("FragmentCurrentLife", "onStart")
    }

    override fun onResume() {
    
    
        super.onResume()
        Log.e("FragmentCurrentLife", "onResume")
    }

    override fun onPause() {
    
    
        super.onPause()
        Log.e("FragmentCurrentLife", "onPause")
    }

    override fun onStop() {
    
    
        super.onStop()
        Log.e("FragmentCurrentLife", "onStop")
    }

    override fun onDestroyView() {
    
    
        super.onDestroyView()
        Log.e("FragmentCurrentLife", "onDestroyView")
    }

    override fun onDestroy() {
    
    
        super.onDestroy()
        Log.e("FragmentCurrentLife", "onDestroy")
    }

    override fun onDetach() {
    
    
        super.onDetach()
        Log.e("FragmentCurrentLife", "onDetach")
    }

} 

开启一个fragment
在这里插入图片描述
按下home键
在这里插入图片描述
重回fragment
在这里插入图片描述
按下物理回退键退出
在这里插入图片描述
onAttach():执行该方法时,Fragment与Activity已经完成绑定,该方法有一个Activity类型的参数,代表绑定的Activity,这时候你可以执行诸如mActivity = activity的操作。

onCreate():初始化Fragment。可通过参数savedInstanceState获取之前保存的值。

onCreateView():初始化Fragment的布局。加载布局和findViewById的操作通常在此函数内完成,但是不建议执行耗时的操作,比如读取数据库数据列表。

onActivityCreated():执行该方法时,与Fragment绑定的Activity的onCreate方法已经执行完成并返回,在该方法内可以进行与Activity交互的UI操作,所以在该方法之前Activity的onCreate方法并未执行完成,如果提前进行交互操作,会引发空指针异常。

onStart():执行该方法时,Fragment由不可见变为可见状态。

onResume():执行该方法时,Fragment处于活动状态,用户可与之交互。

onPause():执行该方法时,Fragment处于暂停状态,但依然可见,用户不能与之交互。

onSaveInstanceState():保存当前Fragment的状态。该方法会自动保存Fragment的状态,比如EditText键入的文本,即使Fragment被回收又重新创建,一样能恢复EditText之前键入的文本。

onStop():执行该方法时,Fragment完全不可见。

onDestroyView():销毁与Fragment有关的视图,但未与Activity解除绑定,依然可以通过onCreateView方法重新创建视图。通常在ViewPager+Fragment的方式下会调用此方法。

onDestroy():销毁Fragment。通常按Back键退出或者Fragment被回收时调用此方法。

onDetach():解除与Activity的绑定。在onDestroy方法之后调用。

setUserVisibleHint():设置Fragment可见或者不可见时会调用此方法。在该方法里面可以通过调用getUserVisibleHint()获得Fragment的状态是可见还是不可见的,如果可见则进行懒加载操作。

Fragment执行流程分解:

1、Fragment创建:setUserVisibleHint()->onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume();

2、Fragment变为不可见状态(锁屏、回到桌面、被Activity完全覆盖):onPause()->onSaveInstanceState()->onStop();

3、Fragment变为部分可见状态(打开Dialog样式的Activity):onPause()->onSaveInstanceState();

4、Fragment由不可见变为活动状态:onStart()->OnResume();

5、Fragment由部分可见变为活动状态:onResume();

6、Fragment退出:onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()(注意退出不会调用onSaveInstanceState方法,因为是人为退出,没有必要再保存数据);

7、Fragment被回收又重新创建:被回收执行onPause()->onSaveInstanceState()->onStop()->onDestroyView()->onDestroy()->onDetach(),重新创建执行onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()->setUserVisibleHint();横竖屏切换:与Fragment被回收又重新创建一样。

onHiddenChanged的回调时机

当使用add()+show(),hide()跳转新的Fragment时,旧的Fragment回调onHiddenChanged(),不会回调onStop()等生命周期方法,而新的Fragment在创建时是不会回调onHiddenChanged(),这点要切记。

最后说一下,目前用的很多的一种模式就是 一个Activity对多个Fragment
有一篇文章讲的很好
Fragment全解析系列
想深度学习的可以去看看
最后推荐大佬写的框架:
Fragmentation

猜你喜欢

转载自blog.csdn.net/i_nclude/article/details/75577887
今日推荐