您现在的位置是:首页 >学无止境 >Jetpack Compose UI预览网站首页学无止境
Jetpack Compose UI预览
Android开发 Jetpack_Compose_2 UI预览@Preview
前言
在学习jetpack compose如何编写ui之前,我认为还是应该先了解与Android studio配合的UI预览@Preview。 这样就可以立刻看到UI效果,从而方便后续学习验证代码。
所需依赖
implementation "androidx.compose.ui:ui:1.2.1" //ui基础库 - 重要
implementation "androidx.compose.ui:ui-tooling:1.2.1" //ui工具基础库 - 重要
implementation "androidx.compose.foundation:foundation:1.2.1" //基础库 - 重要
implementation "androidx.activity:activity-compose:1.5.1" //配合activity使用的基础库 - 重要
implementation "androidx.compose.ui:ui-tooling-preview:1.2.1" //在Android studio里预览ui的基础库
简单的初步了解预览
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
//将MyText添加到Activity里
MyText()
}
}
@Preview //在方法上增加@Preview 表明我们需要预览这个方法里的View
@Composable //在方法上增加@Composable 表面这是compose的ui方法,增加后才能在方法里添加compose的View
fun MyText(){
Text(text = "Hello World", color = Color.White)
}
}
Android studio中的预览
根据条件选择在Android Studio预览效果与设备上运行的UI效果
下面的代码中判断的关键是LocalInspectionMode.current。 用来区分是在Android Studio上还是在设备上的效果。在项目中的实际意义是填充一些模拟数据方便查看预览ui效果。 比如给Image设置一张占位图或者给列表填充一些模拟数据。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyText()
}
}
@Preview
@Composable
fun MyText(){
if (LocalInspectionMode.current){
//在Android studio中显示预览的ui
Text(text = "android studio preview", color = Color.Red)
} else {
//实际在设备上显示的ui
Text(text = "device run ui", color = Color.Red)
}
}
}
在Android studio上的效果图:
在设备上的效果图:
快速部署预览
Preview支持快速部署预览,这个功能解决的痛点是,在我们需要预览一些UI层级很深的页面时,每次都要去在设备上一个一个点击跳转到目标页面查看UI效果。这个特别费时费力,现在只需要按照下图点击就可立即在设备上显示当前页面。
这功能可以说是半个热加载...
可能出现的报错
这可能应该是Android Studio的Bug,现在每次使用这个功能都需要build一下preview,在点击
build编译一下然后在点击上面的设备图标就行了。
一个方便使用的细节
你在某个activity里使用过一次快速部署预览功能后,在如下图中会自动生成一份预览文件选项。后续只要选择某个compose 方法的预览,点击运行就可以在设备上快速部署预览。
另外请注意!你需要及时清理掉一些失效的预览,这样可以防止创建新的并且相同名称的预览后,在尝试运行时却提示找不到文件,如下图所示:
互动模式
借助互动模式,您可以采用类似于在设备上互动的方式与预览互动。互动模式被隔离在沙盒环境中(与其他预览隔离),在该模式下,您可以在预览中点击元素并输入用户输入;预览甚至还可以播放动画。通过使用这种模式,您可以快速测试可组合项的不同状态和手势,例如勾选或清空复选框。
预览互动模式直接在 Android Studio 中运行,并未运行模拟器,因此存在一些限制:
- 无法访问网络
- 无法访问文件
具体开启操作与体验如下图片:
@Preview的属性讲解
name
添加name的意义是,可以在预览页面增加名称区分。在有多个Compose方法需要预览的时候可以快速区分。另外预览@Preview 可以多个组合一起同时对一个Compose方法进行预览(比如同时创建平板设备与手机设备的显示效果,或者是不同文字缩放比例的显示效果),从而区分对应配置的预览。组合预览会在下面详细讲解,这里只是引用强调name的意义。最后建议一定需要给每一个@Preview添加name。
如图参考:
group
group的作用是将若干Compose的方法进行分组,分组后可以选择只显示某个组别的View。这点google的官方文档真是啥都没说让人无语。
@Preview(name = "文本1", group = "文本组1")
@Composable
fun MyText1() {
Text(text = "文本1", color = Color.White)
}
@Preview(name = "文本2", group = "文本组2")
@Composable
fun MyText2() {
Text(text = "文本2", color = Color.Yellow)
}
@Preview(name = "文本3", group = "文本组2")
@Composable
fun MyText3() {
Text(text = "文本3", color = Color.Red)
}
效果如下动图:
widthDp 与 heightDp
Android studio预览ui上设置预览的容器大小
@Preview(name = "文本1", widthDp = 50, heightDp = 100)
@Composable
fun MyText1() {
Text(text = "文本1", color = Color.White)
}
@Preview(name = "文本2", widthDp = 100, heightDp = 50)
@Composable
fun MyText2() {
Text(text = "文本2", color = Color.White)
}
效果图:
locale
Android studio预览ui上设置语言-地区显示预览
@Preview(name = "文本1", locale = "en")
@Composable
fun MyText1() {
Text(text = stringResource(id = R.string.hello_world), color = Color.White)
}
@Preview(name = "文本2", locale = "zh")
@Composable
fun MyText2() {
Text(text = stringResource(id = R.string.hello_world), color = Color.White)
}
效果图:
fontScale
Android studio预览ui上设置文字缩放比例
@Preview(name = "文本1", fontScale = 0.8f)
@Composable
fun MyText1() {
Text(text = stringResource(id = R.string.hello_world), color = Color.White)
}
@Preview(name = "文本2", fontScale = 1.5f)
@Composable
fun MyText2() {
Text(text = stringResource(id = R.string.hello_world), color = Color.White)
}
效果图:
showSystemUi
Android studio预览ui上显示设备的状态栏和操作栏
@Preview(name = "文本1", showSystemUi = true)
@Composable
fun MyText1() {
Text(text = stringResource(id = R.string.hello_world), color = Color.Black)
}
效果图:
backgroundColor 与 showBackground
backgroundColor 通常与 showBackground 组合在一起使用,一个是设置Android studio预览ui背景颜色,一个是开启or关闭背景显示
@Preview(name = "文本1", showBackground = true, backgroundColor = 0xFFF44336)
@Composable
fun MyText1() {
Color(0xFFF44336)
Text(text = stringResource(id = R.string.hello_world), color = Color.White)
}
效果动图:
uiMode
设置Android studio预览ui模式,比如夜间模式
/**
* UI_MODE_TYPE_UNDEFINED 未定义
* UI_MODE_TYPE_NORMAL 正常模式
* UI_MODE_TYPE_DESK 工作模式
* UI_MODE_TYPE_CAR, 汽车模式
* UI_MODE_TYPE_TELEVISION, 电视设备
* UI_MODE_TYPE_APPLIANCE, 便携设备
* UI_MODE_TYPE_WATCH, 手表设备
* UI_MODE_TYPE_VR_HEADSET. VR设备
* UI_MODE_NIGHT_MASK. 夜间模式
* UI_MODE_NIGHT_UNDEFINED. 夜间未定义
* UI_MODE_NIGHT_NO. 白天模式
* UI_MODE_NIGHT_YES. 黑夜模式
*/
@Preview(name = "文本1", uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun MyText1() {
Text(text = stringResource(id = R.string.hello_world),
fontSize = 24.sp,
color = Color.Gray,
modifier = Modifier.background(Color.Black))
}
device
指定在Android studio中预览的设备样式
@Preview(name = "文本1", device = Devices.WEAR_OS_LARGE_ROUND)
@Composable
fun MyText1() {
Text(
text = stringResource(id = R.string.hello_world),
fontSize = 24.sp,
color = Color.Gray,
modifier = Modifier.background(Color.Black)
)
}
其他device参数
const val DEFAULT = ""
const val NEXUS_7 = "id:Nexus 7"
const val NEXUS_7_2013 = "id:Nexus 7 2013"
const val NEXUS_5 = "id:Nexus 5"
const val NEXUS_6 = "id:Nexus 6"
const val NEXUS_9 = "id:Nexus 9"
const val NEXUS_10 = "name:Nexus 10"
const val NEXUS_5X = "id:Nexus 5X"
const val NEXUS_6P = "id:Nexus 6P"
const val PIXEL_C = "id:pixel_c"
const val PIXEL = "id:pixel"
const val PIXEL_XL = "id:pixel_xl"
const val PIXEL_2 = "id:pixel_2"
const val PIXEL_2_XL = "id:pixel_2_xl"
const val PIXEL_3 = "id:pixel_3"
const val PIXEL_3_XL = "id:pixel_3_xl"
const val PIXEL_3A = "id:pixel_3a"
const val PIXEL_3A_XL = "id:pixel_3a_xl"
const val PIXEL_4 = "id:pixel_4"
const val PIXEL_4_XL = "id:pixel_4_xl"
const val AUTOMOTIVE_1024p = "id:automotive_1024p_landscape"
const val WEAR_OS_LARGE_ROUND = "id:wearos_large_round"
const val WEAR_OS_SMALL_ROUND = "id:wearos_small_round"
const val WEAR_OS_SQUARE = "id:wearos_square"
const val WEAR_OS_RECT = "id:wearos_rect"
// Reference devices
const val PHONE = "spec:id=reference_phone,shape=Normal,width=411,height=891,unit=dp,dpi=420"
const val FOLDABLE = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480"
const val TABLET = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=420"
const val DESKTOP = "spec:shape=Normal,width=1920,height=1080,unit=dp,dpi=420"
Multipreview 自定义预览注解
注意:此功能从 Android Studio Dolphin 和 Jetpack Compose 1.2.0-beta01 开始提供
简单的说,这个功能其实是多个@Preview 自定义组合在一起,这样你可以配置属于你需求的@Preview 。并且可以选择满足在不同条件下的ui预览。
class DeploymentActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyText1()
}
}
@LandscapeAndPortraitPreviews
@Composable
fun MyText1() {
Text(
text = stringResource(id = R.string.hello_world),
fontSize = 24.sp,
color = Color.White,
modifier = Modifier.background(Color.Black)
)
}
}
@Preview(
name = "横屏",
group = "横屏组",
fontScale = 0.5f,
widthDp = 1280,
heightDp = 720
)
@Preview(
name = "竖屏",
group = "竖屏组",
fontScale = 1.5f,
widthDp = 720,
heightDp = 1280
)
annotation class LandscapeAndPortraitPreviews
效果图:
@PreviewParameter 带参数预览
在正常开发中,我们经常会需要给Composable方法传入数据参数(注意,这里的参数是指数据类型,如果你传入Composable的一些参数例如Modifier则没问题)。但是我们添加预览后会出现如下报错提示:
这里需要给name这个String参数添加@PreviewParameter注释。
首先我们需要创建预览数据提供PreviewParameterProvider,这里请注意,这里创建的类不能是内部类,否则可能会出现无法预览的问题。
class NameProvider : PreviewParameterProvider<String> {
override val values: Sequence<String> get() = listOf("苹果","香蕉","西瓜","葡萄").asSequence()
}
把PreviewParameterProvider添加到Composable方法里
@Preview(device = Devices.AUTOMOTIVE_1024p)
@Composable
fun TextDemo(@PreviewParameter(NameProvider::class, 1) name: String) {
Text(text = name)
}
预览效果图:
@PreviewParameter的参数limit
在上面的例子可以看到,在传入了 NameProvider 这个类后,还传入了一个Int值。 这个值与我们实现的NameProvider 的数据是集合有关。修改limit会自动生产集合里其他数据的预览,参考动图如下:
@PreviewParameter 集合数据预览
举例一个更复杂一点点的使用情况
PreviewParameterProvider数据代码:
class ImageProvider : PreviewParameterProvider<SnapshotStateList<Int>> {
override val values: Sequence<SnapshotStateList<Int>>
get() = listOf(
mutableStateListOf(
R.mipmap.copybook_1,
R.mipmap.copybook_1,
R.mipmap.copybook_1
)
).asSequence()
}
Composable方法添加预览数据
@Preview(device = Devices.AUTOMOTIVE_1024p)
@Composable
private fun ImageList(@PreviewParameter(ImageProvider::class, 1) list: SnapshotStateList<Int>) {
Column {
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 200.dp),
verticalArrangement = Arrangement.spacedBy(20.dp),
horizontalArrangement = Arrangement.spacedBy(20.dp),
contentPadding = PaddingValues(top = 20.dp, start = 20.dp, end = 20.dp)
) {
items(list.size) { index ->
Image(painter = painterResource(list[index]), contentDescription = null)
}
}
}
}
预览效果图:
end.