Skip to main content

布局

简介#

Ave 只支持 grid 的布局方式(web 中 flex 布局也可以基于此封装,不过 grid 其实是更灵活、强大的布局方式),所有控件都需要放在 grid 之中,因此组件部分首先从 grid 开始介绍。

Ave 中 grid 的含义和 web 中的(A Complete Guide to Grid)差不多,但是更加底层,也就是说,web 里的 grid css 也可以基于此实现。

例子#

背景色#

export function App() {    return (        <Window>            <Grid                style={{                    backgroundColor: new Vec4(0, 146, 255, 255 * 0.75),                }}            ></Grid>        </Window>    );}

在 Ave 中我们使用Vec4类来表示颜色,其中每个颜色的取值范围都是[0,255],然后使用 grid 的backgroundColor设置背景颜色。

grid background

API#

export interface IGridComponentProps extends IComponentProps {    style?: IGridStyle;    ...}
export interface IGridStyle extends IComponentStyle {    backgroundColor?: Vec4;    ...}

添加组件#

const layout = {    columns: '1 1 1',    rows: '1 1 1',    areas: {        center: { row: 1, column: 1 },    },};
const backgroundColor = new Vec4(0, 146, 255, 255 * 0.75);
export function App() {    return (        <Window>            <Grid style={{ layout }}>                <Grid                    style={{ backgroundColor, area: layout.areas.center }}                ></Grid>            </Grid>        </Window>    );}

这里我们创建了一个 grid,并设置它为 3 行、3 列,也就是说,现在我们的界面相当于一个 3x3 的网格。然后我们在中间那格添加了另一个设置了背景色的格子,运行后界面如下:

add control

rowscolumns分别是为 grid 添加行和列,slice表明这里添加的行、列是成比例的,也就是说,添加的行和列都是 1:1:1,这样可以适应窗口大小变化:

resize

API#

export interface IGridStyle extends IComponentStyle {    ...    layout?: IGridLayout;}
export interface IGridLayout {    /**     * whitespace sperated sizes, eg. "1 50px 100dpx"     *     * 1: slice 1     * 50px: unit is px     * 100dpx: unit is dpx     */    columns?: string;    rows?: string;    areas?: Record<string, IGridArea>;}
export interface IComponentStyle {    area?: IGridArea;    ...}

练习: grid#

这个练习的目的是实现类似 web 中的 24 栅格系统,例如 Ant Design Grid 。在 Ave 中怎样实现如下效果呢?

grid practice grid

练习: offset#

这个练习的目的是实现 grid 的偏移,例如 Ant Design Grid: Offset 。在 Ave 中怎样实现如下效果呢?

grid practice offset

边距#

const layout = {    columns: '1 1 1',    rows: '1 1 1',    areas: {        control: { row: 0, column: 0 },    },};
const backgroundColor = new Vec4(0, 146, 255, 255 * 0.75);
export function App() {    return (        <Window>            <Grid style={{ layout }}>                <Grid                    style={{                        backgroundColor,                        area: layout.areas.control,                        margin: '100dpx 50dpx 0 0',                    }}                ></Grid>            </Grid>        </Window>    );}

在这个例子中,我们设置了蓝色方块的边距,它本身位于窗口的左上角,在设置了左边距和上边距之后,可以发现它不再紧贴窗口边缘:

set margin

API#

export interface IComponentStyle {    ...    margin?: string;}

练习: gutter#

这个练习的目的是实现类似 web 中的 grid gutter,例如 Ant Design Grid: Gutter 。在 Ave 中怎样实现如下效果呢?

grid practice 2

透明度#

要想实现半透明的效果,有两种方式,一种是调整背景颜色的 alpha 值,另一种是设置opacity

const layout = {    columns: "1 1 1 1 1",    rows: "1 1 1 1 1",    areas: {        left: { row: 1, column: 1 },        right: { row: 1, column: 3 },    },};
export function App() {    return (        <Window>            <Grid style={{ layout }}>                <Grid style={{ backgroundColor: new Vec4(0, 146, 255, 255 * 0.25), area: layout.areas.left }}></Grid>                <Grid style={{ backgroundColor: new Vec4(0, 146, 255, 255), area: layout.areas.right, opacity: 0.25 }}></Grid>            </Grid>        </Window>    );}

在这个例子中,我们采取了两种不同的方式,画出了相同效果的半透明蓝色方块。

grid opacity

两种方式的区别如下:

  • opacity:设置整体透明度,包括放在里面的控件全部都会半透明
  • backgroundColor:就只有 grid 本身的背景部分有影响

练习答案#

grid#

练习描述

const colors = {    white: new Vec4(255, 255, 255, 255),    darkBlue: new Vec4(0, 146, 255, 255),    lightBlue: new Vec4(0, 146, 255, 255 * 0.75),};
const layout = {    columns: Array.from<number>({ length: 24 }).fill(1).join(" "),    rows: [50, 25, 50, 25, 50, 25, 50, 25].map((r) => `${r}dpx`).join(" "),    areas: {        _24: { row: 0, column: 0, rowSpan: 1, columnSpan: 24 },        _12_1: { row: 2, column: 0, rowSpan: 1, columnSpan: 12 },        _12_2: { row: 2, column: 12, rowSpan: 1, columnSpan: 12 },        _8_1: { row: 4, column: 0, rowSpan: 1, columnSpan: 8 },        _8_2: { row: 4, column: 8, rowSpan: 1, columnSpan: 8 },        _8_3: { row: 4, column: 16, rowSpan: 1, columnSpan: 8 },        _6_1: { row: 6, column: 0, rowSpan: 1, columnSpan: 6 },        _6_2: { row: 6, column: 6, rowSpan: 1, columnSpan: 6 },        _6_3: { row: 6, column: 12, rowSpan: 1, columnSpan: 6 },        _6_4: { row: 6, column: 18, rowSpan: 1, columnSpan: 6 },    },};
export function App() {    return (        <Window>            <Grid style={{ layout }}>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._24 }}></Grid>                <Grid style={{ backgroundColor: colors.lightBlue, area: layout.areas._12_1 }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._12_2 }}></Grid>                <Grid style={{ backgroundColor: colors.lightBlue, area: layout.areas._8_1 }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._8_2 }}></Grid>                <Grid style={{ backgroundColor: colors.lightBlue, area: layout.areas._8_3 }}></Grid>                <Grid style={{ backgroundColor: colors.lightBlue, area: layout.areas._6_1 }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._6_2 }}></Grid>                <Grid style={{ backgroundColor: colors.lightBlue, area: layout.areas._6_3 }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._6_4 }}></Grid>            </Grid>        </Window>    );}

offset#

练习描述

const colors = {    darkBlue: new Vec4(0, 146, 255, 255),};
const span1 = 8;const offset_11 = 0;const offset_12 = offset_11 + span1 + 8;
const span2 = 6;const offset_21 = 6;const offset_22 = offset_21 + span2 + 6;
const span3 = 12;const offset_3 = 6;
const layout = {    columns: Array.from<number>({ length: 24 }).fill(1).join(" "),    rows: `1 50dpx 25dpx 50dpx 25dpx 50dpx 1`,    areas: {        _11: { row: 1, column: offset_11, rowSpan: 1, columnSpan: span1 },        _12: { row: 1, column: offset_12, rowSpan: 1, columnSpan: span1 },        _21: { row: 3, column: offset_21, rowSpan: 1, columnSpan: span2 },        _22: { row: 3, column: offset_22, rowSpan: 1, columnSpan: span2 },        _3: { row: 5, column: offset_3, rowSpan: 1, columnSpan: span3 },    },};
export function App() {    return (        <Window>            <Grid style={{ layout }}>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._11 }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._12 }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._21 }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._22 }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._3 }}></Grid>            </Grid>        </Window>    );}

gutter#

练习描述

我们使用边距来实现区块间隔的效果:

const colors = {    lightBlue: new Vec4(0, 146, 255, 255 * 0.75),    darkBlue: new Vec4(0, 146, 255, 255),};
const gutter = 50;const margin = `${gutter / 2}dpx 0 ${gutter / 2}dpx 0`;
const layout = {    columns: Array.from<number>({ length: 24 }).fill(1).join(" "),    rows: `1 50dpx 1`,    areas: {        _1: { row: 1, column: 0, rowSpan: 1, columnSpan: 6 },        _2: { row: 1, column: 6, rowSpan: 1, columnSpan: 6 },        _3: { row: 1, column: 12, rowSpan: 1, columnSpan: 6 },        _4: { row: 1, column: 18, rowSpan: 1, columnSpan: 6 },    },};
export function App() {    return (        <Window>            <Grid style={{ layout }}>                <Grid style={{ backgroundColor: colors.lightBlue, area: layout.areas._1, margin }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._2, margin }}></Grid>                <Grid style={{ backgroundColor: colors.lightBlue, area: layout.areas._3, margin }}></Grid>                <Grid style={{ backgroundColor: colors.darkBlue, area: layout.areas._4, margin }}></Grid>            </Grid>        </Window>    );}