Scaffold
我们知道Flutter里有一个Scaffold控件,中文翻译过来是脚手架的意思,它实现了基本的Material Design可视化的布局结构,提供了抽屉drawer、snackbar和底部导航栏的API,帮我们更方便的定义页面布局。在Compose中也有Scaffold,我们看看它是怎么使用的。
Scaffold的简单了解
我们先看看它的方法体参数:
@Composable
fun 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
)
可以看到,Scaffold的参数很多,但方便的是你可以选择使用其中的几个,因为这些参数都有默认值,我们通过一个例子来看看它的使用:
// Scaffold的使用
Scaffold(
topBar = { /*标题栏*/
TopAppBar(title = { Text("标题") }, navigationIcon = {
IconButton(onClick = { /*点击事件*/ }) {
Icon(Icons.Filled.ArrowBack, "")
}})
},
floatingActionButton = { /*悬浮按钮*/
FloatingActionButton(onClick = {
// Floating点击事件
Log.e("LM" , "点击了FloatingButton")
}) {
Text("OK")
}
},
content = { /*主内容*/
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text("主屏幕", fontSize = 40.sp)
}
}
)
我们添加了一个标题栏、一个悬浮按钮和主屏幕,这些在Android View里也不陌生,运行效果如下:
点击悬浮按钮后可以看到控制台打印日志:
2022-04-09 09:22:42.330 21719-21719/com.carey.compose E/LM: 点击了FloatingButton
抽屉的实现
在Android View中要实现抽屉的效果不容易,但是在Compose中实现起来却很容易,在Scaffold的方法里有关于抽屉的参数,我们只需要设置上即可:
drawerContent = {
Column(modifier = Modifier
.fillMaxSize()
.background(Color.Blue),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "侧边栏抽屉", fontSize = 30.sp)
}
}
代码很简单,一个充满父布局的Column里包含一个Text,运行代码如上图,可以看到从左往右能拉出一个抽屉的效果。其实Scaffold还可以设置很多的样式和功能,可以根据自己的业务需求场景去实现自己的效果,可以去尝试下。
ConstraintLayout
ConstraintLayout还是很常见的,Android View中也常用,很好用,能很好的解决布局层次问题。如:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Text1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Text2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/text1"/>
<TextView
android:id="@+id/text3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Text3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/text2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
约束布局优点很多,但是要实现对齐要求比较复杂的较大布局时,ConstraintLayout很有用,但在创建简单布局时,Compose中首选Column和Row。和Column和Row等布局不同,约束布局需要额外添加依赖:
implementation 'androidx.constraintlayout:constraintlayout-compose:1.0.0'
虽然约束布局可以替代多个嵌套Row、Column、Box和自定义布局,但只是替代,性能上没有显著提升,因为Compose可以高效处理较深布局层次结构,所以还是推荐使用约束布局,方便后期维护。
Compose中的ConstraintLayout支持DSL:ConstraintLayout中每个可组合项都需要有与之关联的引用,引用是使用createRefs或createRef创建的,不同的是createRefs可以同时创建多个引用,而createRef只能创建一个引用。约束条件是使用constrainAs修饰符提供的,该修饰符将引用作为参数,既可以在主体lambda中指定约束条件,也可以使用linkTo或其它有用的方法指定。parent是一个现有的引用(ConstraintLayout本身),可用于指定对ConstraintLayout可组合项本身的约束条件。我们看一个例子:
@Composable
fun DefaultText(text: String, modifier: Modifier) {
Text(
text,
modifier = modifier.size(100.dp)
.background(Color.Red),
fontSize = 30.sp,
textAlign = TextAlign.Center
)
}
ConstraintLayout(modifier = Modifier.fillMaxSize()) {
val (one, two) = createRefs()
val three = createRef()
DefaultText(
"",
modifier = Modifier.constrainAs(one) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(parent.top, margin = 16.dp)
}
)
DefaultText("Two", Modifier.constrainAs(two) {
start.linkTo(parent.start)
end.linkTo(parent.end)
top.linkTo(one.bottom, margin = 16.dp)
})
DefaultText("Three", Modifier.constrainAs(three) {
start.linkTo(parent.start)
end.linkTo(parent.end)
bottom.linkTo(parent.bottom, margin = 16.dp)
})
}
]
我们可以看到,首先创建了一个可组合项DefaultText,然后在ConstraintLayout中使用DefaultText,接着通过createRefs创建了一个多引用,又通过createRef创建了一个单引用。下面的可组合项通过constrainAs和引用进行关联,又通过start.linkTo(parent.start)和end.linkTo(parent.end)将可组合项定位到父布局的水平中间位置,并添加了margin=16dp,之后将可组合项Two放到One的下面,最后将可组合项Three放到父布局的底部。最终效果如上图所示。
我们可以看到,和Android View中的约束布局ConstraintLayout约束条件是一致的,大家可以试着用用其它的属性。