使用方式
简单用法
先从最简单的开始:一个页面包含左右两个fragment。新建FragmentTest,新建一个左侧fragment的布局left_fragment.xml:
<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>
再新建一个右侧fragment的布局right_fragment.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#00ff00"
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>
接着新建LeftFragment类,并继承ragment,此处继承的Fragment一定要是AndroidX库中的。编写LeftFragment:
class LeftFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return LayoutInflater.from(context).inflate(R.layout.left_fragment, container, false)
}
}
接着创建RightFragment:
class RightFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return LayoutInflater.from(context).inflate(R.layout.right_fragment, container, false)
}
}
修改activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<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>
此时可运行。
动态添加fragment
fragment的强大之处在于,可以在程序运行时动态添加到activity,而根据具体情况动态地添加fragment,我们就可以将程序界面定制的更加多样化。
新建another_right_fragment.xml:
<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:layout_gravity="center_horizontal"
android:text="This is another right fragment"
android:textSize="24sp" />
</LinearLayout>
新建AnotherRightFragment作为另一个右侧fragment:
class AnotherRightFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return LayoutInflater.from(context).inflate(R.layout.another_right_fragment, container, false)
}
}
修改activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<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" />
</LinearLayout>
将右侧的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) {
//在activity中可以直接调用getSupportFragmentManager方法获取FragmentManager
val fragmentManager = supportFragmentManager
//开启事务
val transaction = fragmentManager.beginTransaction()
//向容器内添加或替换fragment,一般用replace方法
transaction.replace(R.id.rightLayout, fragment)
//提交事务
transaction.commit()
}
}
实现返回栈
实现了动态添加fragment的功能后,如果我们点击返回键,程序会直接退出。如果我们想实现按返回键可以回到上一个fragment、这样一个类似返回栈的效果,我们可以使用FragmentTransaction的addToBackStack方法,用于将一个事务添加到返回栈中。
class MainActivity : AppCompatActivity() {
...
private fun replaceFragment(fragment: Fragment) {
val fragmentManager = supportFragmentManager
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.rightLayout, fragment)
//可以接收名字描述返回栈的情况,一般传入null即可
transaction.addToBackStack(null)
transaction.commit()
}
}
Fragment和Activity之间的交互
虽然Fragment是嵌入在Activity中显示的,可是它们的关系并没有那么亲密。实际上,Fragment和Activity是各自存在于一个独立的类当中的,它们之间并没有那么明显的方式来直接进行交互。
为了方便Fragment和Activity之间进行交互,FragmentManager提供了一个类似于findViewById()的方法,专门用于从布局文件中获取Fragment的实例:
val fragment = supportFragmentManager.findFragmentById(R.id.leftFrag) as LeftFragment
另外,kotlin-android-extensions插件也对此进行了扩展:
val fragment = leftFrag as LeftFragment
无疑后者是更推荐的写法。
而如果我们想要在fragment中调用activity中的方法,直接使用fragment中的getActivity方法,就可以得到和当前fragment相关联的activity:
if (activity != null) {
val mainActivity = activity as MainActivity
}
由于getActivity方法可能返回null,所以我们要先进行判空处理。另外当fragment需要context对象时,也可以使用getActivity方法,因为获取到的activity对象本身就是一个context对象。
而既然fragment可以和activity通信,那么fragment之间也可以做到,只需要在一个fragment中获取与之相关联的activity,再让这个activity去获取另一个我们想通信的fragment,这样就可以实现了。