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版本中某些行为还是不太一致的,比如环形依赖的问题,这里大家可以实际操作体验一下。

相关推荐
abc80021170341 小时前
前端Bug 修复手册
前端·bug
Best_Liu~1 小时前
el-table实现固定列,及解决固定列导致部分滚动条无法拖动的问题
前端·javascript·vue.js
_斯洛伐克2 小时前
下降npm版本
前端·vue.js
苏十八3 小时前
前端进阶:Vue.js
前端·javascript·vue.js·前端框架·npm·node.js·ecmascript
st紫月4 小时前
用MySQL+node+vue做一个学生信息管理系统(四):制作增加、删除、修改的组件和对应的路由
前端·vue.js·mysql
studyForMokey4 小时前
kotlin 函数类型接口lambda写法
android·开发语言·kotlin
乐容4 小时前
vue3使用pinia中的actions,需要调用接口的话
前端·javascript·vue.js
似水明俊德5 小时前
ASP.NET Core Blazor 5:Blazor表单和数据
java·前端·javascript·html·asp.net
至天6 小时前
UniApp 中 Web/H5 正确使用反向代理解决跨域问题
前端·uni-app·vue3·vue2·vite·反向代理
与墨学长6 小时前
Rust破界:前端革新与Vite重构的深度透视(中)
开发语言·前端·rust·前端框架·wasm