android 约束布局容器ConstraintLayout的初探

2024-05-04 12:38

本文主要是介绍android 约束布局容器ConstraintLayout的初探,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

约束布局容器声明

<android.support.constraint.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="qssq666.cn.constraintlayout.MainActivity"></android.support.constraint.ConstraintLayout>

注意

  • 容器里面的控件如果设置了左右约束,将不支持设置match_parent 改用0dp代替
  • 代替属性Important: MATCH_PARENT is not supported for widgets contained in a ConstraintLayout, though similar behavior can be defined by using MATCH_CONSTRAINT with the corresponding left/right or top/bottom constraints being set to “parent”.`
  • Guideline控件在容器里面可以设置wrap_content

容器里面的控件位置摆放介绍

左上对齐 让容器里面的某控件相对于约束布局容器
实际上做上不需要加上属性默认就是,哈哈哈

app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"

f和它左边对齐 比如parent是整个屏幕,就需要设置这个,如果设置的是lefttoright parent那么肯定是看不到了因为parent是整个屏幕。

layout_constraintLeft_toLeftOf

右下对齐 前提是别再设置toLeftOf和 toTopOf了

app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintRight_toRightOf="parent"

居中对齐 所有属性 上下左右 都使用上即可.

app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"

手动操作实现上面效果,无图无真相..文字介绍太枯燥了,
选择控件将弹出4个圆圈 选择每一个圆圈往它那方靠近屏幕的方向拉去,如果没拉到屏幕变上 开发工具是不会产生控件的偏移动画的,而且松手又回来了, 那么全部拉好之后就是上面的代码效果,上下左右居中。

下一步学习 让一个控件和之前那个居中的控件的右边对齐

<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="我是居中的!"android:id="@+id/center_view"app:layout_constraintRight_toRightOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintTop_toTopOf="parent"/><TextViewandroid:text="我不跟随父亲我长度够长,我右边始终和中间view右边对齐"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintRight_toRightOf="@+id/center_view"/>//看到的效果就是  第二个控件在顶部,但是始终右边和中间的右边对齐。
手动拉如何产生这个效果呢?选择第二个控件的右边方向的圆圈连接到中间view的右边的圆圈。

找规律

app:layout_constraintRight_toRightOf 也就是 我的右边和哪个空间的右边对齐呢?如果填写为parent那就是和父容器的右边对齐,因此这里懂了吧。

仿RelativeLayout的属性用法

@id代表某控件
让当前控件在某控件右边layout_toRightOf=@idlayout_constraintLeft_toRightOf=@id

让当前控件在某控件之下layout_below =@idapp:layout_constraintTop_toBottomOf= =@id手动拖控件方法 就是选择上面的某控件的底部圆圈连接 需要在他下面控件的上边圆圈

让当前控件和某控件底部对齐layout_alignBottom =@idlayout_constraintBottom_toBottomOf=@id

手动拖控件方法 就是选择参考物的某控件的底部圆圈连接和另外一个想和他底部对齐的view底部圆圈进行连接

让当前控件和父控件右边对齐layout_alignParentRight="true"layout_constraintRight_toRightOf="parent"

举一反三,不再多介绍了。

仿LinearLayout权重

<Buttonandroid:id="@+id/btn_0"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="#ff0"android:text="Btn01"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"tools:layout_editor_absoluteX="0dp"tools:layout_editor_absoluteY="0dp" /><Buttonandroid:id="@+id/btn_1"android:layout_width="0dp"android:layout_height="wrap_content"android:background="#f00"android:text="Btn02"app:layout_constraintLeft_toRightOf="@+id/btn_0"app:layout_constraintRight_toRightOf="parent" />

右边占据剩余的宽度。左边宽度就是包裹内容了, 需要右边父容器对齐又需要在左边容器的右边。 有时候只能用代码写,因为鼠标操作的话拦住了。

让空间水平铺满屏幕的属性

android:layout_width="0dp"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"

保持宽高比 16:9

*这里宽度是16高度9 也代表 H,16:9为何英文意思是相反的我就不知道了。

app:layout_constraintDimensionRatio="16:9"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"

和下面这个一样

app:layout_constraintDimensionRatio="H,16:9"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"

如果改成W

app:layout_constraintDimensionRatio="W,16:9"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"

那么高度尺寸比宽度尺寸大。另外上面的left_toleft right_toright 都必须填写,否则就没法做到宽高比了,否则你写死高宽。另外务必把宽度和高度设置成这样android:layout_width="0dp" android:layout_height="0dp" 否则不会生效。
而我们的PercentFrameLayout在26已经不再推荐使用了.如果使用26的buildtool工具会提出现删除线。
那么让我们来怀恋一下百分比布局的16:9

app:layout_aspectRatio="177%"
app:layout_widthPercent="100%"
android:layout_height="0dp"
android:layout_width="match_parent"

多按钮等分权重

  • app:layout_constraintHorizontal_weight="1" 是控制权重比例的不填写此参数的时候权重就是1
  • 每一个控件的左边右边都要约束好,否则宽度还是原来自身的宽度,不会起作用
<Buttonandroid:id="@+id/btn_0"android:layout_width="0dp"android:layout_height="wrap_content"android:background="#f00"android:text="Btn01"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toLeftOf="@id/btn_1" /><Buttonandroid:id="@+id/btn_1"android:layout_width="0dp"android:layout_height="wrap_content"android:background="#0f0"android:text="Btn01"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toRightOf="@id/btn_0"app:layout_constraintRight_toLeftOf="@+id/btn_2" /><Buttonandroid:id="@+id/btn_2"android:layout_width="0dp"android:layout_height="wrap_content"android:background="#00f"android:text="Btn01"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toRightOf="@id/btn_1"app:layout_constraintRight_toRightOf="parent" />

加上margin不受影响

<Buttonandroid:id="@+id/btn_0"android:layout_width="0dp"android:layout_height="wrap_content"android:background="#f00"android:text="Btn01"android:layout_margin="10dp"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toLeftOf="@id/btn_1" /><Buttonandroid:id="@+id/btn_1"android:layout_width="0dp"android:layout_margin="10dp"android:layout_height="wrap_content"android:background="#0f0"android:text="Btn01"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toRightOf="@id/btn_0"app:layout_constraintRight_toLeftOf="@+id/btn_2" /><Buttonandroid:id="@+id/btn_2"android:layout_width="0dp"android:layout_margin="10dp"android:layout_height="wrap_content"android:background="#00f"android:text="Btn01"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toRightOf="@id/btn_1"app:layout_constraintRight_toRightOf="parent" />

写死宽度调试权重样式
app:layout_constraintHorizontal_chainStyle|layout_constraintVertical_chainStyle="spread|spread_inside|packed"

  • spread 必须配合width=0使用
  • spread_inside packed 是必须配合width height不等于0的时候使用
  • spread和不填写一样,因此意义不大
  • spread_inside 和英文意思一样 非写死宽度的剩余宽度分配中,平均分配左右两边 是靠边的,而packed是紧靠在一起,剩余的在整个控件之外,紧靠在一起。
  • 我以为可以做到相交和不相交处的权重等分,结果然并卵,也没啥用哈。
    参考代码
<Buttonandroid:id="@+id/btn_0"android:layout_width="50dp"android:layout_height="wrap_content"android:background="#f00"android:text="Btn01"app:layout_constraintHorizontal_chainStyle="packed"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toLeftOf="@id/btn_1" /><Buttonandroid:id="@+id/btn_1"android:layout_width="50dp"android:layout_height="wrap_content"android:background="#0f0"android:text="Btn01"app:layout_constraintHorizontal_chainStyle="packed"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toRightOf="@id/btn_0"app:layout_constraintRight_toLeftOf="@+id/btn_2" /><Buttonandroid:id="@+id/btn_2"android:layout_width="50dp"android:layout_height="wrap_content"android:background="#00f"android:text="Btn01"app:layout_constraintHorizontal_chainStyle="packed"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toRightOf="@id/btn_1"app:layout_constraintRight_toRightOf="parent" />

约束 _bias的作用

这里注意把约束容器的高度设置为patch_parent不然app:layout_constraintVertical_bias就测试不出来了

app:layout_constraintVertical_bias="0.9"app:layout_constraintHorizontal_bias="0.9"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"
  • 0 -1距离是控制x或者y方向的 的右边(Horizontal)或者底边(Vertical)的百分比距离,1则是完全到右边了。
  • 如果不配合layout_constraintBottom_toBottomOf righttoright left toleft bottomtoleft就没法测试效果了哈。上面的东西如果没设置bias是居中的,设置之后就开始被拉扯。
  • bias的意思是偏向于

辅助线控件的用法

`android.support.constraint.Guideline

<android.support.constraint.Guidelineandroid:id="@+id/guideline_w"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horzontal"app:layout_constraintGuide_begin="50dp"app:layout_constraintGuide_end="50dp"app:layout_constraintGuide_percent="0.5"/>

主要属性有3个

android:orientation="horzontal"app:layout_constraintGuide_begin="50dp"app:layout_constraintGuide_end="50dp"app:layout_constraintGuide_percent="0.5"
  • 如果设置了百分比那么begin end都没卵用了, 百分比在哪里 begin在哪里由方向控制,不再多叙述。
  • 辅助线和我们安卓开发平时应到的隐藏控件做辅助完全雷同啊,我也是这么玩的有时候需求没法解决就弄一个隐藏的view,然后below它的下面。
  • 辅助线控件不可见

还有一些属性没有使用介绍,本人边写边学了一个下午...眼睛都花了

杂项学习

tools:layout_editor_absoluteY 是干啥的? 它只是用来开发工具显示控制偏移用的,下面这个代码得意思是让当前控件距离上边51dp但是实际上运行就不是你看到的开发工具看到的预览效果了。

tools:layout_editor_absoluteY="51dp"

实际上什么约束都没有用上就会出现下面的提示 但是运行是正常的。 是因为垂直或者水平方向没有添加约束

This view is not constrained vertically: at runtime it will jump to the left unless you add a vertical constraint less... (Ctrl+F1)The layout editor allows you to place widgets anywhere on the canvas, and it records the current position with designtime attributes (such aslayout_editor_absoluteX
.) These attributes are **not** applied at runtime, so if you push your layout on a device, the widgets may appear in a different location than shown in the editor. To fix this, make sure a widget has both horizontal and vertical constraints by dragging from the edge connections.此视图不受垂直约束:在运行时它将跳转到
向左,除非您添加了一个垂直约束…
(Ctrl + F1)
布局编辑器允许您将小部件放置在画布上的任何位置,
它记录当前位置和设计时间的属性(如aslayout_editor_absolutex
。)
这些属性在运行时不***,所以如果你推你的
布局在设备上,小部件可能出现在不同的位置。
在编辑器中显示。要解决此问题,请确保小部件具有两个水平。
和从边缘连接拖动的垂直约束。

本人写布局发现存在的问题和无法实现的方案记录

  • 水平排列布局 左边是头像 中间是 纵向的3行文字, 右边是一个关注按钮 ,左中右都是应该居中的。

左边头像 ,中间2 到3个 上下垂直排列 view 居中。右边按钮居中的结构, 上下view无法控制居中,有知道的大神求指导 。约束的情况无法控制

  • 中间垂直排列的某个view 隐藏了也就无法做到类似自动堆在一起。所以线性布局等布局还是有很多存在的意义的。

约束布局无法完美解决所有布局,必要的时候还是要借助其他布局特别是线性布局。

对比

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><data /><androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="2dp"android:orientation="horizontal"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerview_menu"android:layout_width="100dp"app:layout_constraintLeft_toLeftOf="parent"android:layout_height="match_parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintWidth_percent="0.3"/><FrameLayoutandroid:id="@+id/fragment_space_inner"android:layout_width="0dp"android:layout_height="match_parent"android:="@+id/recyclerview_menu"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toRightOf="@+id/recyclerview_menu"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"></FrameLayout></androidx.constraintlayout.widget.ConstraintLayout>
</layout><!--<?xml version="1.0" encoding="utf-8"?><androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".uipage.my.MyFragment"><androidx.appcompat.widget.LinearLayoutCompatandroid:layout_width="match_parent"android:layout_height="match_parent"app:divider="@drawable/divider"android:orientation="vertical"app:dividerPadding="1dp"app:showDividers="middle|beginning|end"><LinearLayoutandroid:id="@+id/btn_print_test"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/ic_launcher_foreground" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="打印测试"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/ll_devanning_box"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/ic_launcher_foreground" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="拆箱"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/ic_launcher_foreground" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="Test"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/ic_launcher_foreground" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="Test"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/ic_launcher_foreground" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="Test"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/ic_launcher_foreground" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="Test"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout></androidx.appcompat.widget.LinearLayoutCompat></androidx.core.widget.NestedScrollView>-->

和百分比

<?xml version="1.0" encoding="utf-8"?>
<layout><data /><android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginTop="2dp"android:orientation="horizontal"><android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerview_menu"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentLeft="true"app:layout_widthPercent="30%" /><FrameLayoutandroid:id="@+id/fragment_space_inner"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_toRightOf="@+id/recyclerview_menu"></FrameLayout></android.support.percent.PercentRelativeLayout>
</layout>

参考链接

http://blog.csdn.net/lmj623565791/article/details/78011599http://www.jianshu.com/p/111b2fbd333e

这篇关于android 约束布局容器ConstraintLayout的初探的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/959212

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

poj 3159 (spfa差分约束最短路) poj 1201

poj 3159: 题意: 每次给出b比a多不多于c个糖果,求n最多比1多多少个糖果。 解析: 差分约束。 这个博客讲差分约束讲的比较好: http://www.cnblogs.com/void/archive/2011/08/26/2153928.html 套个spfa。 代码: #include <iostream>#include <cstdio>#i

poj 3169 spfa 差分约束

题意: 给n只牛,这些牛有些关系。 ml个关系:fr 与 to 牛间的距离要小于等于 cost。 md个关系:fr 与 to 牛间的距离要大于等于 cost。 隐含关系: d[ i ] <= d[ i + 1 ] 解析: 用以上关系建图,求1-n间最短路即可。 新学了一种建图的方法。。。。。。 代码: #include <iostream>#include

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动