Jetpack Compose學習(7)——MD樣式架構元件Scaffold及導航底部選單
Jetpack Compose學習(7)——MD樣式架構元件Scaffold及導航底部選單 | Stars-One的雜貨小窩
Compose給我們提供了一個Material Design樣式的首頁元件(Scaffold
),我們可以直接套用從而完成一個APP的首頁介面
本系列以往文章請檢視此分類連結Jetpack compose學習
由於Scaffold中還包含有其他的元件,所以講解Scaffold先講解前置的一些元件
TopAppBar
首先,便是TopAppBar,其本質就是我們Android原生常見的Toolbar,不過其封裝的比較好,可以快速構建,下面是其的引數列表
TopAppBar( title: @Composable () -> Unit, modifier: Modifier = Modifier, navigationIcon: @Composable (() -> Unit)? = null, actions: @Composable RowScope.() -> Unit = {}, backgroundColor: Color = MaterialTheme.colors.primarySurface, contentColor: Color = contentColorFor(backgroundColor), elevation: Dp = AppBarDefaults.TopAppBarElevation )
title
標題,接收Compose元件,可以傳個Text文字進去modifier
修飾符,詳情見上一章節navigationIcon
導航圖示actions
動作元件backgroundColor
背景色contentColor
內容顏色elevation
陰影
可能說的那麼明確,我們直接上程式碼和效果圖,各位就清晰了
TopAppBar( navigationIcon = { IconButton( onClick = {} ) { Icon(Icons.Filled.Menu, null) } }, title = { Text("stars-one的測試應用") },actions = { IconButton( onClick = {} ) { Icon(Icons.Filled.Share, null) } IconButton( onClick = {} ) { Icon(Icons.Filled.Settings, null) } } )
效果圖如下
FloatingActionButton
比較常見的懸浮按鈕,一般裡面是個簡單的按鈕,引數與之前的Button一樣,詳情請參考Jetpack Compose學習(3)——圖示(Icon) 按鈕(Button) 輸入框(TextField) 的使用 | Stars-One的雜貨小窩
FloatingActionButton( onClick: () -> Unit, modifier: Modifier = Modifier, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, shape: Shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)), backgroundColor: Color = MaterialTheme.colors.secondary, contentColor: Color = contentColorFor(backgroundColor), elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(), content: @Composable () -> Unit )
使用:
FloatingActionButton(onClick = { /*TODO*/ }) {
Icon(imageVector = Icons.Default.Add, contentDescription = null)
}
PS: 一般這個與
Scaffold
連用,Scaffold裡面可控制FloatingActionButton的位置
除此之外,還有個ExtendedFloatingActionButton
,這種就是可以帶圖示和文字的,如下圖
ExtendedFloatingActionButton(
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
text = { Text("ADD TO BASKET") },
onClick = { /*do something*/ }
)
ExtendedFloatingActionButton
和FloatingActionButton
區別是,ExtendedFloatingActionButton
是以文字為主,圖示是可選的,而FloatingActionButton
只顯示圖示
BottomAppBar
這個與之前的TopAppBar引數有所不同,從名字看我們知道其實放在底部的一個Toolbar,但是其本身是不帶有位置控制,也是得與Scaffold連用,如果單獨使用,效果也是會和TopAppBar的一樣放在頁面的頂頭
BottomAppBar(
modifier: Modifier = Modifier,
backgroundColor: Color = MaterialTheme.colors.primarySurface,
contentColor: Color = contentColorFor(backgroundColor),
cutoutShape: Shape? = null,
elevation: Dp = AppBarDefaults.BottomAppBarElevation,
contentPadding: PaddingValues = AppBarDefaults.ContentPadding,
content: @Composable RowScope.() -> Unit
)
可以把這個佈局看作是個Row佈局,裡面的引數從名字都能看到出來,設定背景色或者設定padding邊距的,這裡不再贅述
唯一值得注意的是cutoutShape
屬性,如果在Scaffold
中,有BottomAppBar
和FloatingActionButton
,可以實現下面的效果
BottomNavigation
BottomNavigation
裡面會有N個BottomNavigationItem
,這裡就看你自己準備定義多少個選單項了
BottomNavigation(
modifier: Modifier = Modifier,
backgroundColor: Color = MaterialTheme.colors.primarySurface,
contentColor: Color = contentColorFor(backgroundColor),
elevation: Dp = BottomNavigationDefaults.Elevation,
content: @Composable RowScope.() -> Unit
)
BottomNavigation
提供的一些引數也就是改變顏色或者陰影,重點是在BottomNavigationItem
BottomNavigationItem(
selected: Boolean,
onClick: () -> Unit,
icon: @Composable () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
label: @Composable (() -> Unit)? = null,
alwaysShowLabel: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
selectedContentColor: Color = LocalContentColor.current,
unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium)
)
BottomNavigationItem
有個selected
引數,表示是否選中
icon
則是圖示的設定,label
則是文字,這兩個都是需要接收一個元件的
selectedContentColor
選中顏色unselectedContentColor
未選中顏色
下面直接來個例子講解
var selectIndex by remember {
mutableStateOf(0)
}
val navList = listOf("首頁","發現","我的")
BottomNavigation() {
navList.forEachIndexed { index, str ->
BottomNavigationItem(
selected = index == selectIndex, onClick = { selectIndex = index },
icon = {
Icon(imageVector = Icons.Default.Favorite, contentDescription =null )
},label = {Text(str)}
)
}
}
Text(text = "這是${navList[selectIndex]}")
效果如下所示
Scaffold
Scaffold(
modifier: Modifier = Modifier,
scaffoldState: ScaffoldState = rememberScaffoldState(),
topBar: @Composable () -> Unit = {},
bottomBar: @Composable () -> Unit = {},
snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
floatingActionButton: @Composable () -> Unit = {},
floatingActionButtonPosition: FabPosition = FabPosition.End,
isFloatingActionButtonDocked: Boolean = false,
drawerContent: @Composable (ColumnScope.() -> Unit)? = null,
drawerGesturesEnabled: Boolean = true,
drawerShape: Shape = MaterialTheme.shapes.large,
drawerElevation: Dp = DrawerDefaults.Elevation,
drawerBackgroundColor: Color = MaterialTheme.colors.surface,
drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
drawerScrimColor: Color = DrawerDefaults.scrimColor,
backgroundColor: Color = MaterialTheme.colors.background,
contentColor: Color = contentColorFor(backgroundColor),
content: @Composable (PaddingValues) -> Unit
)
屬性說明
topBar
頂部的佈局bottomBar
底部的佈局floatingActionButton
懸浮按鈕佈局floatingActionButtonPosition
懸浮按鈕位置,有FabPosition.End
(預設)和FabPosition.Center
可選isFloatingActionButtonDocked
與BottomAppBar配合使用,可以實現底部導航條的裁剪效果,效果可以看下圖drawerGesturesEnabled
是否開啟側邊抽屜手勢(開啟後可側滑彈出抽屜)drawerShape
抽屜的形狀drawerContent
側邊抽屜內容,是個Column佈局,自己可以順便排列drawerElevation
側邊抽屜的陰影drawerBackgroundColor
側邊抽屜的背景色drawerContentColor
側邊抽屜內容顏色(似乎是覆蓋字型顏色而已)drawerScrimColor
側邊抽屜遮蓋最底層的顏色
基本使用
使用5個屬性topBar
bottomBar
floatingActionButton
floatingActionButtonPosition
isFloatingActionButtonDocked
,實現個簡單架構效果
Scaffold(
topBar = {
TopAppBar(
navigationIcon = {
IconButton(
onClick = {}
) {
Icon(Icons.Filled.Menu, null)
}
},
title = {
Text("stars-one的測試應用")
},actions = {
IconButton(
onClick = {}
) {
Icon(Icons.Filled.Share, null)
}
IconButton(
onClick = {}
) {
Icon(Icons.Filled.Settings, null)
}
}
)
},
floatingActionButton = {
FloatingActionButton(onClick = { /*TODO*/ }) {
Icon(imageVector = Icons.Default.Favorite, contentDescription = null)
}
},
bottomBar = {
BottomAppBar(cutoutShape = CircleShape) {
}
},
//注意此引數,可以實現圖中那種被裁剪的效果,前提是上面的cutoutShape也有設定
isFloatingActionButtonDocked = true,
floatingActionButtonPosition = FabPosition.End
) {
//這裡是主介面
Text("我是要展示的內容")
}
效果如下圖所示
底部導航條
我們在上面的基礎改下即可(主要是bottomAppBar這個引數),程式碼如下所示
//當前選擇的NavItem
var selectIndex by remember { mutableStateOf(0) }
val navTextList = listOf("主頁", "發現", "我的")
//圖示
val iconList = listOf(Icons.Default.Home,Icons.Default.Favorite,Icons.Default.AccountBox)
Scaffold(
topBar = {
TopAppBar(
navigationIcon = {
IconButton(
onClick = {}
) {
Icon(Icons.Filled.Menu, null)
}
},
title = {
Text("stars-one的測試應用")
},actions = {
IconButton(
onClick = {}
) {
Icon(Icons.Filled.Share, null)
}
IconButton(
onClick = {}
) {
Icon(Icons.Filled.Settings, null)
}
}
)
},
floatingActionButton = {
FloatingActionButton(onClick = { /*TODO*/ }) {
Icon(imageVector = Icons.Default.Add, contentDescription = null)
}
},
bottomBar = {
BottomNavigation() {
navTextList.forEachIndexed { index, str ->
BottomNavigationItem(label = {Text(str)},selected = index==selectIndex , onClick = {selectIndex = index },icon = {
Icon(imageVector = iconList[index], contentDescription = null)
})
}
}
},
//注意此引數,可以實現圖中那種被裁剪的效果,前提是上面的cutoutShape也有設定
floatingActionButtonPosition = FabPosition.End
) {
//這裡是主介面
//根據底部導航選中的下標改變展示的頁面
when(selectIndex){
0 -> Text("這是首頁")
1 -> Text("這是發現")
2 -> Text("這是我的")
}
}
效果如下圖所示
帶側邊抽屜
這裡需要注意的是,彈出側邊抽屜是個掛起操作(suspend),所以需要使用到Kotlin中的協程,不過不是涉及太深,我們先知道怎麼用即可,後面有空我再補充協程的用法
這裡主要是測試了帶drawer開頭的那幾個引數,及點選左上角的選單按鈕彈出側邊抽屜功能(即對應的點選事件)
//狀態
val scaffoldState = rememberScaffoldState()
//協程的作用域
val scope = rememberCoroutineScope()
//當前選擇的NavItem
var selectIndex by remember { mutableStateOf(0) }
val navTextList = listOf("主頁", "發現", "我的")
//圖示
val iconList =
listOf(Icons.Default.Home, Icons.Default.Favorite, Icons.Default.AccountBox)
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
navigationIcon = {
IconButton(
onClick = {
//使用協程
scope.launch {
//改變狀態,顯示drawer抽屜
scaffoldState.drawerState.open()
}
}
) {
Icon(Icons.Filled.Menu, null)
}
},
title = {
Text("stars-one的測試應用")
}, actions = {
IconButton(
onClick = {}
) {
Icon(Icons.Filled.Share, null)
}
IconButton(
onClick = {}
) {
Icon(Icons.Filled.Settings, null)
}
}
)
},
floatingActionButton = {
FloatingActionButton(onClick = { /*TODO*/ }) {
Icon(imageVector = Icons.Default.Add, contentDescription = null)
}
},
bottomBar = {
BottomNavigation() {
navTextList.forEachIndexed { index, str ->
BottomNavigationItem(
label = { Text(str) },
selected = index == selectIndex,
onClick = { selectIndex = index },
icon = {
Icon(
imageVector = iconList[index],
contentDescription = null
)
})
}
}
},
//注意此引數,可以實現圖中那種被裁剪的效果,前提是上面的cutoutShape也有設定
floatingActionButtonPosition = FabPosition.End,
drawerContent = {
Text("這是抽屜的內容")
},
drawerContentColor = Color.Black,
drawerBackgroundColor = Color.Green,
drawerGesturesEnabled = true,
drawerScrimColor = Color.Red,
drawerShape = RoundedCornerShape(20.dp)
) {
//這裡是主介面
//根據底部導航選中的下標改變展示的頁面
when (selectIndex) {
0 -> Text("這是首頁")
1 -> Text("這是發現")
2 -> Text("這是我的")
}
}
參考
提問之前,請先看提問須知 點選右側圖示發起提問 或者加入QQ群一起學習 TornadoFx學習交流群:1071184701