-
Notifications
You must be signed in to change notification settings - Fork 16
导航Fragment
在需要导航的Fragment上添加@Destination
注解,并设置对应的route路径,然后调用navigate
方法并传入目的地的路径即可。
//定义目的地
@Destination(route = Destinations.DESTINATION_TEST)
class TestFragment : Fragment()
//导航
Butterfly.of(context).navigate(Destinations.DESTINATION_TEST)
route路径可以是任意字符串常量,通常我们使用
scheme://path/xxx
这样的格式作为route地址
Butterfly支持多种参数传递方式,可通过拼接路径的形式带入额外的参数,或者通过调用params
方法手动传入参数,
或者在调用navigate
方法时传入参数,或者混合使用以上几种方式。
//拼接路径带入参数
Butterfly.of(this).navigate(Destinations.DESTINATION_TEST + "?a=1&b=2&c=3")
//调用params方法
Butterfly.of(this)
.params(
"x" to 1,
"y" to true,
"z" to "test value"
)
.navigate(Destinations.DESTINATION_TEST)
//调用navigate时传入参数
Butterfly.of(this)
.navigate(
Destinations.DESTINATION_TEST,
"a" to "1"
)
//同时使用多种方式
Butterfly.of(this)
.params(
"x" to 1,
"y" to true,
"z" to "test value"
)
.navigate(
Destinations.DESTINATION_TEST + "?a=1&b=2&c=3",
"d" to "4"
)
以上几种方式的优先级为:navigate > route string > params,也就是说如果遇到同名的参数, 则通过navigate方法传递的参数会覆盖拼接路径字符串中的参数,拼接路径字符串中的参数又会覆盖通过params方法传递的参数。
传入的参数会打包进一个Bundle对象,并设置为Fragment的Arguments,因此获取参数只需要对Fragment的Bundle对象进行解析即可。
@Destination(route = Destinations.DESTINATION_TEST)
class TestFragment : Fragment() {
val a by lazy { arguments?.getString("a") ?: "" }
val b by lazy { arguments?.getString("b") ?: "" }
val c by lazy { arguments?.getString("c") ?: "" }
//...
}
除了手动解析参数以外,还可以使用Bracer
库来进行智能参数解析
@Destination(route = Destinations.DESTINATION_TEST)
class TestFragment : Fragment() {
val a by params<String>()
val b by params<String>()
val c by params<String>()
}
Bracer 使用方式详情见: Github 地址 Bracer
Butterfly也支持设置Fragment的启动模式,默认情况下使用standard
模式启动,
通过调用singleTop
和clearTop
方法,可以设置为栈顶复用模式或者清除栈顶模式启动。
// 设置为 clearTop 模式,如果当前栈中有目标类型的Fragment,则会清除目标上面的所有Fragment,
// 确保目标Fragment位于栈顶位置,否则创建新的Fragment入栈
Butterfly.of(context)
.clearTop()
.navigate(Destinations.DESTINATION_TEST)
// 设置为 singleTop 模式,如果栈顶已经是该目标Fragment,则保持目标Fragment不变,
// 否则创建新的Fragment入栈
Butterfly.of(context)
.singleTop()
.navigate(Destinations.DESTINATION_TEST)
在这两种启动模式下,如果复用了栈中的目标Fragment,如何更新目标Fragment的参数呢?
Butterfly为Fragment提供了一个接口:FragmentParamUpdatable
,Fragment可以实现该接口,从而接收最新的导航参数:
@Destination(FRAGMENT)
class TestFragment : Fragment(), FragmentParamUpdatable {
val oldParam by params<String>()
override fun onParamsUpdate(newParams: Bundle) {
val newParam by newParams.params<String>()
println(newParam)
}
}
Fragment导航默认使用ContentView作为容器,可以通过container
方法设置为自定义的ViewGroup容器。
Butterfly.of(context)
.container(R.id.container) //指定容器的ID
.container("container_tag") //或者指定容器的Tag
.navigate(Destinations.DESTINATION_TEST)
在导航Fragment的过程中,可以通过enterAnim
和exitAnim
方法添加Fragment进入和退出的动画:
Butterfly.of(context)
.enterAnim(R.anim.fade_in) // 淡入
.exitAnim(R.anim.fade_out) // 淡出
.navigate(Destinations.DESTINATION_TEST)
使用Butterfly进行导航Fragment之后,如需返回可以使用popBack
方法进行回退。
如果Fragment回退的时候需要携带返回值,使用popBack
可以直接传入返回值。
@Destination(FRAGMENT)
class TestFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.back.setOnClickListener {
//使用popBack回退
Butterfly.of(context).popBack()
//使用popBack回退并返回值
Butterfly.of(context).popBack("result" to "123")
}
}
}
返回结果会被封装为一个Bundle
对象,通过解析Bundle即可获取返回结果:
Butterfly.of(context).navigate(Destinations.DESTINATION_TEST) { result ->
if (result.isSuccess) {
val bundle = result.getOrDefault(Bundle.EMPTY)
val result by bundle.params<String>()
println(result)
}
}
Butterfly除了支持以栈的形式来管理Fragment,还支持以Group组的形式对Fragment进行管理,常用于主页或Tab页面。
@Destination(Destinations.Test)
class BottomNavigationActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val groupId = "test_group"
binding.navView.setOnItemSelectedListener {
when (it.itemId) {
R.id.navigation_home -> {
Butterfly.of(this)
.container(R.id.container)
.group(groupId)
.navigate(Destinations.HOME)
}
R.id.navigation_dashboard -> {
Butterfly.of(this)
.container(R.id.container)
.group(groupId)
.navigate(Destinations.DASHBOARD)
}
R.id.navigation_notifications -> {
Butterfly.of(this)
.container(R.id.container)
.group(groupId)
.navigate(Destinations.NOTIFICATION)
}
}
}
}
}