Android JetPack Compose组件中Scaffold的应用【转】

393 阅读4分钟

一、 创建Activity Empty Compose模块
在Android Studio中创建一个新的项目,选择一个Empty Compose Activity,如下图所示:
Empty Compose Activity
二、搭建Scaffold脚手架主结构

/**
 * 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
}

在主活动MainActivity中调用脚手架主框架
三、定义需要切换的三个界面:HomeScreen、SettingScreen、HelpScreen
显示效果如图所示:
切换的界面

/** 定义首页界面*/
@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)
        }
}

四、将切换屏幕界面定义在密封类中

/**
 * 定义要切换界面的密封类
 * @property route String
 * @property title String
 * @property screenToLoad [@androidx.compose.runtime.Composable] Function0<Unit>
 * @constructor
 */
sealed class Screens(val route:String,val title:String,
val screenToLoad:@Composable ()->Unit){
    object Home:Screens("home","首页", {
        HomeScreen()
    })
    
    object Setting:Screens("setting","配置页面",{
        SettingScreen()
    })
    
    object Help:Screens("help","帮助页面",{
        HelpScreen()
    })
}

定义保存屏幕界面的列表中
//定义要切换的界面列表

val screens = listOf<Screens>(Screens.Home,Screens.Setting,Screens.Help)

五、创建侧滑菜单的导航
创建侧滑菜单,显示效果如下所示:
侧滑菜单显示效果(1)定义侧滑菜单的顶部内容

/**
 * Top bar view
 * 定义头部
 */
@Preview
@Composable
fun TopBarView(){
   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 = R.mipmap.boy),
                       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)定义侧滑菜单

/**
 * 定义侧滑的下面的菜单
 * @param selectedScreen Screens 要选择切换的界面
 * @param onMenuSelected Function1<[@kotlin.ParameterName] Screens, Unit>? 要处理的切换动作,默认为空
 */
@Composable
fun DrawerMenuView(selectedScreen:Screens,
onMenuSelected:((screen:Screens)->Unit)?=null){
    Column(modifier=Modifier.fillMaxWidth()){
        //对每个界面进行遍历访问
        screens.forEach{it:Screens->
            Row(
                content = {
                  Text(text = it.title,
                      fontSize=20.sp, fontWeight = FontWeight.Bold,
                  color = if(it.route==selectedScreen.route)  colorResource(id = R.color.purple_500) else colorResource(id = R.color.teal_700))
                },
                modifier = Modifier.fillMaxWidth()
                    .padding(horizontal = 16.dp, vertical = 8.dp)
                    .clickable {//处理点击动作
                        onMenuSelected?.invoke(it)
                    }
                )//end Row
        }
    }
}

(3)组合两部分的内容到脚手架主框架中。
在脚手架中增加侧滑菜单的处理

/**
 * Main screen
 * 定义主界面的脚手架框架
 */
@Composable
fun mainScreen(){
    //脚手架的状态
    val scaffoldState = rememberScaffoldState()
    //协程的范围
    val scope = rememberCoroutineScope()
    //当前的屏幕
Val currentScreen:MutableState<Screens>= 
remember{ mutableStateOf(Screens.Home) }

    Scaffold(scaffoldState = scaffoldState,
        //定义头部
        topBar={

        },
        //定义侧滑内容
        drawerContent = {
            TopBarView()
            **DrawerMenuView**(selectedScreen = currentScreen.value){screen->
                scope.launch {
                    //关闭侧滑菜单
                    **scaffoldState.drawerState.close()**
                }
		 //将选择的菜单设置为当前菜单
                currentScreen.value = screen
            }
        },
        .......
    )//end Scaffold
}

六、创建应用头部的导航

/**
 * 定义应用头部内容
 * 在头部定义一个导航菜单
 * @param currentScreen Screens 当前屏幕界面
 * @param scaffoldState ScaffoldState 脚手架的状态
 * @param scope CoroutineScope  协程的范围
 */
@Composable
fun TopAppView(currentScreen:Screens,
scaffoldState:ScaffoldState,scope:CoroutineScope){
    TopAppBar(title = {//标题
                Text(currentScreen.title)
             },
            navigationIcon = {//导航图标
                IconButton(onClick = {
                    scope.launch {
                        scaffoldState.drawerState.open()//打开侧滑菜单
                    }//end scope.launch
                }){
                    Icon(Icons.Filled.Menu,"Home导航图标") //定义图标
                }
            },//end navigationIcon
            backgroundColor = Color.Blue,
            contentColor =Color.White
    )
}

说明:
(1) scaffoldState:ScaffoldState,scope:CoroutineScope必须与脚手架中使用的scaffoldState对象和scope协程对象已知,否则无法控制导航的实现;
(2) currentScreen是正在显示的屏幕界面,用于头部标题的显示
(3) 定义TopAppBar来定义类似ActionBar的头部动作条。
修改MainActivity.kt中定义的脚手架,增加TopBar的功能

/**
 * Main screen
 * 定义主界面的脚手架框架
 */
@Composable
fun mainScreen(){
    //脚手架的状态
    val scaffoldState = rememberScaffoldState()
    //协程的范围
    val scope = rememberCoroutineScope()
    //当前的屏幕
    val currentScreen: MutableState<Screens> = remember{ mutableStateOf(Screens.Home) }

    Scaffold(scaffoldState = scaffoldState,
        //定义头部
        topBar={
            TopAppView(currentScreen = currentScreen.value, 
scaffoldState =scaffoldState , scope =scope )
        },
       ......
    )//end Scaffold
}

七、创建应用底部的导航
运行效果如下所示:
底部导航
(1) 定义底部导航菜单项单项实体类

/**
 * 定义底部的菜单单项
 * @property label String 菜单项
 * @property icon ImageVector 菜单的图标
 * @property route String  菜单的路线
 * @property screen Screens 菜单选择对应的界面
 * @constructor
 */
data class BottomMenuItem(val label:String,
                          val icon: ImageVector,
                          val route:String,
                          val screen:Screens)

(2) 定义底部导航栏的内容

/**
 * 定义应用底部的视图
  *接收从外部传递的要显示的当前界面
 */
@Composable
fun BottomAppView(currentScreen:MutableState<Screens>){
    //定义底部菜单项列表
    val menuItems = listOf<BottomMenuItem>(
        BottomMenuItem("首页", Icons.Filled.Home,"home",Screens.Home),
        BottomMenuItem("配置界面", Icons.Filled.Settings,"setting",Screens.Setting),
        BottomMenuItem("帮助界面", Icons.Filled.Info,"help",Screens.Help)
    )

    BottomNavigation(backgroundColor = Color.Blue,
        contentColor = Color.White, elevation = 5.dp) {
        menuItems.forEach { menuItem ->
            BottomNavigationItem(//定义单项
                //选择菜单项的状态
                selected = menuItem.route == currentScreen.value.route,
                //图标
                icon={
                    Icon(imageVector = menuItem.icon,
contentDescription = menuItem.label)
                },
                //文本
                label={
                    Text(menuItem.label)
                },
                //点击动作处理
                onClick = {
                    currentScreen.value = menuItem.screen
                })
        }//end forEach
    }
}

(3) 底部导航栏加入到脚手架中,并实现底部导航
在MainActivity.kt中的脚手架中,增加底部导航栏的处理

@Composable
fun mainScreen(){
    //脚手架的状态
    val scaffoldState = rememberScaffoldState()
    //协程的范围
    val scope = rememberCoroutineScope()
    //当前的屏幕
    val currentScreen: MutableState<Screens> = remember{ mutableStateOf(Screens.Home) }

    Scaffold(scaffoldState = scaffoldState,
        .....
        //定义底部的导航内容
        bottomBar = {
            **BottomAppView(currentScreen)**
        }
        .....
    )//end Scaffold
}

八、脚手架增加浮动按钮返回首页的处理
增加悬浮按钮

@Composable
fun mainScreen(){
    //脚手架的状态
    val scaffoldState = rememberScaffoldState()
    //协程的范围
    val scope = rememberCoroutineScope()
    //当前的屏幕
    val currentScreen: MutableState<Screens> = remember{ mutableStateOf(Screens.Home) }
    //当前上下文
    val context = LocalContext.current

    Scaffold(scaffoldState = scaffoldState,
       ......
        floatingActionButton = {
           FloatingActionButton(onClick = {
               Toast.makeText(context,"返回首页",Toast.LENGTH_LONG).show()
               currentScreen.value = Screens.Home
           }){
               Icon(Icons.Filled.Home, contentDescription = "返回首页")
           }
        }
    )//end Scaffold
}

参考文献
(1)www.geeksforgeeks.org/bottom-navi…
(2)amryousef.me/side-drawer…

本文转自 blog.csdn.net/userhu2012/…,如有侵权,请联系删除。