RelativeContainer (鸿蒙版本的ConstraintLayout)

再谈ConstraintLayout

ConstraintLayout 是我们Android开发中常见的以"锚点"为布局的容器,某位UI大湿曾经有句名言:我能用ConstraintLayout实现所有布局!的确,ConstraintLayout特有的layout_constraintxx定义,其实更加符合UI开发的直觉,描述约束本身的成本其实是很少的,同时后期可维护性非常强。因为后续想要添加其他子内容的时候,我们只需要处理好约束本身即可。因此,在AndroidStudio的默认工程中,新建一个xml默认都是以ConstraintLayout为根布局,这也看出来官方对其的重视程度。

不仅如此,ConstraintLayout还被Android团队运用在声明式UI框架Compose当中,成为最重要的组件之一

css 复制代码
@Composable
fun ConstraintLayoutContent() {
    ConstraintLayout {
        // Create references for the composables to constrain
        val (button, text) = createRefs()

        Button(
            onClick = { /* Do something */ },
            // Assign reference "button" to the Button composable
            // and constrain it to the top of the ConstraintLayout
            modifier = Modifier.constrainAs(button) {
                top.linkTo(parent.top, margin = 16.dp)
            }
        ) {
            Text("Button")
        }

        // Assign reference "text" to the Text composable
        // and constrain it to the bottom of the Button composable
        Text("Text", Modifier.constrainAs(text) {
            top.linkTo(button.bottom, margin = 16.dp)
        })
    }
}

同时Android团队把ConstraintLayout作为基础,扩展到了更加复杂的MotionLayout中,作为简化开发动画的利器。

RelativeContainer

既然描述约束这么好用,那么Harmony OS中,有没有类似的组件呢?当然有,毕竟谁也不想让开发们遇上多嵌套的Row跟Column(太难受了)

RelativeContainer就是在鸿蒙开发者,承担着解决多重嵌套的布局利器。

默认情况下,RelativeContainer跟普通组件没有什么区别

scss 复制代码
RelativeContainer() {
  Text("text1")
    .fontSize(25)
    .width(200)
    .id("text1")  // 必须添加 id,否则不显示
    .textAlign(TextAlign.Center)
    .backgroundColor("#ccaabb")
   
}
.width('100%')
.height(200)
.backgroundColor("#111111")

子View text1会默认处于RelativeContainer的左上角

我们可以通过alignRules 方法,声明需要的约束,下面我们来详细认识一下这些锚点

锚点

alignRules 接受一个AlignRuleOption 实现,里面提供了几个具体的锚点

php 复制代码
declare interface AlignRuleOption {
  /**
   * The param of left align.
   * @form
   * @since 9
   */
  left?: { anchor: string, align: HorizontalAlign };
  /**
   * The param of right align.
   * @form
   * @since 9
   */
  right?: { anchor: string, align: HorizontalAlign };
  /**
   * The param of middle align.
   * @form
   * @since 9
   */
  middle?: { anchor: string, align: HorizontalAlign };
  /**
   * The param of top align.
   * @form
   * @since 9
   */
  top?: { anchor: string, align: VerticalAlign };
  /**
   * The param of bottom align.
   * @form
   * @since 9
   */
  bottom?: { anchor: string, align: VerticalAlign };
  /**
   * The param of center align.
   * @form
   * @since 9
   */
  center?: { anchor: string, align: VerticalAlign };
}

锚点 举例

我们拿right 举例子

less 复制代码
Text("text1")
  .fontSize(25)
  .width(200)
  .id("text1")  // 必须添加 id,否则不显示
  .textAlign(TextAlign.Center)
  .backgroundColor("#ccaabb")
  .alignRules({
      right: {
        anchor: "__container__",
        align: HorizontalAlign.End
      },

    })

这里alignRules 可以填入锚点方向

css 复制代码
right?: { anchor: string, align: HorizontalAlign };

right 代表着当前组件需要定位的方向,anchor代表着锚点,以anchor为参考系,align表示对齐方式

这里针对anchor有一个特殊值,"__container__" 代表着以父布局为参考系。

right: { anchor: "container", align: HorizontalAlign.End }, 这个含义是指,当前子组件Text的right方向以父布局为基准,然后按照右侧对齐

针对水平方向align为HorizontalAlign

  • HorizontalAlign.Start: 设置子组件右边框相对锚点组件的左边框位置对齐。
  • HorizontalAlign.Center: 设置子组件右边框相对锚点组件的中间点位置对齐。
  • HorizontalAlign.End: 设置子组件右边框相对锚点组件的右边框位置对齐。

当然,单个left跟right对齐其实跟大部分的声明式UI框架没有太多区别,这里我特别举出一个例子,比如我们想要实现一个组件居中对齐,习惯了ConstraintLayout,我们可能会直接对left跟right进行对齐,比如错误示例

css 复制代码
 right: {
   anchor: "__container__",
   align: HorizontalAlign.End
 },
left: {
 anchor: "__container__",
 align: HorizontalAlign.Start
},

这样的话,其实只会把子布局width撑大到父布局,比如


这里也说明了,当多个方向的锚点被设置,其实效果是满足锚点,同时会把子组件自身的width属性的数据丢失(本来设置的width为200)

想要实现水平居中,RelativeContainer 采取middle对齐的方式实现,

css 复制代码
middle:{
  anchor: "__container__",
  align: HorizontalAlign.Center
},

垂直居中的话,就要采取center对齐

css 复制代码
center:{
    anchor: "__container__",
    align: VerticalAlign.Center
  },

其他的几个,欢迎读者们自行尝试一下效果。

除了以父组件为参考系以外,我们还可以以其他子组件为参考系,比如我们放置两个子Text

less 复制代码
RelativeContainer() {
  Text("text1")
    .fontSize(25)
    .id("text1")  // 必须添加 id,否则不显示
    .textAlign(TextAlign.Center)
    .backgroundColor("#ccaabb")
    .alignRules({
      left:{
        anchor:"__container__",
        align: HorizontalAlign.Start
      },
      right:{
        anchor:"__container__",
        align: HorizontalAlign.End
      },
    })


  Text("text2")
    .fontSize(25)
    .id("text2")  // 必须添加 id,否则不显示
    .textAlign(TextAlign.Center)
    .backgroundColor("#bbccaa")
    .alignRules({
      left:{
        anchor:"__container__",
        align: HorizontalAlign.Start
      },
      right:{
        anchor:"__container__",
        align: HorizontalAlign.End
      },
      // 以text1 为参考系,顶部对齐
      top:{
        anchor:"text1",
        align:VerticalAlign.Bottom
      }

    })

}
.width('100%')
.height(200)
.backgroundColor("#111111")

对应的效果图如下

注意点

这里总结几个开发过程中会遇到的几个需要注意的点

width等自身属性会被锚点覆盖

这里我们上面例子也给出来了,当我们设置组件自身固有属性,比如width的时候,如果设置了相同方向的多个锚点,比如同时设置left 跟right,那么组件的宽度会以锚点的布局为最终宽度

子组件需要设置id

如果子组件没有设置id,那么组件会不被绘制展示,比如我们把text2的id拿掉后

less 复制代码
没有id
Text("text2")
  .fontSize(25)
  .textAlign(TextAlign.Center)
  .backgroundColor("#bbccaa")
  .alignRules({
    left:{
      anchor:"__container__",
      align: HorizontalAlign.Start
    },
    right:{
      anchor:"__container__",
      align: HorizontalAlign.End
    },
    // 以text1 为参考系,顶部对齐
    top:{
      anchor:"text1",
      align:VerticalAlign.Bottom
    }

  })

效果如下,text2将不被绘制

避免align 错误影响

align参数也会影响到布局展示,比如

scss 复制代码
  RelativeContainer() {
    Text("text1")
      .fontSize(25)
      .id("text1")
      .textAlign(TextAlign.Center)
      .backgroundColor("#ccaabb")
      .alignRules({
        left:{
          anchor:"__container__",
          align: HorizontalAlign.End
        },
      })


  }
  .width('100%')
  .height(200)
  .backgroundColor("#111111")
}
.width('100%')

如果left 对齐的位置是父view的end,那么其实就是没有展示空间从而不被展示

总结

本章中我们学习到了(鸿蒙版本ConstraintLayout) RelativeContainer 的用法,同时官方的资料中其实对RelativeContainer没有太多补充,因此我在这里提一下,当然,RelativeContainer在每个api版本中某些行为还是不太一致的,比如环形依赖的问题,这里大家可以实际操作体验一下。

相关推荐
帅得不敢出门12 分钟前
Gradle命令编译Android Studio工程项目并签名
android·ide·android studio·gradlew
我要洋人死19 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人31 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人31 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR37 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香39 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969341 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
problc1 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js