文章目录

1.概述2.相关组件(最好是每个都知道是做什么的)3.基本用法4.通过Compose UI简单的实现一个登录界面

1.概述

Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API,可以帮助您简化并加快 Android 界面开发. 但是需要熟悉一下新的Compose的相关控件,虽然也是文本,图片,水平,垂直,但不是LinearLayout,ImageView这些了,不过也类似,记住就行了.

2.相关组件(最好是每个都知道是做什么的)

Text:用于呈现文本的控件。 TextField:可以让用户输入文本的控件。 Button:用于执行操作的控件。 Image:用于显示图像的控件。 Row: 横排布局 Column: 是竖排布局 Card:用于呈现卡片式布局的控件。 Scaffold:可以将应用程序的基本UI元素包装在一起的控件。 FloatingActionButton: 实现浮动操作按钮 Slider:实现滑动条 ProgressBar:实现进度条 Tab:用于在选项卡之间切换的控件。 BottomNavigation:实现底部导航栏 Dialog:用于显示对话框的控件。 Column:用于将子控件垂直排列 Row:用于将子控件水平排列 Box:类似于 FrameLayout,可以用于布局或者装饰 Scaffold:实现 Material Design 风格的屏幕布局 Surface:实现 Material Design 风格的表面,具有形状和阴影 Divider:用于绘制分割线,可以在Column和Row中使用。 TextButton:实现文本按钮 OutlinedButton:实现带边框的按钮 Checkbox:实现多选框 RadioGroup:实现单选框 TabRow:实现选项卡,可用于导航 ModalBottomSheet:实现底部弹出框 AlertDialog:实现弹出框 BottomSheet: 底部弹出式窗口。 Menu: 弹出式菜单。 Tooltip: 文本提示框。 RadioButton: 单选框。 Switch: 开关按钮。 LinearProgressIndicator: 线性进度指示器 CircularProgressIndicator:圆形进度指示器,圆形进度条。 Spacer:用于占据空白区域,并支持自定义大小 AppBar: 应用栏。 Drawer: 抽屉式布局。用于显示侧边栏的控件。 Box:用于在自由布局中控制位置、大小和绘制顺序等。 Snackbar:用于在屏幕底部显示消息的控件。 Navigation:用于管理应用程序的导航,提供了一种可以让用户从一个屏幕到另一个屏幕的方式。 ViewPager2:用于创建可左右滑动的页面。 SwipeRefreshLayout:可用于实现下拉刷新操作的控件。 ProgressIndicator:用于显示进度的控件,提供了多种样式,如环形进度条、线性进度条等。 WebView:用于在应用中加载网页的控件。 SurfaceView:用于在应用中显示视频的控件,支持播放本地视频和网络视频。 LinearProgressIndicator:线性进度条 DropdownMenu:实现下拉菜单 PopupMenu:弹出菜单 LazyColumn:垂直滚动列表 LazyRow:水平滚动列表 LazyVerticalGrid:垂直滚动网格 LazyHorizontalGrid:水平滚动网格 Pager:分页控件 Surface:用于创建表面,可以用来绘制自定义的UI元素。 SwipeRefresh:用于创建下拉刷新的控件。 Accompanist:提供了许多有用的Compose控件,例如各种加载占位符、图片缩放控件、滑动刷新控件等等。 Compose Charts:提供了各种绘图控件,包括折线图、柱状图、饼状图等等。 Compose Navigator:提供了一种新的导航方式,通过声明式路由和导航来管理不同屏幕之间的转换。 Compose DataTable:提供了数据表格控件,用于展示数据的表格。 Compose Countdown Timer:提供了倒计时控件。 Compose Material Dialogs:提供了Material Design风格的对话框控件。 Compose Timeline:提供了时间线控件。 Compose Dropdown Menu:提供了下拉菜单控件。 BottomAppBar:用于底部应用程序栏。 DatePicker:用于选择日期。 BottomAppBar: 底部应用栏 BottomDrawer: 底部抽屉 TopAppBar: 顶部应用栏 ViewPager: 用于滑动切换多个页面的控件

3.基本用法

所有的组件函数都是由 方法参数 + 结尾block块来组合的

这里有个统一的概念,方法参数中可以决定当前控件的大小,颜色,样式等,也就是之前在xml中写的属性样式大部分操作可以通过Modifier来完成,这个类会有构建各种,包含但不限于(宽度,高度,描边,圆角)等等特殊的像设置图片资源之类的才有专门的形参指令,例如Image的 painter需要指向一个资源描述符

代码示例如下

Image(

painter = painterResource(id = R.drawable.ic_launcher_background),//通过painterResource函数指定资源图

contentDescription = "头像",//指定描述文案

modifier = Modifier //通过Modifier指定控件大小,裁切类型,描边类型

.size(40.dp)

.clip(CircleShape)

.border(1.dp, Color.Blue, CircleShape)

)

4.通过Compose UI简单的实现一个登录界面

//Activity onCreate中调用setContent方法,这里的initView是一个Compose函数

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContent {

loginViewModel = ViewModelProvider(this)[LoginViewModel::class.java]

initView()

}

}

通过@Composable注解函数会被认定为compose相关视图,对应的内部才能调用compose的函数,以及预览等,这一块是有编码校验的

@OptIn(ExperimentalUnitApi::class)

@Preview

@Composable

fun initView() {

Column(

modifier = Modifier

.background(color = colorResource(id = R.color.bg_white))

.fillMaxWidth()

.fillMaxHeight(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally

) {

LogIcon()

VSpacer(30)

Text(text = "Welcome to example", fontWeight = FontWeight.Bold, fontSize = TextUnit(23f, TextUnitType.Sp))

VSpacer(30)

InputEdit(hint = "please input your userName")

VSpacer(5)

InputEdit(hint = "please input your password", true)

VSpacer(30)

Button(onClick = { Toast.makeText(this@LoginActivity, "测试", Toast.LENGTH_SHORT).show() }) {

Text(text = "Login")

}

}

}

以上定义的initView函数就是添加@Composable注解,还有@Preview,添加了@Preview注解之后,会在编码框右边看到当前代码的预览图像.如下图所示这样,左边是代码,右边就是预览图,整体还是比较精准的.不过这里没办法选择设备类型,也就是预览图像没有发现哪里可以选择预览的分辨率.能够看个大概

@Composable

fun LogIcon() {

Image(

painter = painterResource(id = R.drawable.ic_launcher_background),

contentDescription = "图标",

modifier = Modifier

.width(50.dp)

.height(50.dp)

.clip(CircleShape)

.border(2.dp, colorResource(id = android.R.color.black), CircleShape)

)

}

LogIcon就是顶部的图标,指定了图标资源,描边,圆形裁切.宽度和高度.

@Composable

fun VSpacer(height: Int) {

Spacer(

modifier = Modifier

.fillMaxWidth()

.height(height.dp)

)

}

因为这里的分割线都是横向的,所以单独抽了一个函数,通过传入的高度决定是多高.不在外面重复编写. 这里就能看出对比xml的优势了.如果是xml中想要复用的话,是很难做到这种程度的,得挨着复制.

Text(text = "Welcome to example", fontWeight = FontWeight.Bold, fontSize = TextUnit(23f, TextUnitType.Sp))

顶部的欢迎文案 所有的控件都通过Column来管理,顶部有介绍这个类似于垂直布局的LinearLayout

@Composable

fun InputEdit(hint: String, isPassword: Boolean = false) {

val textState = remember {

mutableStateOf("")

}

if (!isPassword) {

loginViewModel.saveName.observeForever { }

loginViewModel.saveName.observe(this) {

textState.value = it

}

}

TextField(visualTransformation = if (isPassword) PasswordVisualTransformation() else VisualTransformation.None,

value = textState.value,

onValueChange = {

textState.value = it

if (!isPassword) {

loginViewModel.saveName.value = it

}

},

modifier = Modifier

.width(260.dp)

.height(56.dp),

label = { Text(if (isPassword) "Password" else "UserName") },

keyboardOptions = KeyboardOptions.Default.copy(

imeAction = ImeAction.Done, keyboardType = KeyboardType.Password

),

placeholder = { Text(text = hint, Modifier.alpha(0.5f)) })

}

以上是对应的用户账号和用户密码的输入框,定义了两个形参hint和isPassword 用来动态的显示提示文案和是否是密码输入框 因为这个控件是复用的.对比xml如果要这样做的话,要不就是需要抽取style公共主题,要不就是通过include的方式,然后代码中动态设置. 但是声明式就是这样,关注你的展示结果,而不关注实现过程.可以一个函数搞定这些配置化.这里东西稍微多一些.分开描述一下

TextField输入框,不过源码有打上ExperimentalMaterial3Api注解,后期可能会做出调整

形参 visualTransformation 对应的是输入框内容的显示模式,因为密码的话应该要显示***这种样式需要指定为PasswordVisualTransformation()形参value 对应输入框内容,这里比如要有接受参数,否则输入框会无法键入内容.所以上面创建了一个mutableStateOf对象来接受数据,这个mutableStateOf是会动态更新的,也就是修改state的值,会自动刷新到ui上面去.形参onValueChange 内容变更的时候就会触发,这里会简单演示了一下和ViewModle配合使用的场景,把这个数据设置到livedata中去,这样切换白天黑夜就依然会保存值,但是需要在上面obser监听.然后就是通用的Modier指定宽高.形参label是指定顶部有一个类似于常驻的提示文本.这个不同于hint,是不会因为输入内容而消失的.形参keyboardOptions 指定键盘的输入类型形参placeholder 指定在没有内容的时候显示什么,这里就是一个Text显示hint的文案.并且透明度为0.5f因为没有直接指定hit的参数…

Button(onClick = { Toast.makeText(this@LoginActivity, "测试", Toast.LENGTH_SHORT).show() }) {

Text(text = "Login")

}

最后剩下一个登录按钮,通过Button就可以了,传入onClick blcok参数.后面的block体重,传入Text用于显示文本

class LoginViewModel : ViewModel() {

val saveName = MutableLiveData()

}

最后贴一下ViewModel的代码 Activity完整代码如下

@OptIn(ExperimentalMaterial3Api::class)

class LoginActivity : ComponentActivity() {

private lateinit var loginViewModel: LoginViewModel

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContent {

loginViewModel = ViewModelProvider(this)[LoginViewModel::class.java]

initView()

}

}

@OptIn(ExperimentalUnitApi::class)

@Preview

@Composable

fun initView() {

Column(

modifier = Modifier

.background(color = colorResource(id = R.color.bg_white))

.fillMaxWidth()

.fillMaxHeight(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally

) {

LogIcon()

VSpacer(30)

Text(text = "Welcome to example", fontWeight = FontWeight.Bold, fontSize = TextUnit(23f, TextUnitType.Sp))

VSpacer(30)

InputEdit(hint = "please input your userName")

VSpacer(5)

InputEdit(hint = "please input your password", true)

VSpacer(30)

Button(onClick = { Toast.makeText(this@LoginActivity, "测试", Toast.LENGTH_SHORT).show() }) {

Text(text = "Login")

}

}

}

@Composable

fun LogIcon() {

Image(

painter = painterResource(id = R.drawable.ic_launcher_background),

contentDescription = "图标",

modifier = Modifier

.width(50.dp)

.height(50.dp)

.clip(CircleShape)

.border(2.dp, colorResource(id = android.R.color.black), CircleShape)

)

}

@Composable

fun VSpacer(height: Int) {

Spacer(

modifier = Modifier

.fillMaxWidth()

.height(height.dp)

)

}

@Composable

fun InputEdit(hint: String, isPassword: Boolean = false) {

val textState = remember {

mutableStateOf("")

}

if (!isPassword) {

loginViewModel.saveName.observeForever { }

loginViewModel.saveName.observe(this) {

textState.value = it

}

}

TextField(visualTransformation = if (isPassword) PasswordVisualTransformation() else VisualTransformation.None,

value = textState.value,

onValueChange = {

textState.value = it

if (!isPassword) {

loginViewModel.saveName.value = it

}

},

modifier = Modifier

.width(260.dp)

.height(56.dp),

label = { Text(if (isPassword) "Password" else "UserName") },

keyboardOptions = KeyboardOptions.Default.copy(

imeAction = ImeAction.Done, keyboardType = KeyboardType.Password

),

placeholder = { Text(text = hint, Modifier.alpha(0.5f)) })

}

}

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: