Jepack Compose声明式ui框架
前言
- 2020的Google/IO大会,亮相了一个全新的 Android 原生 UI 开发框架-Jetpack Compose
- 与苹果的SwiftIUI一样,Jetpack Compose是一个声明式的UI框架,随着了今年安卓和苹果两大移动平台相继推出自己的UI开发框架Jetpack Compose 和SwiftIUI,标志着移动操作系统正式全面拥抱声明式 UI 开发模式
- 这时候就有同学问了,何为声明式UI?
- 声明式UI的意思就是描述你想要一个什么样的UI界面, 状态变化时,界面按照先前描述的重写“渲染”即可得到状态绝对正确的界面。
- 它不像命令一样,告诉程序一步一步该干什么,维护各种状态。如果想要了解的同学,可以详细可以查看这篇专栏 从 SwiftUI 谈声明式 UI 与类型系统
- 就简单说到这,下面让我们走进Jetpack Compose的世界,体验它的美好
JetPack Compose简单介绍
- Jetpack Compose 是一个用于构建原生Android UI 的现代化工具包,它基于声明式的编程模型,因此你可以简单地描述UI的外观,而Compose则负责其余的工作-当状态发生改变时,你的UI将自动更新。
- 由于Compose基于Kotlin构建,因此可以与Java编程语言完全互操作,并且可以直接访问所有Android和Jetpack API。它与现有的UI工具包也是完全兼容的,因此你可以混合原来的View和现在新的View,并且从一开始就使用Material和动画进行设计。
简单环境配置
以下是我在Android Sutdio4.1上进行编写demo,可以直接去Android Developers官网下载最新版本
- 创建一个新的kotlin project,以下是我的build.gradle文件
defaultConfig {
applicationId "com.example.jetpackcomposedemo"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
ps: 需要注意的是app目录下的支持的最低版本是21或者以上,否则使用jetpack compose会报错,详细可查看官方回答
- 使用Kotlin-Gradle插件 需要根目录下的build.gradle添加如下代码:
buildscript {
ext.kotlin_version = "1.4.21"
repositories {
google()
jcenter()
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
}
dependencies {
classpath "com.android.tools.build:gradle:4.1.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
}
}
- 加入Jetpack Compose的依赖
- dev02 0.1.0先行版
implementation 'androidx.ui:ui-tooling:0.1.0-dev02'
implementation 'androidx.ui:ui-layout:0.1.0-dev02'
implementation 'androidx.ui:ui-material:0.1.0-dev02'
- 目前使用1.0.0-alpha10版本
implementation 'androidx.compose.ui:ui:1.0.0-alpha10'
// Tooling support (Previews, etc.)
implementation 'androidx.compose.ui:ui-tooling:1.0.0-alpha10'
// Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
implementation 'androidx.compose.foundation:foundation:1.0.0-alpha10'
// Material Design
implementation 'androidx.compose.material:material:1.0.0-alpha10'
// Material design icons
implementation 'androidx.compose.material:material-icons-core:1.0.0-alpha10'
implementation 'androidx.compose.material:material-icons-extended:1.0.0-alpha10'
// Integration with observables
implementation 'androidx.compose.runtime:runtime-livedata:1.0.0-alpha10'
implementation 'androidx.compose.runtime:runtime-rxjava2:1.0.0-alpha10'
// UI Tests
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.0.0-alpha10'
- 至此,Jetpack Compose的准备工具就到此了,现在我们可以创建一个Hello world项目进行体验一下
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//初步使用JetPack进行声明式ui编程
setContent {
MaterialTheme {
greeting("World")
}
}
}
@Composable
private fun greeting(str: String) {
Text(text = "Hello $str!")
}
}
- 这里定义了一个Compose函数打印Text
看看Jetpack的布局
- 在Compose中ui布局是分层级的,元素包含在其他元素中。
- 在Jetpack Compose中,你可以通过从其他composable函数中调composable函数来构建UI层次结构。
- 垂直添加多个text
- 相对于xml是使用LinearLayout中的orientation:vertical可以实现垂直结构,在jetpack compose中,我们就需要使用到Column函数
- 写过flutter的同学看起来是不是很眼熟?是的,跟flutter里面的Column Widget名字和功能完全一样,甚至连他们的属性都一摸一样。
@Composable
fun NewsStory() {
Column {
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
- 添加一些样式(官方)
- 以上是beta02版本的jetpack compose的写法
@Composable
fun newsStory() {
Column(
crossAxisSize = LayoutSize.Expand,
modifier = Spacing(16.dp)
) {
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
- crossAxisSize: 指定Column组件(注:Compose中,所有的组件都是composable函数,文中的组件都是指代composable函数)在水平方向的大小,设置crossAxisSize为LayoutSize.Expand即表示Column宽度应为其父组件允许的最大宽度,相当于传统布局中的match_parant ,还有一个值为LayoutSize.Wrap,看名字就知道,包裹内容,相当于传统布局中的wrap_content。
- modifier:使你可以进行其他格式更改。在这种情况下,我们将应用一个Spacing修改器,该设置将Cloumn与周围的视图产生间距。
- 以下是1.0.0版本的jetpack compose的写法
@Composable
fun NewsStory() {
Column(
modifier = Modifier.padding(16.dp)
) {
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
- 添加一张图片
@Composable
private fun addImage() {
val image = +imageResource(R.mipmap.header)
// 放在容器中,设置大小
Container(expanded = true, height = 180.dp) {
//显示图片
DrawImage(image)
}
// 添加垂直方向间距20dp
HeightSpacer(height = 20.dp)
}
- expanded : 指定Container的大小,默认是false(Container的大小是子组件的大小,相当于wrap_content),如果将它设置为true,就指定Container的大小为父控件所允许的最大size, 相当于match_parent。
- height : 设置Container容器的高度,height属性的优先级高于expanded,因此会覆盖expanded,如上面的例子,设置height为180dp,也就是容器宽为父控件宽度,高为180dp
简单使用Material Design设计
- 添加shape的样式
setContent {
val image = +imageResource(R.mipmap.header)
Column(
crossAxisSize = LayoutSize.Expand,
modifier = Spacing(16.dp)
) {
//放在容器中,设置大小
Container(expanded = true,height = 180.dp) {
Clip(shape = RoundedCornerShape(10.dp)) {
//显示图片
DrawImage(image)
}
}
}
- 这里给图片加入圆角10dp
- 设置下文字样式
Text("Hello World")
Text("我来体验下JetPack Compose,JetPack Compose的复用性很强,可以抽取很多公共组件",
maxLines = 2,
overflow = TextOverflow.Ellipsis,
style = +themeTextStyle { h5 }
)
- 设置了maxLines 和overflow 之后,超出部分就截断处理了,不会影响到整个布局样式。
- 设置按钮
drawerButton(
R.drawable.ic_shape_button.also { },
label = "Home",
isSelected = true
) {
}
- 完整demo代码如下所示
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//初步使用JetPack进行声明式ui编程
setContent {
val image = +imageResource(R.mipmap.header)
Column(
crossAxisSize = LayoutSize.Expand,
modifier = Spacing(16.dp)
) {
//放在容器中,设置大小
Container(expanded = true, height = 180.dp) {
Clip(shape = RoundedCornerShape(10.dp)) {
//显示图片
DrawImage(image)
}
}
//添加垂直方向间距为20dp
HeightSpacer(20.dp)
Text("Hello World")
Text(
"我来体验下JetPack Compose,JetPack Compose的复用性很强,可以抽取很多公共组件",
maxLines = 2,
overflow = TextOverflow.Ellipsis
// style = (+themeTextStyle { h2 }).withOpacity(0.1f)
)
HeightSpacer(20.dp)
drawerButton(
R.drawable.ic_shape_button.also { },
label = "Home",
isSelected = true
) {
}
}
}
}
@Preview
@Composable
private fun newsTory(string: String) {
Text("Hello $string")
}
/**
* 添加一张图片
*/
@Composable
private fun addImage() {
val image = +imageResource(R.mipmap.header)
// 放在容器中,设置大小
Container(expanded = true, height = 180.dp) {
//显示图片
DrawImage(image)
}
// 添加垂直方向间距20dp
HeightSpacer(height = 20.dp)
}
@Composable
private fun drawerButton(
@DrawableRes icon: Int,
label: String,
isSelected: Boolean,
action: () -> Unit
) {
val textIconColor = if (isSelected) {
+themeColor { primary }
} else {
(+themeColor { onSurface }).copy(alpha = 0.6f)
}
val backgroundColor = if (isSelected) {
(+themeColor { primary }).copy(alpha = 0.12f)
} else {
+themeColor { surface }
}
Padding(left = 8.dp, top = 8.dp, right = 8.dp) {
Surface(
color = backgroundColor,
shape = RoundedCornerShape(4.dp)
) {
Button(onClick = action, style = TextButtonStyle()) {
Row(
mainAxisSize = LayoutSize.Expand,
crossAxisAlignment = CrossAxisAlignment.Center
) {
WidthSpacer(16.dp)
Text(
text = label,
style = (+themeTextStyle { body2 }).copy(
color = textIconColor
)
)
}
}
}
}
}
}
总结
- 同学我尝试体验了一下JetPack Compose,目前还存在很多问题,还不能现在将其用于商业项目中,但是这并不能妨碍我们学习和体验它,声明式 UI 框架近年来飞速发展,React 为声明式 UI 奠定了坚实基础并。
- Flutter 的发布将声明式 UI 的思想成功带到移动端开发领域,Apple和Google 分别先后发布了自己的声明式UI框架SwiftUI 和 Jetpack Compose , 以后,原生UI布局,声明式可能将会是主流。
- 具体效果可查看Android官方文档JetPack Compose教程
- 欢迎各位同学大佬们一起学习讨论