文章目录
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)) })
}
}
精彩内容
发表评论