4 Material 3 Scaffold 搭建首页

1,145 阅读3分钟

remember 方法

开始之前先介绍一下 remember 方法。

因为(重组) Composable 函数可以被执行多次,函数中声明变量的赋值语句每次都会被执行,这使得变量每次都会被赋值初始值或者新的对象。 remember 方法可以解决这个问题。

remember 方法两种使用形式 :

  1. remember(calculation:@DisallowComposableCalls () -> T): 没有 key , 每返回的都是第一次执行 calculation 返回的结果
  2. remember(vararg keys:Any?,calculation:@DisallowComposableCalls () -> T): 当 key 改变时会执行 calculation 返回结果,不变时返回上一次 calculation 返回结果

val b = remember { mutableStateOf(0) }    每次运行这行代码返回的都是第一次创建的 MutableState 对象。

三种使用 remember 声明 MutableState 的方式:

  • val mutableState = remember { mutableStateOf(default) } // 返回 MutableState
  • var value by remember { mutableStateOf(default) }           // 返回 T
  • val (value, setValue) = remember { mutableStateOf(default) } // 利用 kotlin 语法 将 MutableState 解构赋值给 value 和 setValue

rememberSaveable 在 remember 功能的基础上还支持 Activity 进程意外销毁后重建的情况(例如配置变更) 下的保存。

可以保存 Bundle 或带有 @Parcelize 注解的对象,还可以自定义 Saver 来自定义保存/恢复规则

搭建首页

除了基本布局以外,Compose 还提供了一些槽位组件,顾名思义就是已经把布局写好,只要在指定的位置插入想要的内容。使用这些组件需要引入 Material 依赖。

Material 3  已经上线,依赖和使用方法与原来的 Material 有所不同。这两个依赖引用一个就够了,在创建项目的时我们已经添加好了 Material 3 依赖。

完整的 Material 3 介绍参见 官网

首页效果如下:

image.png

在每个 ui 模块中创建模块首页文件 提供一个占位的 composable 方法后将其添加到 app 依赖中。

@Composable
fun UiHome(){
    Text(text = "Home")
}

在 app 模块 ui 包下创建 WanApp.kt , 添加枚举类封装底部导航按钮信息

enum class BottomBarItem(
    val label: String,
    val icon: @Composable () -> Unit,
) {
    Home(
        "首页",
        { Icon(imageVector = Icons.Filled.Home, contentDescription = "") },
    ),
    // ...... 问答 、项目 、广场 、体系
}

添加 TopBar 方法用于 Scaffold 的 topBar 槽位

@Composable                  
internal fun TopBar(title: String, onProfileClick: () -> Unit) {//标题,左侧导航按钮点击事件
    CenterAlignedTopAppBar(
        title ={ Text( text = title)}, 
        navigationIcon = {
            IconButton(onClick = onProfileClick) {
                Icon(imageVector = Icons.Filled.Person, contentDescription = "")
            }
        }
    )
}

添加 BottomBar 方法用于 Scaffold 的 bottomBar 槽位

@Composable
internal fun BottomBar(
  items:Array<BottomBarItem>, //item 集合
  selectedIndex:Int = 0, // 当前选中 item 的索引
  onBottomItemClick:(Int) -> Unit) // item 点击事件
{
    NavigationBar {
        items.forEachIndexed { index, bottomBarItem ->
            NavigationBarItem(
                icon = bottomBarItem.icon,
                selected = index == selectedIndex,
                onClick = {onBottomItemClick(index)},
                colors = NavigationBarItemDefaults.colors()// 设置颜色
            )
        }
    }
}

添加 WanApp 方法收拢 Compose 代码,在方法中用 Scaffold 创建首页

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun WanApp(){
	//当前选中的 BottomBarItem 索引

  	//Scaffold 根据选中的状态显示不同的内容
    var selectedItemIndex by remember { mutableStateOf(0) } 
	
    val bottomBarItems = remember { BottomBarItem.values() }

    WanAndroidTheme {
        // A surface container using the 'background' color from the theme
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = MaterialTheme.colorScheme.background
        ) {
            Scaffold(
                topBar = {
                    TopBar(title = bottomBarItems[selectedItemIndex].label) {
			//todo 跳转到我的页面
                    }
                },
                bottomBar = {
                    BottomBar(bottomBarItems, selectedItemIndex) {
                      	//点击底部 item 时更新 selectedItemIndex
                        selectedItemIndex = it
                    }
                },
                containerColor = Color.LightGray
            ) {
                Box(modifier = Modifier
                    .padding(it)
                    .fillMaxSize()){
                    //根据 selectedItemIndex 在 content 中显示不同的页面
                    when(selectedItemIndex){
                        0 -> UiHome()
                        1 -> UiFqa()
                        2 -> UiProfile()
                        3 -> UiSquare()
                        else -> UiSystem()
                    }
                }
            }
        }
    }
}

收拢后 Main Activity 中的代码

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            WanApp()
        }
    }
}

简单实现了首页功能,主要目的是熟悉 Compose 中 Composable 方法,状态, rememeber 方法,及 Material 3 中的槽位组件的使用。 接下来要使用 Jectpack Navigation 完成真正的首页功能。

代码 git 地址