Android Compose自推出正式版本后,google 就不停保举利用Compose来开辟。恰好疫情期间,作为一个 Android 摸鱼达人,就来探索一下Compose的开辟。说真话开辟了2天感觉对Android 开辟职员来说变革是巨大的,但是作为从业者我们还必须学习和学会,才能不被甩开。
学习利用 Compose 我们必要坐什么呢?
1.利用 Kotlin
2.利用Android Studio 最新版本开辟工具
3.去官网查察教程,跟着google 一步一个脚迹的学习->官方文档速转通道
- Jetpack Compose 利用入门
https://developer.android.google.cn/jetpack/compose/documentation
- Compose 教程
https://developer.android.google.cn/courses/pathways/compose
- Compose 示例
https://github.com/android/compose-samples
- Codelab: 在 Jetpack Compose 中利用状态
https://developer.android.google.cn/codelabs/jetpack-compose-state
4.找其他开辟者的文档,更详细更服从的学习
- https://jetpackcompose.cn/docs文档和开源项目
- https://github.com/Gurupreet/ComposeCookBook开源项目
下载工具
利用 Android Studio Bumblebee 大黄蜂?版本,假如不想影响老版本 Android Studio 的运行项目,可以下载 zip 的版本。AS尽大概升级到最新版,最少也要Arctic Fox,老版本无法实现 Compose 的预览和开辟
官方下载地点:https://developer.android.google.cn/studio
快速下载地点:https://www.androiddevtools.cn/
下载后创建 Compose 项目,假如你电脑配置的 java为11,那么就没题目。假如出现题目如下:
Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8.
You can try some of the following options:
- changing the IDE settings.
- changing the JAVA_HOME environment variable.
- changing org.gradle.java.home in gradle.properties.
Gradle settings
办理方案为:
1.更新 java 到11,完善。固然你根本用不到11
2.到体系设置中Preferences -> Build Tools ->Gradle , 选择 Gradle JDK 为11
Compose项目构成
在项目可以正式运行后,我们可以先打开MainActivity,继承ComponentActivity()包罗了setContent()方法,假如去除setContent内的代码运行可以看到一个空页面。
然后我们添加一个文本控件Text,对应原生的TextView。
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text("Hello world!") } }}项目运行起来后我们看下整个项目标代码是怎么样的。
Compose 的引入
buildscript { ext { compose_version = '1.0.1' }}//compose 核心implementation "androidx.compose.ui:ui compose_version"implementation "androidx.compose.material:material compose_version"implementation "androidx.compose.ui:ui-tooling-preview compose_version"另外 google 提供了非常多的compose 库,详细查察可以到https://developer.android.google.cn/jetpack/androidx/explorer查察。
初识组件
Compose 内部的组件非常少,但是合理的搭配可以做到比安卓原生更好的开辟体验。大要如下:
分类Compose原生文本TextTextView文本TextFieldEdittext图片IconImageView图片ImageImageViewButtonButtonButtonButtonIconButtonButtonButtonIconToggleButtonCheckBox,SwitchButtonSwitchSwitchButtonRadioButtonRadioButtonButtonCheckboxCheckBox布局BoxFrameLayout布局ColumnLinearLayout布局RowLinearLayout布局Scaffold无布局ConstraintlayoutConstraintlayout列表LazyColumnRecyclerView,ListView列表LazyRowRecyclerView,ListView间距类SpacerSpace(估计许多人都没用过)我们直接在setContent添加个 Text 和 Image 控件,下面代码就是最简单的写法。
Text、Image应该是我们最常用的控件,特别是 Text 可实现的功能特别多,详细可以去看后续文章大概看下其他博客。
setContent { Text("Hello world!") Image( painter = painterResource(R.drawable.share_calc), contentDescription = null )}上面的展示代码会使内容重叠,必要利用 Row 大概 Column。
按照下面展示,我们添加了Column垂直布局,控件就往下绘制不重叠了。
Row 、Column、Box
Column 垂直布局 -- 对用 LinearLayout 的android rientation="vertical";Row 程度布局 -- 对用 LinearLayout 的android rientation="horizontal";Box靠近FrameLayout,详细利用可以看下图的例子.
Compose 中的三个根本尺度布局元素是 Column、Row 和 Box 可组合项。
Column(){Text("Hello world!")Image( painter = painterResource(R.drawable.share_calc), contentDescription = null )}Row(){Text(" Row W")Image( painter = painterResource(R.drawable.share_calc), contentDescription = null )}Box( modifier = Modifier .background(Color.Cyan) .size(180.dp) ) { Box( modifier = Modifier .align(Alignment.TopCenter) .size(60.dp, 60.dp) .background(Color.Red) ) { } Box( modifier = Modifier .align(Alignment.BottomEnd) .size(60.dp, 60.dp) .background(Color.Blue) ) { } }
Scaffold脚手架和Constraintlayout布局
Scaffold脚手架我们先看下源码,可以看到包罗了topBar、bottomBar、floatingActionButton等控件的页面。这是个固定布局,当我们的首页符合该页面固定样式时,可以直接利用该布局。
Constraintlayout布局和Android 原生一样
@Composablefun 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) TextField文本输入控件
@Composablefun InputText() { val input = remember { mutableStateOf("") } TextField(value = input.value, onValueChange = { input.value = it })}Icon 和 Image图片类
Row { Icon(painter = painterResource(R.drawable.database_set), contentDescription = null) Spacer(modifier = Modifier.width(8.dp)) Image( painter = painterResource(R.drawable.share_calc), contentDescription = null ) }Button 类
Compose Button多种多样,详细的各人可以先看 UI 展示,就能明确在详细场景下利用什么 button。估计是参考的H5前端的按钮样式
Button 就是带配景致的按钮,OutlinedButton是带边框绘制的,TextButton是无配景致的按钮。其他都可以参考原生的样式
Row() { //普通按钮 Button(onClick = { /*TODO*/ }) { Text(text = "Button") } Spacer(modifier = Modifier.width(8.dp)) //带边框绘制的 button OutlinedButton(onClick = { /*TODO*/ }) { Text(text = "OutlinedButton") } Spacer(modifier = Modifier.width(8.dp)) //纯笔墨按钮 TextButton(onClick = {}) { Text("TextButton") } }Row() { //带Icon的按钮 //圆形水波纹和 Checkbox,Switch 水波纹效果同等, //android 可以看下设置android:background="?attr/selectableItemBackgroundBorderless"("?attr/actionBarItemBackground")的效果 IconButton(modifier = Modifier.width(120.dp), onClick = { /*TODO*/ }) { Row() { Icon( painter = painterResource(id = R.drawable.database_set), contentDescription = null ) Spacer(modifier = Modifier.width(8.dp)) Text("IconButton") } } //图标切换 button,雷同于switch,但是更靠近于CheckBox //圆形水波纹和Checkbox,Switch 水波纹效果同等, //android 可以看下设置android:background="?attr/selectableItemBackgroundBorderless"("?attr/actionBarItemBackground")的效果 IconToggleButton(checked = false, onCheckedChange = {}) { Text(text = "IconToggleButton") } //悬浮按钮 ExtendedFloatingActionButton(text = { Text(text = "FAB") }, onClick = { }) }RadioButton\Checkbox和原生对应,但是没 text 属性,假如必要体现文本必要和 Text 控件组合利用
RadioDefault() RadioText() RadioButtonGroup() Row() { CheckboxDefault() SwitchDefault() }@Composablefun RadioDefault() { val isSelected = remember { mutableStateOf(false) } RadioButton(selected = isSelected.value, onClick = { isSelected.value = !isSelected.value Log.e(TAG, "默认Checkbox,同RadioButton不带text文本控件") })}@Composablefun RadioText() { val isSelected = remember { mutableStateOf(false) } // 假如必要 text 必要和 Text 组合利用,click处置惩罚在row上 Row(modifier = Modifier.clickable { isSelected.value = !isSelected.value }) { RadioButton( selected = isSelected.value, onClick = null, colors = RadioButtonDefaults.colors( selectedColor = MaterialTheme.colors.primary, unselectedColor = MaterialTheme.colors.error, disabledColor = MaterialTheme.colors.secondary ) ) Text("选项②") }}@Composablefun RadioButtonGroup() { val options = listOf("选项③", "选项④", "选项⑤", "选项⑥") val selectedButton = remember { mutableStateOf(options.first()) } //RadioButton 不带 text 文本控件, Row() { options.forEach { val isSelected = it == selectedButton.value Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clickable { selectedButton.value = it }) { RadioButton( selected = isSelected, onClick = null, ) Text(it, textAlign = TextAlign.Justify) } } }}@Composablefun CheckboxDefault() { val isSelected = remember { mutableStateOf(false) } Checkbox(checked = isSelected.value, onCheckedChange = { isSelected.value = it Log.e(TAG, "默认Checkbox,同RadioButton不带text文本控件") })}@Composablefun SwitchDefault() { val isSelected = remember { mutableStateOf(false) } Switch(checked = isSelected.value, onCheckedChange = { isSelected.value = it Log.e(TAG, "默认Checkbox,同RadioButton不带text文本控件") })}界说一个带 Text 的 RadioButton
@Composablefun RadioText() { val isSelected = remember { mutableStateOf(false) } // 假如必要 text 必要和 Text 组合利用,click处置惩罚在row上 Row(modifier = Modifier.clickable { isSelected.value = !isSelected.value }) { RadioButton( selected = isSelected.value, onClick = null, colors = RadioButtonDefaults.colors( selectedColor = MaterialTheme.colors.primary, unselectedColor = MaterialTheme.colors.error, disabledColor = MaterialTheme.colors.secondary ) ) Text("选项②") }}Compose 无RadioGroup 组件,假如必要实现RadioGroup也必要组合利用
界说 RadioGroup 组件,在循环中改变状态
@Composablefun RadioButtonGroup() { val options = listOf("选项③", "选项④", "选项⑤", "选项⑥") val selectedButton = remember { mutableStateOf(options.first()) } //RadioButton 不带 text 文本控件, Row() { options.forEach { val isSelected = it == selectedButton.value Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clickable { selectedButton.value = it }) { RadioButton( selected = isSelected, onClick = null, ) Text(it, textAlign = TextAlign.Justify) } } }}同理Checkbox和Switch控件就不细说了。对应的参数改成了checked和onCheckedChange,也是没有 text 属性,必要组合利用。
@Composablefun CheckboxDefault() { val isSelected = remember { mutableStateOf(false) } Checkbox(checked = isSelected.value, onCheckedChange = { isSelected.value = it Log.e(TAG, "默认Checkbox,同RadioButton不带text文本控件") })}@Composablefun SwitchDefault() { val isSelected = remember { mutableStateOf(false) } Switch(checked = isSelected.value, onCheckedChange = { isSelected.value = it Log.e(TAG, "默认Checkbox,同RadioButton不带text文本控件") })}LazyColumn、LazyRow
LazyColumn 和 LazyRow 相称于 Android View 中的 RecyclerView。它们只会渲染屏幕上可见的内容,从而在渲染大型列表时提拔服从。
注意:LazyColumn 不会像 RecyclerView 一样回收其子级。它会在您滚动它时发出新的可组合项,并保持高效运行,由于与实例化 Android Views 相比,发出可组合项的资本相对较低。
@Composablefun RecyclerView(names: List<String> = List(1000) { "$it" }) { LazyColumn() { items(items = names) { item -> MessageCard(item) } }}@Composablefun MessageCard(msg: String) { var isExpanded by remember { mutableStateOf(false) } val surfaceColor: Color by animateColorAsState( if (isExpanded) MaterialTheme.colors.primary else MaterialTheme.colors.surface, ) Row(modifier = Modifier .fillMaxWidth() .clickable { isExpanded = !isExpanded } .padding(8.dp) ) { Image( painter = painterResource(R.drawable.share_calc), contentDescription = null, modifier = Modifier .size(40.dp) .clip(CircleShape) .border(1.5.dp, MaterialTheme.colors.secondaryVariant, CircleShape) ) Spacer(modifier = Modifier.width(8.dp)) // We toggle the isExpanded variable when we click on this Column Column() { Text("当前索引:") Spacer(modifier = Modifier.height(4.dp)) Surface( shape = MaterialTheme.shapes.medium, elevation = 1.dp, // surfaceColor color will be changing gradually from primary to surface color = surfaceColor, // animateContentSize will change the Surface size gradually modifier = Modifier .animateContentSize() .padding(1.dp) ) { Text( text = "索引为--------> $msg ,这是一个可睁开和关闭的 Text 控件:" + "微凉的晨露 沾湿黑制服\n" + "石板路有雾 父在低诉\n" + "无奈的觉悟 只能更暴虐\n" + "统统都为了通往圣堂的路", modifier = Modifier.padding(all = 4.dp), maxLines = if (isExpanded) Int.MAX_VALUE else 1, style = MaterialTheme.typography.body2 ) } } }}这边界说了一个内容为1000行的 List,利用LazyColumn包裹,同时在 MessageCard 中对点击坐了处置惩罚,点击后放开 Text 的行数限定。详细效果如下
这篇博客只是只是展示了控件的简单利用,快速的相识控件的创建及展示效果。
下一篇我们先容怎样跳转页面。 |