之前的项目我们一直用手机模拟器来运行,这次我们来用平板模拟器来运行,我们来创建一个平板模拟器Pixel C ,也是Android 10版本,然后我们来创建一个新的项目 FragmentTest,开始我们的Fragment 探(tian)索(xiu)之(sao)旅(cao)吧(zuo)!
5.2.1 Fragment 的简单用法
先在一个最简单的Fragment 示例来练练手,在一个Activity 中添加两个Fragment ,让这两个Fragment 平分Activity 的空间。
<?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/leftFrag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:name=""
android:layout_weight="1"
/>
<fragment
android:id="@+id/rightFrag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:name=""
android:layout_weight="1"
/>
</LinearLayout>
这里 android:name 的值是我们创建的Fragment 类的路径,由于我们还没创建Fragment 类,接下来我们就开始创建吧。
首先我们创建左侧的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>
屏幕水平居中显示一个Button 按钮。
接下来是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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="24sp"
android:text="This is right fragment"
/>
</LinearLayout>
显示一行文字 告诉我们这是右侧的Fragment,并且背景设置了绿色。
接下来就需要创建Fragment 类来,在Fragment 类的相应生命周期中加载布局文件。
LeftFragment:
class LeftFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.left_fragment,container,false)
}
}
RightFragment:
class RightFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.right_fragment,container,false)
}
}
这样我们就完成了Fragment 的基本创建了,还记得刚才说的 android:name 属性吗,我们把这LeftFragment 和 RightFragment 的路径添加进去就可以运行了。
这就是静态注册Fragment!
5.2.2 动态添加Fragment
接下来我们改学习动态添加Fragment了,这是公司开发中必不可少的知识点,可以根据不同的具体情况来动态的添加Fragment 而不是像静态一样固定的使用一个Fragment。
我们左侧的fragment 还使用之前的静态fragment ,我们来让右侧的Fragment 变为动态注册,点击左侧的Button 按钮来切换右侧的Fragment,那么我们来新建一个右侧的fragment 布局文件:
another_right_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<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="24sp"
android:text="This is another right fragment"
/>
</LinearLayout>
然后我们创建一个AnotherRightFragment 类:
class AnotherRightFragment :Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.another_right_fragment,container,false)
}
}
这样我们准备工作就做完了,接下来改更改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/leftFrag"
android:layout_width="0dp"
android:layout_height="match_parent"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_weight="1"
/>
<FrameLayout
android:id="@+id/rightLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
</LinearLayout>
我们把右侧的fragment 换成 FrameLayout 了,这是布局中最简单的一种布局,所以的组件都会放在左上角,由于我们只需要放置一个fragment ,不需要任何定位,直接充满FrameLayout 就可以了,这里的fragment 需要在代码中动态添加。
接下来我们进入MainActivity 中进行动态添加:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
replaceFragment(AnotherRightFragment())
}
replaceFragment(RightFragment())
}
private fun replaceFragment(fragment: Fragment){
val supportFragmentManager = supportFragmentManager
val beginTransaction = supportFragmentManager.beginTransaction()
beginTransaction.replace(R.id.rightLayout,fragment)
beginTransaction.commit()
}
}
重点就是我们创建的 replaceFragment 函数:
1、我们通过getSupportFragmentManager 拿到了Fragment 管理者
2、通过supportFragmentManager 由拿到了 Fragment 的事务 beginTransaction
3、beginTransaction 调用了replace 函数
4、传入了容器id和fragment 实例
5、最后commit 提交事务完成。
Ps:beginTransaction 调用 add函数可以进行添加fragment,然后调用show 或hide 函数进行展示也隐藏,而replace 函数则是清空布局内的所有Fragment 然后只显示我们传入的Fragment,每次使用replace 都会重新加载生命周期。
5.2.3 在Fragment 的实现返回栈
我们在一个事务 提交之前调用 addToBackStatck 函数就可以将一个事务添加到返回栈中。这样使用每次使用返回键都会返回到上一个事务中。
private fun replaceFragment(fragment: Fragment){
val supportFragmentManager = supportFragmentManager
val beginTransaction = supportFragmentManager.beginTransaction()
beginTransaction.addToBackStack(null)
beginTransaction.replace(R.id.rightLayout,fragment)
beginTransaction.commit()
}
5.2.4 Fragment 和Activity 之间的交互
这两个独立的类我们怎么相互交互呢?来看看Activity 与 Fragment 的交互,如何拿到fragment 的实例:
在Activity 通过此方式可以拿到fragment的实例,一般来说我们创建了Fragment 就已经拿到了实例了。。。。
supportFragmentManager.findFragmentByTag()
supportFragmentManager.findFragmentById()
还有一种简化的写法,Kotlin 也对 findFragmentViewById 进行了扩展,允许我们直接使用id 名称来自动获取响应的fragment 实例:
val fragment = leftFrag as LeftFragment
掌握了 在Activity 中拿到Fragment 那么下面就是如何从Fragment 中拿到所属Activity了,直接在Fragment 类中调用getActivity 函数就能拿到所属Activity ,就这么简单, 注意由于getActivity 有可能拿到null 空,所以逻辑代码要做非空判断,比如 所属Activity 被系统回收,或者旋转屏幕等等,都会暂时的丢失所属Activity。
不同的Fragment 之间也是可以通讯的,前提是他们所属一个Activity ,fragment 拿到所属activity,所属activity 在拿到想要通讯的fragment 实例就可以了。