1. Create the Activity Empty Compose module
. Create a new project in Android Studio and select an Empty Compose Activity, as shown in the figure below:
2. Build the main structure of the Scaffold scaffolding
/**
* Main activity
* 定义主活动
* @constructor Create empty Main activity
*/
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Ch04_ComposeTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
MainScreen()
}
}
}
}
}//end MainActivity
/**
* Main screen
* 定义主界面的脚手架框架
*/
@Composable
fun MainScreen(){
val scaffoldState = rememberScaffoldState()
Scaffold(scaffoldState = scaffoldState,
//定义头部
topBar={
},
//定义侧滑内容
drawerContent = {
},
//定义中心区内容,实现界面的切换
content={
},
//定义底部的导航内容
bottomBar = {
},
//定义悬浮按钮
floatingActionButton={
}
)//end Scaffold
}
Call the scaffolding main frame in the main activity MainActivity
3. Define the three interfaces that need to be switched: HomeScreen, SettingScreen, HelpScreen The
display effect is as shown in the figure:
/** 定义首页界面*/
@Preview
@Composable
fun HomeScreen(){
Column(modifier= Modifier
.fillMaxSize()
.padding(10.dp)
.background(colorResource(id = R.color.teal_200)),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
content = {
Text(text="首页界面",color=Color.White,
fontSize=36.sp, fontWeight = FontWeight.ExtraBold)
})
}
/**定义配置界面*/
@Preview
@Composable
fun SettingScreen(){
Column(
content = {
Text("配置界面",
fontSize=36.sp,
color = Color.White)
},
modifier = Modifier
.fillMaxSize()
.background(colorResource(R.color.teal_200)),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
)
}
/**定义帮助界面*/
@Preview
@Composable
fun HelpScreen(){
Column(modifier= Modifier.fillMaxSize()
.background(colorResource(id = R.color.teal_200)),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally){
Text("帮助界面",color= Color.White,fontSize=36.sp)
}
}
You can also define a general combination function, and then let the combination function that defines an interface be called, like this:
@Composable
fun DisplayText(content:String){
Column(modifier= Modifier.fillMaxSize()
.background(colorResource(id = R.color.teal_200)),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally){
Text("$content",color= Color.White,fontSize=36.sp)
}
}
The modifications to the three interfaces are as follows:
/** 定义首页界面*/
@Preview
@Composable
fun HomeScreen(){
DisplayText("首页界面")
}
/**定义配置界面*/
@Preview
@Composable
fun SettingScreen(){
DisplayText("配置界面")
}
/**定义帮助界面*/
@Preview
@Composable
fun HelpScreen(){
DisplayText("帮助界面")
}
4. Define the switching screen interface in the sealed class
/**
* 定义要切换界面的密封类
* @property route String 导航线路
* @property title String 标题
* @property icon ImageVector 图标
* @property screenToLoad [@androidx.compose.runtime.Composable] Function0<Unit> 加载动作处理
* @constructor
*/
sealed class Screens(val route:String, val title:String, val icon: ImageVector, val screenToLoad:@Composable ()-> Unit){
object HomePage:Screens("home","首页界面", Icons.Filled.Home,{
HomeScreen()
})
object SettingPage:Screens("setting","配置界面",Icons.Filled.Settings,{
SettingScreen()
})
object HelpPage:Screens("help","帮助界面",Icons.Filled.Info,{
HelpScreen()
})
}
Define the list of saved screen interfaces
//Define the list of interfaces to be switched
val screens = listOf<Screens>(Screens.HomePage,Screens.SettingPage,Screens.HelpPage)
5. Create the navigation of the side-sliding menu.
Create the side-sliding menu. The display effect is as follows:
(1) Define the top content of the side-sliding menu
/**
* Top bar view
* 定义头部
*/
@Preview
@Composable
fun HeaderBarView(){
Box(modifier= Modifier
.fillMaxWidth()
.wrapContentHeight()
.background(color = colorResource(id = R.color.purple_200))){
Row(modifier= Modifier
.fillMaxWidth()
.padding(5.dp)){
Column{
Image(painter=painterResource(id = android.R.mipmap.sym_def_app_icon),
contentDescription = "logo图标",
modifier= Modifier .width(dimensionResource(id = R.dimen.image_width))
.height(60.dp)
.clip(shape = CircleShape)
.background(Color.Black))
}//end Column
Column{
Text(stringResource(id = R.string.title_robot))
Text(stringResource(id = R.string.title_introduction))
}
}//end Column
}
}
(2) Define side sliding menu
/**
* 定义侧滑的下面的菜单
* @param scaffoldState ScaffoldState 脚手架的状态
* @param action Function1<[@kotlin.ParameterName] Screens, Unit>? 要处理的切换动作,默认为空
*/
@Composable
fun DrawerViews(scaffoldState: ScaffoldState,
action: ((screen:Screens) -> Unit)?=null){
val scope = rememberCoroutineScope()
Column(modifier= Modifier.fillMaxSize()){
screens.forEach { screen->
val clickable =remember{ mutableStateOf(false) }
Row(verticalAlignment = Alignment.CenterVertically){
IconButton(onClick={
action?.invoke(screen)
clickable.value = !clickable.value
scope.launch {
scaffoldState.drawerState.close()
}
}){
Icon(imageVector = screen.icon,"${screen.title}")
}
Text("${screen.title}",fontSize=20.sp, fontWeight = FontWeight.Bold,
color = if(clickable.value) colorResource(id = R.color.purple_500) else colorResource(id = R.color.teal_700))
}
}
}
}
(3) Combine the contents of the two parts into the main frame of the scaffolding.
Add processing of side sliding menu in scaffolding
/**
* Main screen
* 定义主界面的脚手架框架
*/
@Composable
fun MainScreen(){
//脚手架的状态
val scaffoldState = rememberScaffoldState()
//当前的屏幕
Val currentScreen:MutableState<Screens>=
remember{ mutableStateOf(Screens.Home) }
Scaffold(scaffoldState = scaffoldState,
//定义头部
topBar={
},
//定义侧滑内容
drawerContent = {
HeaderBarView()
DrawerViews(scaffoldState){screen->
currentScreens.value = screen
}
},
//主界面显示区
content={
currentScreens.value.screenToLoad()
},
.......
)//end Scaffold
}
6. Create navigation for the application header
/**
* 定义应用头部内容
* 在头部定义一个导航菜单
* @param scaffoldState ScaffoldState 脚手架的状态
*/
@Composable
fun TopBarView(currentScreen:MutableState<Screens>,scaffoldState: ScaffoldState){
//协程的范围
val scope = rememberCoroutineScope()
TopAppBar(
title={
Text("${currentScreen.title}",fontSize=20.sp)
},
navigationIcon={
IconButton(onClick={
scope.launch {
scaffoldState.drawerState.open()
}
}){
Icon(imageVector = Icons.Filled.Home,contentDescription="",tint=Color.White)
}
},
actions={
IconButton(onClick = {
}) {
Icon(imageVector = Icons.Filled.MoreVert,contentDescription="",tint=Color.White)
}
},
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
backgroundColor = Color.Black,
contentColor = Color.White
)
}
Description:
(1) scaffoldState: ScaffoldState is used to handle scaffolding-related operations, here it is used to open the side-sliding menu.
(2) Define TopAppBar to define a head action bar similar to ActionBar.
Modify the scaffolding defined in MainActivity.kt and add TopBar functionality
/**
* Main screen
* 定义主界面的脚手架框架
*/
@Composable
fun MainScreen(){
val scaffoldState = rememberScaffoldState()
val currentScreens:MutableState<Screens> = remember{ mutableStateOf(Screens.HomePage) }
Scaffold(scaffoldState = scaffoldState,
topBar = {
TopBarView(currentScreen,scaffoldState)
},
drawerContent = {
HeaderBarView()
DrawerViews(scaffoldState){screen->
currentScreens.value = screen
}
},
content={
currentScreens.value.screenToLoad()
},
......
}
7. Create the navigation at the bottom of the application.
The running effect is as follows:
Define the content of the bottom navigation bar
/**
* 定义应用底部的视图
*接收从外部传递的要显示的当前界面
*/
@Composable
fun BottomViews(currentScreen:MutableState<Screens>){
BottomAppBar(
backgroundColor = Color.Blue,
contentColor = Color.Yellow){
screens.forEach { screen->
BottomNavigationItem(
icon = {
Icon(imageVector = item.icon, contentDescription = "${screen.title}")
} ,
label={
Text("${screen.title}")
},
selected = screen.route == currentScreen.value.route,
onClick = {
currentScreen.value = screen
}
)
}
}
}
(3) The bottom navigation bar is added to the scaffolding and bottom navigation is implemented.
In the scaffolding in MainActivity.kt, the processing of the bottom navigation bar is added.
@Composable
fun MainScreen(){
val scaffoldState = rememberScaffoldState()
val currentScreens:MutableState<Screens> = remember{ mutableStateOf(Screens.HomePage) }
Scaffold(scaffoldState = scaffoldState,
topBar = {
TopBarView(currentScreen,scaffoldState)
},
drawerContent = {
HeaderBarView()
DrawerViews(scaffoldState){screen->
currentScreens.value = screen
}
},
content={
currentScreens.value.screenToLoad()
},
bottomBar = {
BottomViews(currentScreen = currentScreens)
},
......
}
8. Scaffolding adds a floating button to return to the homepage
@Composable
fun MainScreen(){
//脚手架的状态
val scaffoldState = rememberScaffoldState()
//当前显示的界面
val currentScreen:MutableState<Screens> = remember{ mutableStateOf(Screens.HomePage) }
//当前的上下文
val context = LocalContext.current
Scaffold(scaffoldState = scaffoldState,
topBar = {
TopBarView(currentScreen,scaffoldState)
},
drawerContent = {
HeaderBarView()
DrawerViews(scaffoldState){screen->
currentScreen.value = screen
}
},
content={
currentScreen.value.screenToLoad()
},
bottomBar = {
BottomViews(currentScreen = currentScreen)
},
floatingActionButton = {
FloatingActionButton(
backgroundColor = Color.Red,
onClick = {
Toast.makeText(context,"返回首页",Toast.LENGTH_LONG).show()
currentScreen.value = Screens.HomePage
}){
Icon(Icons.Filled.Home, contentDescription = "返回首页")
}
})
}
参考文献
(1)https://www.geeksforgeeks.org/bottom-navigation-bar-in-android-jetpack-compose/
(2)https://amryousef.me/side-drawer-jetpack-compose