Jetpack Compose 自定义布局以及固有特性测量(1)

CornerPosition.TopRight->{

placeable.placeRelative(constraints.maxWidth-placeable.width, 0)

}

CornerPosition.BottomLeft->{

placeable.placeRelative(0, constraints.maxHeight-placeable.height)

}

CornerPosition.BottomRight->{

placeable.placeRelative(constraints.maxWidth-placeable.width, constraints.maxHeight-placeable.height)

}

}

}

}

复制代码

  • 首先我们声明一个枚举。叫CornerPosition,枚举有四种取值,TopLeft表示左上角,TopRight右上角,BottomLeft左下角,BottomRight又下角。

  • 接着我们定义一个Modifier的扩展函数customCornerPosLayout,入参是pos:CornerPosition我们的枚举类

  • customCornerPosLayout的实现是通过layout的lamda去实现。其实是调用Modifier.layout去实现自定义布局。有两个参数一个是measurable,一个是constraints父控件的约束

  • 自定义布局第一步val placeable = measurable.measure(constraints) 是根据measurable跟constraints父控件的约束,通过方法measurable.measure(constraints)去生成一个placeable类。该类拥有子控件的宽width跟高height

  • 自定义布局的第二部 需要调用layout(w,h)的方法去设置当前view能使用的宽高。我们这里是用layout(constraints.maxWidth, constraints.maxHeight) 传入的是constraints.maxWidth父控件提供能使用的最大宽,constraints.maxHeight父控件提供能使用的最大高

  • 接着第三部就是在layout{}里通过 placeable.placeRelative 去放置该元素的位置。我们这里是根据传入的参数是左上角CornerPosition.TopLeft,还是左下角CornerPosition.BottomLeft,还是右上角CornerPosition.TopRight,还是右下角CornerPosition.BottomRight去放置该界面元素的位置。

  • placeable.placeRelative(0, 0) 左上角是0,0

  • placeable.placeRelative(constraints.maxWidth-placeable.width, 0) 右上角 x是需要拿最大宽度减去本身view的宽度,y是0

  • placeable.placeRelative(0, constraints.maxHeight-placeable.height) 左下角x是0,y是需要拿最大的高度减去本身的高度

  • placeable.placeRelative(constraints.maxWidth-placeable.width, constraints.maxHeight-placeable.height) x是需要拿最大宽度减去本身view的宽度,y需要拿最大的高度减去本身的高度

举例:自定义完成之后,我们举个放置在右下角的例子

@Preview

@Composable

fun customCornerPosLayoutTest(){

Box(modifier = Modifier.size(100.dp)

.background(color = Color.Red)) {

Box(modifier = Modifier

.customCornerPosLayout(CornerPosition.BottomRight)

.size(10.dp)

.background(color = Color.Blue, shape = CircleShape))

}

}

复制代码

效果如下: Screenshot_bottomright.jpg

1.2 Layout创建自定义布局

Modifier.layout修饰符仅更改调用的可组合项。如需测量和布置多个可组合项,请改用 Layout。在 View 系统中,创建自定义布局我们是会扩展 ViewGroup 并实现onMeasure和onLayout函数。在 Compose 中,我们只需使用 Layout 可组合项编写一个函数即可。

下面我们通过Layout去自定义一个有方向的Column布局。直接上代码

@Composable

fun CustomColumnView(

layoutDirection:LayoutDirection,

modifier: Modifier = Modifier,

content: @Composable() () -> Unit){

Layout(

modifier = modifier,

content = content

) { measurables, constraints ->

var totalHeight = 0

var maxWidth = 0

val placeables = measurables.map {

val placeable = it.measure(constraints)

totalHeight+=placeable.height

if(placeable.width>maxWidth){

maxWidth = placeable.width

}

placeable

}

layout(maxWidth,totalHeight){

if(layoutDirection == LayoutDirection.Ltr){

var y = 0

placeables.forEach {

it.place(0,y)

y+=it.height

}

}else{

var y = totalHeight

placeables.forEach {

y-=it.height

it.place(0,y)

}

}

}

}

}

复制代码

  • 我们定义了一个CustomColumnView的可组合函数

  • 定义了三个参数,layoutDirection去控制方向,modifier修饰符,内容可组合函数content。

  • 内部的实现我们是通过Layout去自定义布局

  • 测量每个子view的宽高 val placeable = it.measure(constraints) 自定义布局第一步需要通过父控件给的约束条件constraints跟measurable去执行measure测量。获得Placeable对象。该对象里可以获取到测量完成的每个子item的宽width跟高height。

  • 接着我们根据测量好的所有的子view的宽高,可以去计算出我们自定义CustomColumnView所需要的宽高,高我们用totalHeight变量先存储,宽我们用maxWidth变量存储

  • totalHeight+=placeable.height 我们把每个子View的高累加起来就是CustomColumnView控件的高。

  • if(placeable.width>maxWidth){maxWidth = placeable.width} 我们把子View最大的宽作为CustomColumnView的宽。

  • 计算完成CustomColumnView的宽高之后,我们需要调用layout(maxWidth,totalHeight)方法去设置CustomColumnView的宽高

  • 并且需要在layout方法里去调用placeable.place(x, y) 去放置子View的位置

layout(maxWidth,totalHeight){

if(layoutDirection == LayoutDirection.Ltr){

var y = 0

placeables.forEach {

it.place(0,y)

y+=it.height

}

}else{

var y = totalHeight

placeables.forEach {

y-=it.height

it.place(0,y)

}

}

}

}

复制代码

  • 比如上面的例子中我们是根据方向layoutDirection == LayoutDirection.Ltr 我们就从上到下放置子View。it.place(0,y) y初始值是0,并且y是一直累加上上一个子View的高度

  • 否则我们就从下到上去放置子View,it.place(0,y) y初始值是totalHeight即CustomColumnView的高度也就是在最底部,并且y是一直去减去当前子View的高度。这样就能从底部往上放置了

封装完成自定义的CustomColumnView后,我们举例使用 从上往下排列的CustomColumnView

@Preview

@Composable

fun bottomToTopCustomColumnTest(){

CustomColumnView(

layoutDirection = LayoutDirection.Ltr,

modifier = Modifier.background(color = Color.Red)

){

Text(text = “第一个Text第一个Text第一个Text第一个Text”)

Text(text = “第二个Text”)

Text(text = “第三个Text”)

Text(text = “第四个Text”)

Text(text = “第五个Text第五个Text”)

}

}

复制代码

效果如下: Screenshot_top_bottom.jpg

从下往上排列的CustomColumnView

@Preview

@Composable

fun bottomToTopCustomColumnTest(){

CustomColumnView(

layoutDirection = LayoutDirection.Rtl,

modifier = Modifier.background(color = Color.Red)

){

Text(text = “第一个Text第一个Text第一个Text第一个Text”)

Text(text = “第二个Text”)

Text(text = “第三个Text”)

Text(text = “第四个Text”)

Text(text = “第五个Text第五个Text”)

}

}

复制代码

Screenshot_bottom_top.jpg

二:Intrinsic Measurement(固有特性测量)

以前在Android的View系统中,存在多次测量。所以在View系统中我们为了优化性能,要求减少布局层次的嵌套。而在Compose中,子项只能测量一次,测量两次就会引发运行时异常,所以在Compose中各种嵌套子项是不会影响性能的。Compose中为啥能做到不需要测量多次呢,就是因为有了这个Intrinsic Measurement(固有特性测量)。

Intrinsic Measurement 是允许父项对子项测量之前,先让子项测量下自己的最大最小的尺寸。 使用官网的例子讲解:比如我们想要达到下面的效果 test.jpg

我们的代码如下去写:

@Preview

@Composable

fun twoViewTest() {

Row() {

Text(

modifier = Modifier

.weight(1f)

.padding(start = 4.dp)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

**一个零基础的新人,我认为坚持是最最重要的。**我的很多朋友都找我来学习过,我也很用心的教他们,可是不到一个月就坚持不下来了。我认为他们坚持不下来有两点主要原因:

他们打算入行不是因为兴趣,而是因为所谓的IT行业工资高,或者说完全对未来没有任何规划。

刚开始学的时候确实很枯燥,这确实对你是个考验,所以说坚持下来也很不容易,但是如果你有兴趣就不会认为这是累,不会认为这很枯燥,总之还是贵在坚持。

技术提升遇到瓶颈了?缺高级Android进阶视频学习提升自己吗?还有大量大厂面试题为你面试做准备!

提升自己去挑战一下BAT面试难关吧

对于很多Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些知识图谱希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

不论遇到什么困难,都不应该成为我们放弃的理由!

如果有什么疑问的可以直接私我,我尽自己最大力量帮助你!

最后祝各位新人都能坚持下来,学有所成。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

自己吗?还有大量大厂面试题为你面试做准备!**

提升自己去挑战一下BAT面试难关吧

[外链图片转存中…(img-X2TKT5ZI-1713382217605)]

对于很多Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些知识图谱希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

不论遇到什么困难,都不应该成为我们放弃的理由!

如果有什么疑问的可以直接私我,我尽自己最大力量帮助你!

最后祝各位新人都能坚持下来,学有所成。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 11
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值