Jetpack Compose 的工具栏结构化行为

时间:2021-06-10 11:36:07

标签: android android-jetpack-compose

想象一下 Android 中工具栏的常见行为。

您在 Toolbar 中定义了一个 Activity 小部件,并且可以使用片段中的 onCreateOptionsMenuonOptionsItemSelected 访问它。

但是,普通的 Jetpack Compose 不可能实现这样的事情,因为无法访问 ToolbarActivity 中定义的 Scaffold

所以想想这个场景。您有一个 Activity,其中定义了 Scaffold,而 NavHost 中还有一个 ScaffoldNavHost 包含应用程序的所有子页面(其他可组合)。标题可以在Navigation Destination Listener中处理,剩下的就是Toolbar的Actions了。

您将如何根据您所在的当前页面/组合件更改工具栏操作?并处理对这些操作的点击?

PS : 在每个页面中使用工具栏并不是解决方案,因为在动画页面之间切换时会导致糟糕的用户体验,工具栏会在每个页面上消失并重新出现。

2 个答案:

答案 0 :(得分:0)

您可以在 TopAppBar 级别使用 Scaffold,并使用您当前的目的地来自定义 topBar

类似于:

topBar = {

    // Use your logic here
    val currentDestination = navBackStackEntry?.destination
    if (currentDestination == ....) {
      CustomAppBar()
    } else {
       TopAppBar(
          title = { /*...*/ },
          actions = {
                if (currentDestination == ....) {
                    IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.Favorite, contentDescription = "")
                    }
                }
                IconButton(onClick = { /* doSomething() */ }) {
                    Icon(Icons.Filled.Add, contentDescription = "")
                }

            }){ //... }
    }
}

否则只需在每个屏幕中使用单独的 TopAppBar

答案 1 :(得分:0)

我使用了一个名为 ToolbarController 的接口,其中包含回调方法,这些方法可以设置调用 scaffold 的 TopAppBar 时使用的变量的值:

@Composable  
fun MyApp(){  
  
 var toolbarTitle by remember{ mutableStateOf("") }  
  
 // ToolbarController would be some interface you have defined  
 val toolbarController = object: ToolbarController {  
        override fun setTitle(title: String){  
            toolbarTitle = title  
        }  
    }  
  
 Scaffold(  
    topBar = { 
       TopAppBar( title = { Text(text = toolbarTitle) }  )  
    }  
 ){  
    SomeScreen(toolbarController = toolbarController)  
 }  
}  
  
@Composable  
fun SomeScreen(  
    toolbarController: ToolbarController  
) {  
    //I'm not 100% sure I need to use an effect here, but I think so...
    //And I'm not sure this is the right one. It is not a coroutine I call,
    //but it of course works with normal calls. Also SideEffect runs on every
    //recompose according to the docs, and that's not what we want.
    //https://developer.android.com/jetpack/compose/side-effects
    LaunchedEffect(true){
       toolbarController.setTitle("Some screen title")  
    }
}

编辑: 并且很容易将它用于任何工具栏属性,您可以像这样创建界面:

interface ToolbarController{
    fun configToolbar(
        title: String = "",
        navigationIcon: IconButton? = null,
        actions: List<IconButton> = listOf()
    )
}

重点是您只需制作回调函数并在 LaunchedEffect 中运行它们。这是从脚手架中的可组合内设置工具栏属性的一种方法。接口的东西只是一种对这些回调进行分组的方式,所以它不会变得太乱。