1.为什么要学?
1.命令式和声明式 UI大战,个人认为命令式UI自定义程度较高,能更深入到性能,内存优化方面,而申明式UI 是现在主流的设计,比如React,React Native,Flutter,Swift UI等等,现在性能也逐渐在变得更好
2.还有一个原因compose 是KMM 是完整跨平台的UI基础
3.声明式UI 个人觉得是非常适合MVVM的设计的,比android databinding 实现的xml 里面绑定vm 更适合,声明式UI一般都是基于状态管理的,只需要处理状态,至于怎么组合,怎么刷新比对 是框架给处理好的,开发不需要关心,所以逻辑稍微简单些
2.前景?
1.RN官方放弃,Flutter 官方宣停,Flutter也是Google ,同样compose 和kmm也是google搞的,说明google 目前是把KMM放在第一梯队的,极大成为后期的主力推荐,现在最新的Android Studio 创建的模版工程就是compose的,而且还支持iOS;
2.我的建立认知是KMM>Flutter>RN;kotlin的的语言优势较大,和Java 无缝通用
hello word
下载最新的Android Studio,(具体是从哪个版本开始没必要深纠,我的版本是Android Studio Giraffe | 2022.3.1)
List列表组建(LazyColum)
class LazyColumnActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
MyLazyList()
}
}
}
@Composable
fun MyLazyList(){
val state= rememberLazyListState();
LazyColumn(state=state){
items(100){
Text(text="item $it")
}
}
}
}
确实比写Adapter,和CollectionViewDelegate简单
Compose函数
"Jetpack Compose 是围绕可组合函数构建的。这些函数可让您以程序化方式定义应用的界面,只需描述应用界面的外观并提供数据依赖项,而不必关注界面的构建过程(初始化元素、将其附加到父项等)。如需创建可组合函数,只需将 @Composable 注解添加到函数名称中即可。" 官话
@Composable
fun MyText(){
Text(text = "00000");
return Text(text = "xfdft");
}
上面这段代码 执行结果显示 两个重叠的文字, 其实这个return 是无效的,内嵌的两个text函数都会执行,@Composable函数的返回值是UNIT
@Composable
fun MyText():Int{
Text(text = "00000FFF");
return 1;
}
这样改造成返回值int 类型 在实际的结果中依旧是展示了这个text 也不报错,这尼玛就有点神奇了?
Kotlin 中间代码(intermediate representation, IR),
这个是kotlin插件,是编译时的,比较深奥,参考
预览函数
基于xml的布局都提供预览,Android layout ios storeboard 等,同样compose 也具备这个特性
@Preview(name = "第一个预览区域")
@Composable
fun preview(){
Text(text="Hello,my name is jack,What's your name");
}
@Preview(name = "第二个预览区域")
@Composable
fun preview2(){
Text(text="停车坐爱枫林晚,窗前明月光");
}
在android studio 的预览区域就会显示出来了,可以支持多个,但是在编辑的时候不是很流畅,官方还有很大的优化空间
Compose 组件清单大全
Text:用于显示文本内容。
Image:用于显示图片。
Button:用于创建按钮。
TextField:用于接收用户输入的文本。
Column:用于垂直排列多个组件。
Row:用于水平排列多个组件。
Box:用于在屏幕上创建一个矩形的区域。
Surface:用于绘制一块可交互的区域。
Card:用于显示一个卡片式的 UI 元素。
Divider:用于在 UI 中添加分隔线。
Spacer:间距组件
例子:结合行列间距来实现简单的列表样式
class LazyColumnActivity2: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
MyLazyList()
}
}
}
@Composable
fun MyLazyList(){
val state= rememberLazyListState();
val items= listOf<Item>(Item("张三","我是中国的"),
Item("李四","我是中国的"),
Item("王武","我是中国的"))
LazyColumn(state=state){
items(items){
MyItem(item = it)
}
}
}
@Composable
@Preview
fun MyItemPreview(){
MyItem(item = Item("张三","我是中国的"))
}
@Composable
fun MyItem(item:Item){
return Row(modifier = Modifier.padding(10.dp)) {
Image(painter = painterResource(id = R.drawable.ic_launcher_background), contentDescription ="这是头显",
modifier = Modifier
.size(40.dp)
.clip(CircleShape))
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(text = item.name);
Spacer(modifier = Modifier.height(8.dp))
Text(text = item.desc);
}
}
}
class Item(val name:String,val desc:String){
}
}
例子:自定义线性布局cloumn
/**
* @ProjectName: Jetpack_Compose_Study
* @Package: com.xxf.jetpack.compose.study.ui.theme
* @ClassName: MyColumnActivity
* @Description:
* @Author: xuanyouwu@163.com 17611639080
* @Date: 2023/9/4 10:25
*/
class MyColumnActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Jetpack_Compose_StudyTheme {
MyColumnWidget(modifier = Modifier
.padding(10.dp)
.background(Color.Yellow)) {
Text("第一行",color = Color.Black)
Text("第二行",color= Color.Red)
Text("第三行",color= Color.Green)
Text("第四行",color= Color.Blue)
}
}
}
}
@Composable
fun MyColumnWidget(modifier: Modifier=Modifier,
content:@Composable ()->Unit){
Layout(modifier=modifier,content=content){ measurables, constraints->
//测量元素
val placeables = measurables.map {
it.measure(constraints);
}
//布局
var yPostion=0;
layout(constraints.maxWidth,constraints.maxHeight) {
placeables.forEach {
it.placeRelative(x=0,y=yPostion);
yPostion+=it.height;
}
}
}
}
}
这个很像android 自定义组件的步骤,measure->layout
例子:用ConstraintLayout来实现相对布局
需要引入
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
大致步骤
1.使用createRefs()或者createRefFor()为ConstraintLayout中的每个组合项创建引用
2.建立绑定关系,是用modifer 中constrainAs来建立 引用绑定
3.通过约束方法linkto等 可以建立createRefs创建的引用之间的布局依赖
class ConstraintLayoutActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyConstraintLayout()
}
}
@Composable
fun MyConstraintLayout(){
ConstraintLayout {
//用createRefs 创建组件的引用
//用Modifier.constrainAs(xxx)进行连接赋值
val (button,text)=createRefs();
Button(onClick = { }, modifier = Modifier.constrainAs(button){
this.top.linkTo(parent.top, margin = 10.dp);
}) {
Text(text = "Button")
}
Text(text = "文本", modifier = Modifier.constrainAs(text){
this.top.linkTo(button.bottom, margin = 10.dp);
})
}
}
}
createRefs是强引用关系,我们可以通过类似android:id 这样的方式解耦
createRefFor(id) 参数id类似于android:id 取id的方法
如下:ConstraintLayout参数形式指定约束,实现横竖屏间距不等问题
@Composable
fun DecoupledConstraintLayout(){
BoxWithConstraints {
//横竖屏设置不一样的间距
val constraints=if(this.maxWidth<this.maxHeight){
decoupledConstraints(10.dp)
}else{
decoupledConstraints(60.dp)
}
ConstraintLayout(constraints) {
Button(onClick = { }, modifier = Modifier.layoutId("button")) {
Text(text = "Button")
}
Text(text = "文本", modifier = Modifier.layoutId("text"))
}
}
}
private fun decoupledConstraints(margin:Dp):ConstraintSet{
return ConstraintSet{
val button=createRefFor("button");
val text=createRefFor("text");
constrain(button){
this.top.linkTo(this.parent.top,margin=margin);
}
constrain(text){
this.top.linkTo(button.bottom,margin);
}
}
}
状态管理
状态管理的常见三个函数,remember、mutableStateOf、rememberSaveable的区别
mutableStateOf:标识这个data是有状态的,如果状态发生改变,所有引用这个状态的view都将重绘;
remember:存储值,当界面重新绘制,会读取之前的值,相当于在mutableStateOf之上包了一层,把这个变量存储脱离函数,那么即使这个函数再次执行这个值并不会变成初始值,但是如果页面切换就会失效
rememberSaveable:在remember上保证了可以在页面切换的过程中保存数据,rememberSaveable==remember+onSaveInstaneState+onCreate中的read savedInstanceState,当configChanges的时候,将remember的值写入bundle中,然后重新构建activity的时候,从bundle中读取数据
class StateActivity: ComponentActivity() {
val vm:MyViewModel by viewModels<MyViewModel>();
val s= androidx.compose.runtime.mutableStateOf("");
@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Column {
//对于输入框如果不记录 就会一直输入不了,所以采取提升状态 方式将mutableStateOf升级为activity的成员
test2(s.value) {
s.value = it;
};
//提升状态采用remember函数记录
test();
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun test(){
val (text,setText)= remember {
mutableStateOf("");
}
Row {
TextField(value =text , onValueChange ={
setText(it)
},
modifier = Modifier
.background(Color.Green))
Button(onClick = {
setText("");
}, enabled = text.isNotBlank()) {
Text(text = "搜索")
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun test2(value:String,onTextChange:(String)->Unit){
Row {
TextField(value =value , onValueChange =onTextChange,
modifier = Modifier
.background(Color.Green))
Button(onClick = {
onTextChange("");
}, enabled = value.isNotBlank()) {
Text(text = "搜索")
}
}
}
class MyViewModel: ViewModel() {
val state= MutableLiveData<Boolean>(true);
}
}
下面将对博客进行分篇,点击下面的链接文章来源:https://www.toymoban.com/news/detail-651973.html
Text组件文章来源地址https://www.toymoban.com/news/detail-651973.html
到了这里,关于JetPack Compose 学习笔记(持续整理中...)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!