Fragment简介和使用方式
1 Fragment是什么
Fragment(fm)是一种可以嵌入在Activity(ac)中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用得非常广泛。fm和ac非常相似,可以理解为在一个ac中划分出多个fm,虽然这样一个fm可能就跟手机上一个ac一样大了。
2 Fragment的使用方式
先在Android Studio(AS)中创建一个Pixel C平板模拟器,然后新建FragmentTest项目。
2.1 简单用法
在一个ac中添加两个fm,并让这两个fm平分ac的空间
新建一个左侧fm的布局 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>
新建一个右侧fm的布局 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="#00ff00">
<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>
New一个LestFragment类,继承于Fragment,此处的Fragment不要用系统内置的android.app.Fragment,要用AndroidX库中的androidx.fragment.app.Fragment。
class LeftFragment: Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.left_fragment, container, false)
}
}
重写onCreateView()
方法,加载left_fragment,简单明了
接下来同样的方法创建RightFragment
class RightFragment: Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.right_fragment, container, false)
}
}
接下来修改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">
<fragment
android:id="@+id/leftFrag"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<fragment
android:id="@+id/rightFrag"
android:name="com.example.fragmenttest.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
代码简单明了,需要用name属性指定完整包名
运行结果
2.2 动态加载Fragment
Fragment的强大之处在于它可以在程序运行时动态地添加到Activity中
新建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.anothe_right_fragment, container, false)
}
}
同样没什么好说的
接下来修改activity_main中的代码
<fragment
android:id="@+id/leftFrag"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<FrameLayout
android:id="@+id/rightLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
这里用一个帧布局替换了Fragment
然后用kotlin代码向FrameLayout里面添加内容,实现动态添加Fragment的功能,修改MainActivity中的代码。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener{
replaceFragment(AnotherRightFragment())
}
replaceFragment(RightFragment())
}
private fun replaceFragment(fragment: Fragment){
val fragmentManager = supportFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.rightLayout, fragment)
transaction.commit()
}
首先给按钮添加点击事件,逻辑写动态加载AnotherRight,然后动态加载Right,而动态加载通过replaceFragment()
方法来实现,通过方法里的代码,我们可以看出动态加载Fragment主要分为五步:
- 创建待添加的Fragment实例
- 获取FragmentManager,在ac中可以直接调用
getSupportFragmentManager()
方法获取 - 通过FragmentManager的
beginTransaction()
方法开启一个事务 - 通过该事务的
replace()
方法向容器内添加或替换Fragment,需要传入容器的id和待添加的Fragment实例 - 通过
commit()
方法提交事务
运行结果
点击Button
2.3 在Fragment中实现返回栈
FragmentTransaction提供了一个addToBackStack()
方法,可以用于将一个事务添加到返回栈中,接收一个参数用于描述返回栈的状态,一般传入null即可。
在replaceFragment()
方法中加上一行
private fun replaceFragment(fragment: Fragment){
val fragmentManager = supportFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.rightLayout, fragment)
transaction.addToBackStack(null)
transaction.commit()
}
此时再启动项目进入AnotherRight以后,点击back键会回到Right,再点back键Right界面会消失,再点一次back键程序才会退出
2.4 Fragment和Activity之间的交互
- ac调用fm中的方法
FragmentManager提供了一个类似于findViewById()的方法,专门从布局文件中获取Fragment实例,比如
val fragment =
supportFragmentManager
.findFragmentById(R.id.letfFrag) as LeftFragment
如此可以在ac中得到相应的fm实例,就能调用fm中的方法了
- fm调用ac中的方法
每个fm中都可以通过调用getActivity()
方法来获取与当前fm相关联的ac实例,比如:
if (activity != null){
val mainActivity = activity as MainActivity
}
这样便获取到了ac实例