Skip to content

ArgoUI布局

xuwhale6 edited this page Feb 26, 2021 · 6 revisions

ArgoUI新布局

ArgoUI新布局以flex box 为基础,结合了线性布局、SwiftUI布局里的优秀特性。让开发人员可以用更简洁扁平的方式布局UI。

分为以下几种布局,下面将通过demo示例逐步讲解。

  1. HStack 横向线性布局
  2. VStack 纵向线性布局
  3. Spacer 占位布局

我们将用新布局来完成一个简单的入门demo。效果图如下:

HStack

HStack是横向线性布局,对于它而言,主轴即指水平方向,交叉轴指竖直方向。

1. 默认宽高自适应。可通过设置widthPercent/heightPercent实现宽高占父view的百分比。

如设置widthPercent(100)来实现宽度占满。

mLabel(str, bgColor) {
    Label(str)
    .textColor(Color(255, 255, 255, 0.8))
    .padding(3, 5, 3, 5)
    .bgColor(bgColor)
    .fontSize(10)
}
---
--- UI
ui {
    --- layout views
    HStack()
    .widthPercent(100)
    .bgColor(Color(220, 230, 200, 1))
    .subs(
        mLabel("0元配送", Color(100, 100, 200, 0.8))
        ,
        mLabel("支持自取", Color(100, 120, 200, 0.8))
        ,
        mLabel("食无忧", Color(140, 120, 200, 0.8))
        ,
        mLabel("津贴2元", Color(180, 150, 100, 0.8))
        ,
        mLabel("会员专享", Color(180, 100, 100, 0.8))
        ,
        mLabel("首单立减", Color(150, 60, 100, 0.8))
    )
}

---
--- preview
local function preview()
end


2. 通过mainAxis(int mainAxis)设置子view在主轴方向的对齐方式。参数是MainAxis枚举类型。

主轴默认是MainAxis.START 向起始方向对齐。

--demo1
mLabel(str, bgColor) {
    Label(str)
    .textColor(Color(255, 255, 255, 0.8))
    .padding(3, 5, 3, 5)
    .bgColor(bgColor)
    .fontSize(10)
}
---
--- UI
ui {
    --- layout views
    HStack()
    .mainAxis(MainAxis.START)
    .widthPercent(100)
    .bgColor(Color(220, 230, 200, 1))
    .subs(
        mLabel("0元配送", Color(100, 100, 200, 0.8))
        ,
        mLabel("支持自取", Color(100, 120, 200, 0.8))
        ,
        mLabel("食无忧", Color(140, 120, 200, 0.8))
        ,
        mLabel("津贴2元", Color(180, 150, 100, 0.8))
        ,
        mLabel("会员专享", Color(180, 100, 100, 0.8))
        ,
        mLabel("首单立减", Color(150, 60, 100, 0.8))
    )
}

---
--- preview
local function preview()
end

MainAxis.CENTER 向中心对齐。将demo1中MainAxis枚举值改为CENTER,ui显示如下


MainAxis.END 向结束方向对齐。将demo1中MainAxis枚举值改为END,ui显示如下


MainAxis.SPACE_BETWEEN 空闲区域在子view之间,等间距分布space,头尾不占space。


MainAxis.SPACE_AROUND 空闲区域在子view之间,等间距分布space,头尾各占1/2space。


MainAxis.SPACE_EVENLY 空闲区域在子view之间,等间距分布space,头尾各占1space。


3. 未设置自动换行时,通过crossAxis(int crossAxis)设置子view在交叉轴方向的对齐方式。当子View的高度小于HStack的高度时才有意义。参数是CrossAxis枚举类型。

我们为HStack设置一个固定高度,来观察CrossAxis的枚举效果。

交叉轴默认是CrossAxis.START 向起始方向对齐。

mLabel(str, bgColor) {
    Label(str)
    .textColor(Color(255, 255, 255, 0.8))
    .padding(3, 5, 3, 5)
    .bgColor(bgColor)
    .fontSize(10)
}
---
--- UI
ui {
    --- layout views 
    HStack().height(50)
    .crossAxis(CrossAxis.START)
    .mainAxis(MainAxis.SPACE_EVENLY)
    .widthPercent(100)
    .bgColor(Color(220, 230, 200, 1))
    .subs(
        mLabel("0元配送", Color(100, 100, 200, 0.8))
        ,
        mLabel("支持自取", Color(100, 120, 200, 0.8))
        ,
        mLabel("食无忧", Color(140, 120, 200, 0.8))
        ,
        mLabel("津贴2元", Color(180, 150, 100, 0.8))
        ,
        mLabel("会员专享", Color(180, 100, 100, 0.8))
        ,
        mLabel("首单立减", Color(150, 60, 100, 0.8))
    )
}

---
--- preview
local function preview()
end


CrossAxis.CENTER 向中心对齐。


CrossAxis.END 向结束方向对齐。


CrossAxis.STRETCH 交叉轴上拉伸。注意:子view未设置高度时才会拉伸。


CrossAxis.BASELINE 沿基线对齐。为demo中子view设置不同的高度,ui显示如下:


CrossAxis.SPACE_BETWEEN 交叉轴方向上空闲区域在子view之间,等间距分布space,头尾不占space。
设置HStack多行,观察枚举效果(具体实现会在Wrap中介绍到)。

HStack()
    .wrap(Wrap.WRAP)
    .crossContent(CrossAxis.SPACE_BETWEEN)


CrossAxis.SPACE_AROUND 交叉轴方向上空闲区域在子view之间,等间距分布space,头尾各占1/2space。

HStack()
    .wrap(Wrap.WRAP)
    .crossContent(CrossAxis.SPACE_AROUND)


4. 若设置自动换行,需通过crossContent(int crossAxis)设置子view在交叉轴方向的对齐方式。参数是CrossAxis枚举类型。下面介绍wrap时会详细说明。

5. 通过wrap(int wrap)设置子view是否换行排列。参数是Wrap枚举类型。

默认Wrap.NO_WRAP 不换行。

--wrap_demo
mLayout(str, imgBool) {
    HStack()
    .padding(0, 5, 0, 5)
    .bgColor(Color(220, 220, 220, 0.5))
    .cornerRadius(5)
    .height(28)
    .crossAxis(CrossAxis.CENTER)
    .left(3)
    .right(3)
    .top(3)
    .bottom(3)
    .subs(
        ImageView()
        .width(18)
        .height(18)
        .image("https://s.momocdn.com/w/u/others/custom/MLNUI/icon.png")
        .bind(function()
            if imgBool then
                self.display(true)
            else
                self.display(false)
            end
        end)
        ,
        Label(str)
        .fontSize(12)
    )

}
---
--- UI
ui {
    --- layout views
    HStack()
    .height(100)
    .bgColor(Color(220, 230, 200, 0.2))
    .wrap(Wrap.NO_WRAP)
    .subs(
        mLayout("汉堡", true)
        ,
        mLayout("龙虾饭", true)
        ,
        mLayout("番茄米线", false)
        ,
        mLayout("健康蔬菜沙拉", true)
        ,
        mLayout("车厘子优选", true)
        ,
        mLayout("藤椒麻辣香锅", false)
    )

}
---
--- preview
function preview()
end

设置wrap(Wrap.NO_WRAP)后,我们分别设置crossAxis(CrossAxis.CENTER)crossContent(CrossAxis.CENTER)

--未设置自动换行时,设置crossAxis有效
HStack()
    .wrap(Wrap.NO_WRAP)
    .crossAxis(CrossAxis.CENTER)



--未设置自动换行时,设置crossContent无效
HStack()
    .wrap(Wrap.NO_WRAP)
    .crossContent(CrossAxis.CENTER)



Wrap.WRAP 自动换行。

--设置自动换行时,设置crossAxis无效
HStack()
    .wrap(Wrap.WRAP)
    .crossAxis(CrossAxis.CENTER)



--设置自动换行时,设置crossContent有效
HStack().wrap(Wrap.WRAP)
    .crossContent(CrossAxis.CENTER)



Wrap.WRAP_REVERSE 反方向自动换行。

--设置自动换行时,设置crossAxis无效
HStack()
    .wrap(Wrap.WRAP_REVERSE)
    .crossAxis(CrossAxis.CENTER)



--设置自动换行时,设置crossContent有效
HStack()
    .wrap(Wrap.WRAP_REVERSE)
    .crossContent(CrossAxis.CENTER)


总结:未设置自动换行时通过crossAxis方法设置子view在交叉轴方向的对齐方式。若设置自动换行,使用crossContent方法。

⚠️注意:设置MainAxis后,主轴上对齐方式每行单独生效。设置CrossAxis,以所有行为一个整体生效,每行的子View不受其控制。

HStack()
    .height(100)
    .bgColor(Color(220, 230, 200, 0.2))
    .wrap(Wrap.WRAP)
    .mainAxis(MainAxis.SPACE_EVENLY) 
    .crossContent(CrossAxis.CENTER)

6. HStack的子view通过crossSelf(int crossAxis)设置子view自身在交叉轴的对齐方式。

下面我们为demo中子view设置crossSelf来观察效果。

初始ui如下:

为子view设置crossSelf后如下:

mLabel(str, bgColor) {
    Label(str)
    .textColor(Color(255, 255, 255, 0.8))
    .padding(3, 5, 3, 5)
    .bgColor(bgColor)
    .fontSize(10)
}
---
--- UI
ui {
    --- layout views
    HStack().height(50)
    .widthPercent(100)
    .bgColor(Color(220, 230, 200, 1))
    .subs(
        mLabel("0元配送", Color(100, 100, 200, 0.8))
        ,
        mLabel("支持自取", Color(100, 120, 200, 0.8))
        .crossSelf(CrossAxis.CENTER)
        ,
        mLabel("食无忧", Color(140, 120, 200, 0.8))
        .crossSelf(CrossAxis.END)
        ,
        mLabel("津贴2元", Color(180, 150, 100, 0.8))
        .crossSelf(CrossAxis.STRETCH)
        ,
        mLabel("会员专享", Color(180, 100, 100, 0.8))
        ,
        mLabel("首单立减", Color(150, 60, 100, 0.8))
    )
}
---
--- preview
local function preview()
end


7. basis、grow、shrink

basis:设置view自身在主轴方向的基础尺寸。

HStack的子view 同时设置固定宽度和basis时,basis生效)   


grow:填充拉伸。所有设置grow的子View,先走自身尺寸或basis尺寸,剩余多出来的空间,再由grow比例分配加到每个子View上。

shrink:压缩。当空间不足以放下所有子View时,按照shrink比例对每个子View进行压缩。

HStack().bgColor(Color(0xffff00))
    .widthPercent(100)
    .height(50)
    .subs(
        Label("label1").bgColor(Color(0xff0000))
        .width(100).grow(1)
        ,
        Label("label2").bgColor(Color(0xfff0f0))
        .basis(50).grow(1)
        ,
        Label("label3")
    )

8. display、hidden

通过display(boolean display)设置View是否可见。设置false后View不占空间。⚠️View设置PositionType.ABSOLUTE后,display方法会失效。
通过hidden(boolean hidden)设置View是否可见。设置true后View不可见,但仍占空间。

mLabel(str, bgColor) {
    Label(str)
    .textColor(Color(255, 255, 255, 0.8))
    .padding(3, 5, 3, 5)
    .bgColor(bgColor)
    .fontSize(10)
}
---
--- UI
ui {
    --- layout views
    HStack().height(50)
    .widthPercent(100)
    .bgColor(Color(220, 230, 200, 1))
    .subs(
        mLabel("0元配送1", Color(100, 100, 200, 0.8))
        .display(true)
        ,
        mLabel("支持自取2", Color(100, 120, 200, 0.8))
        .display(false)
        ,
        mLabel("食无忧3", Color(140, 120, 200, 0.8))
        ,
        mLabel("津贴2元4", Color(180, 150, 100, 0.8))
        .hidden(true)
        ,
        mLabel("会员专享5", Color(180, 100, 100, 0.8))
        .hidden(false)
        ,
        mLabel("首单立减6", Color(150, 60, 100, 0.8))
    )
}.safeArea(SafeArea.TOP)

---
--- preview
local function preview()
end

9. position定位

positionType(int positionType),参数为PositionType枚举。

PositionType.ABSOLUTE:绝对定位。相对父View的偏移,偏移后其他同级控件会受影响。⚠️设置绝对定位后,display方法会失效。
PositionType.RELATIVE:相对定位。相对自身位置的基础上进行偏移,偏移后其他同级控件位置不变。

通过position(top, right,bottom,left)/positionLeft(left)等设置偏移量。

初始ui如下:

如下代码中设置PositionType.ABSOLUTE相关后,可以看到设置position的控件不再占位,其之后的同级控件位置会前移:

--为Label设置position如下
mLabel("津贴2元", Color(180, 150, 100, 0.8))
        .positionType(PositionType.ABSOLUTE)
        .positionLeft(10)
        .positionTop(10)


如下代码中设置PositionType.RELATIVE相关后,可以看到设置position的控件原位置仍保留,其同级控件位置不变:

mLabel("津贴2元", Color(180, 150, 100, 0.8))
        .positionType(PositionType.RELATIVE)
        .positionLeft(10)
        .positionTop(10)
--完整demo
mLabel(str, bgColor) {
    Label(str)
    .textColor(Color(255, 255, 255, 0.8))
    .padding(3, 5, 3, 5)
    .bgColor(bgColor)
    .fontSize(10)
}
---
--- UI
ui {
    --- layout views
    HStack().height(50)
    .widthPercent(100)
    .bgColor(Color(220, 230, 200, 1))
    .subs(
        mLabel("0元配送", Color(100, 100, 200, 0.8))
        ,
        mLabel("支持自取", Color(100, 120, 200, 0.8))
        ,
        mLabel("食无忧", Color(140, 120, 200, 0.8))
        ,
        mLabel("津贴2元", Color(180, 150, 100, 0.8))
        .positionType(PositionType.ABSOLUTE)
        .positionLeft(10)
        .positionTop(10)
        ,
        mLabel("会员专享", Color(180, 100, 100, 0.8))
        ,
        mLabel("首单立减", Color(150, 60, 100, 0.8))
    )
}.safeArea(SafeArea.TOP)

---
--- preview
local function preview()
end

总结:

  1. 之前想要实现类似等间隔布局,需要通过计算设置每个子view的margin值,现在直接设置HStack的MainAxis即可快速实现;
  2. 之前想要实现子view保持一致的对齐方式,需要为每个子view设置gravity,重复工作较多,现在直接设置HStack的MainAxis、CrossAxis即可快速实现;
  3. 我们经常会遇到如下业务场景,多个子view长度不等,按行排列,放不下的标签折行继续排列。之前的做法,我们需要计算剩余空间能否放下子view,然后再进行布局,现在只需要设置HStack的wrap属性即可轻松实现。

VStack

VStack是纵向线性布局,对于它而言,主轴即指竖直方向,交叉轴指水平方向。VStack使用与HStack类似。

1. 通过mainAxis(int mainAxis)设置子view在主轴方向(即竖直方向)的对齐方式。参数是MainAxis枚举类型。

主轴默认是MainAxis.START 向起始方向对齐。

mLabel(str, bgColor) {
    Label(str)
    .textColor(Color(255, 255, 255, 0.8))
    .padding(3, 5, 3, 5)
    .bgColor(bgColor)
    .fontSize(10)

}
colorLabel(str, color, size) {
    Label(str)
    .textColor(color)
    .fontSize(size)
}

---
--- UI
ui {
    --- layout views
    VStack()
    .mainAxis(MainAxis.START)
    .widthPercent(100)
    .height(100)
    .bgColor(Color(220, 230, 200, 1))
    .subs(
        colorLabel("小龙虾饭 ", Color(20, 20, 20, 1), 14)
        ,
        colorLabel("评分4.5 ", Color(250, 60, 100, 1), 12)
        ,
        colorLabel("起送 ¥20", Color(120, 120, 120, 1), 12)
        ,
        HStack()
        .widthPercent(100)
        .mainAxis(MainAxis.SPACE_BETWEEN)
        .bgColor(Color(220, 230, 200, 1))
        .subs(
            mLabel("0元配送", Color(100, 100, 200, 0.8))
            ,
            mLabel("支持自取", Color(100, 120, 200, 0.8))
            ,
            mLabel("食无忧", Color(140, 120, 200, 0.8))
            ,
            mLabel("津贴2元", Color(180, 150, 100, 0.8))
            ,
            mLabel("会员专享", Color(180, 100, 100, 0.8))
            ,
            mLabel("首单立减", Color(150, 60, 100, 0.8))
        )
    )

}
---
--- preview
local function preview()
end

MainAxis.CENTER 向中心对齐。将demo1中MainAxis枚举值改为CENTER,ui显示如下


MainAxis.END 向结束方向对齐。将demo1中MainAxis枚举值改为END,ui显示如下


MainAxis.SPACE_BETWEEN 空闲区域在子view之间,等间距分布space,头尾不占space。


MainAxis.SPACE_AROUND 空闲区域在子view之间,等间距分布space,头尾各占1/2space。


MainAxis.SPACE_EVENLY 空闲区域在子view之间,等间距分布space,头尾各占1space。


3. 通过crossAxis(int crossAxis)设置子view在交叉轴方向(水平方向)的对齐方式。参数是CrossAxis枚举类型。

交叉轴默认是CrossAxis.START 向起始方向对齐。

    VStack()
            .crossAxis(CrossAxis.START)


CrossAxis.CENTER 向中心对齐。


CrossAxis.END 向结束方向对齐。


VStack使用与HStack类似,其他用法说明请参考HStack

Spacer

占位布局,需配合HStackVStack使用。

我们以下图布局为例,开始使用Spacer。

1. Spacer会占用所有剩余空间。

colorLabel(str, color, size) {
    Label(str)
            .textColor(color)
            .fontSize(size)
}
---
--- UI
ui = {
    --- layout views
    HStack()
            .subs(

            colorLabel("评分4.5", Color(250, 60, 100, 1), 12)
    ,
            colorLabel("销量66", Color(50, 50, 50, 1), 12)
    ,
            Spacer()
    ,
            colorLabel("35分钟", Color(50, 150, 50, 1), 12)
    ,
            colorLabel("1.2km", Color(50, 50, 150, 1), 12)
    )

}


2. 存在多个Spacer时,剩余空间由多个Spacer平分。

HStack()
            .subs(

            colorLabel("评分4.5", Color(250, 60, 100, 1), 12)
    ,
            colorLabel("销量66", Color(50, 50, 50, 1), 12)
    ,
            Spacer()
    ,
            colorLabel("35分钟", Color(50, 150, 50, 1), 12)
    ,
            Spacer()
    ,
            colorLabel("1.2km", Color(50, 50, 150, 1), 12)
    )


点击查看完整demo
mLabel(str, bgColor) {
    Label(str)
    .textColor(Color(255, 255, 255, 0.8))
    .padding(3, 5, 3, 5)
    .bgColor(bgColor)
    .fontSize(10)
}

colorLabel(str, color, size) {
    Label(str)
    .textColor(color)
    .fontSize(size)
}
mLayout(str, imgBool) {
    HStack()
    --.width(MeasurementType.WRAP_CONTENT)
    .padding(0, 5, 0, 5)
    .bgColor(Color(220, 220, 220, 0.5))
    .cornerRadius(5)
    .height(28)
    .crossAxis(CrossAxis.CENTER)
    .left(3)
    .right(3)
    .top(3)
    .bottom(3)
    .subs(
        ImageView()
        .width(18)
        .height(18)
        .image("https://s.momocdn.com/w/u/others/custom/MLNUI/icon.png")
        .bind(function()
            if imgBool then
                self.display(true)
            else
                self.display(false)
            end
        end)
        ,
        Label(str)
        .fontSize(12)
    )

}
---
--- UI
ui = {
    --- layout views
    VStack().widthPercent(100)
    .subs(
        colorLabel("热门搜索", Color(20, 20, 20, 1), 14)
        ,
        HStack().bgColor(Color(220, 230, 200, 0.2))
        .wrap(Wrap.WRAP)
        .subs(
            mLayout("汉堡", true)
            ,
            mLayout("龙虾饭", true)
            ,
            mLayout("番茄米线", false)
            ,
            mLayout("健康蔬菜沙拉", true)
            ,
            mLayout("车厘子优选", true)
            ,
            mLayout("藤椒麻辣香锅", false)
        )

        ,
        HStack()
        .bgColor(Color(220, 230, 200, 1))
        .crossAxis(CrossAxis.CENTER)
        .widthPercent(100)
        .subs(
            ImageView("https://hbimg.huabanimg.com/7c41bc5871d74c9036932ca9bba76de363727be113b6fd-NApej6_fw658")
            .width(50)
            .height(50)
            .contentMode(ContentMode.SCALE_ASPECT_FILL)
            .cornerRadius(40)
            ,
            ImageView("https://s.momocdn.com/w/u/others/custom/MLNUI/hot2.png")
            .width(15)
            .height(15)
            .positionType(PositionType.RELATIVE)
            .positionLeft(-15)
            .positionBottom(15)
            ,
            VStack()
            .width(250)
            .mainAxis(MainAxis.SPACE_EVENLY)
            .crossAxis(CrossAxis.START)
            .height(100)
            .subs(
                colorLabel("小龙虾饭 ", Color(20, 20, 20, 1), 14)
                ,
                colorLabel("起送 ¥20", Color(120, 120, 120, 1), 12)
                ,
                HStack()
                .widthPercent(100)
                .subs(

                    colorLabel("评分4.5", Color(250, 60, 100, 1), 12)
                    ,
                    colorLabel(" 销量66", Color(50, 50, 50, 1), 12)
                    ,
                    Spacer()
                    ,
                    colorLabel("35分钟", Color(50, 150, 50, 1), 12)
                    ,
                    colorLabel(" 1.2km", Color(50, 50, 150, 1), 12)
                )
                ,
                HStack()
                .widthPercent(100)
                .mainAxis(MainAxis.SPACE_BETWEEN)
                .subs(
                    mLabel("支持自取", Color(100, 120, 200, 0.8))
                    ,
                    mLabel("食无忧", Color(140, 120, 200, 0.8))
                    ,
                    mLabel("津贴2元", Color(180, 150, 100, 0.8))
                    ,
                    mLabel("会员专享", Color(180, 100, 100, 0.8))
                    ,
                    mLabel("首单立减", Color(150, 60, 100, 0.8))
                )
            )
            ,
            mLabel("分享", Color(100, 100, 200, 1), 12)
            .positionType(PositionType.ABSOLUTE)
            .positionRight(0)
            .positionTop(0)
            ,
            mLabel("赞", Color(150, 60, 100, 1), 12)
            .crossSelf(CrossAxis.END)
            .positionType(PositionType.ABSOLUTE)
            .positionRight(0)
        )
        ,
        HStack()
        .widthPercent(100)
        .subs(
            mLabel("\"吃货强推\"", Color(200, 100, 0, 0.5))
            .width(60)
            ,
            mLabel("\"人气飙升\"", Color(100, 100, 0, 0.5))
            .width(60)
            .basis(2)
            ,
            mLabel("\"赞\"", Color(200, 100, 0, 0.5))
            .basis(1)
            ,
            mLabel("\"就很棒哇\"", Color(100, 100, 0, 0.5))
            .basis(2)
            ,
            mLabel("\"吃货强推啊啊啊啊\"", Color(200, 100, 0, 0.5))
            .basis(3)
        )
    )
}

---
--- preview
function preview()
end

使用过程中,如有任何问题,欢迎反馈~

Clone this wiki locally