【例说Arm-2D界面设计】还在手算坐标?试试LayoutAssistant吧!-深圳pch公司薪酬

常见问题 阅读 111 2025-12-24 21:41:56

【说在前面的话】

在前面的文章中,我们介绍了如何使用

Arm-2D

所提供的场景播放器(

Scene Player

)和场景模板(

Scene

)实现基于面板的图形界面设计范式。

当我们实际开始使用

Arm-2D

进行

2D

图像处理时,几乎所有的API都需要指定目标

Region

。特别是对于那些需要使用

Arm-2D

进行简单UI设计的用户来说,

如何放置图形元素

以及

如何处理屏幕布局

本质上都是一个

Region

计算的问题。

在与开源社区互动的过程中,我注意到

很多朋友仍然在手动计算每个图形元素的起始坐标

,设计出来的

界面往往也缺乏根据屏幕分辨率的不同而做出一定程度自适应的能力

为了让用户摆脱手动计算

Region

的困扰,

Arm-2D

参考了流行的

GUI

布局方法,并提供了一系列简单易用的辅助功能,以宏模板的形式呈现,称为布局助手。

本文将通过示例详细介绍

Arm-2D

布局助手的使用。

【一些重要的基本概念】

这里不妨假设您第一次接触

Arm-2D

,因此为了方便后续的讲解,我们需要首先介绍一些基本概念,例如区域(

Region

)、画布(

Canvas

)、容器(

Container

)等等。

什么是区域(Region)

Region

是一个由位置(

Location

,即左上角坐标)和大小(

Size

)信息描述的矩形区域。

typedef struct arm_2d_region_t {

implement_ex(arm_2d_location_t, tLocation);

implement_ex(arm_2d_size_t, tSize);

} arm_2d_region_t;

上述代码展示了

Region

的结构体定义,其中包含了

Location

Size

的信息,如下图所示:

在这里,

Region

的坐标由位矩形左上角的顶点定义,它的数据结构如下:

typedef struct arm_2d_location_t {

int16_t iX;

int16_t iY;

} arm_2d_location_t;

与一般的笛卡尔坐标系不同,在图形学中,

Y

轴通常是沿相反方向镜像的,这意味着

Y

坐标越小,其值越大。在稍后介绍的“包围盒模型(

Bounding Box Model

)”中,我们会了解到

Region

的坐标可以是负数,表示当前

Region

相对于其父

Region

的起始点的位置。

如上图所示,当

Region

x

y

坐标都为负数时,实际上它有相当大一部分区域在父

Region

的外面(左上角)。当我们尝试获取当前

Region

与其父Region的交集时,会发现只有重叠的部分是有效的。

Region

的尺寸信息由宽度(

Width

)和高度(

Height

)共同描述。数据结构定义如下:

typedef struct arm_2d_size_t {

int16_t iWidth;

int16_t iHeight;

} arm_2d_size_t;

请注意:这里虽然使用了带符号的

int16_t

类型来描述宽度和高度,但是负数是没有意义的,应该避免使用。

什么是包围盒模型(Bounding Box Model)

所谓的包围盒模型描述了

Region

之间的从属关系,通常用于描述容器和可视元素之间的关系。

在GUI堆栈中,包围盒模型通常涉及到更复杂的内容,例如:边框的宽度(

Border Width

)、容器边框内的边距(

Margin

)、容器内元素之间的间距(

Padding

)等等。但是

Arm-2D

并不关心这些细节,它的包围盒模型中只描述容器和其内部元素之间的简单关系。

Arm-2D

中,我们将面板或窗口视为容器,面板和窗口的位置是它们在显示缓冲区中的坐标。我们称这种直接描述显示缓冲区(

Display Buffer

)内坐标的位置信息为

绝对坐标

。下图中,面板(顶层容器)的坐标就是绝对坐标。

容器内部图形元素所使用的坐标是相对于容器左上角来说的,我们将这种坐标称为

相对坐标

。除此之外,如果我们把容器本身也看成是一个图形元素,那么,容器嵌套就是自然而然的事情了。

如果一个

Region

具有绝对坐标,我们就称之为

绝对Region

;类似地,如果一个

Region

具有相对坐标,就称为

相对Region

当我们使用这些相对和绝对信息来进行布局时,

Arm-2D

可以帮助我们轻松地将那些实际上对用户不可见的区域裁减掉,从而提高

2D

处理的整体性能。

什么是画布(Canvas)

Canvas

的本质是

Region

。要在

Tile

上绘制图像,我们需要首先使用

arm_2d_canvas()

创建一个

canvas

。其语法如下:

arm_2d_canvas(<目标Tile的地址>, ) {

/* canvas的作用域 */

}

这里,我们需要向

arm_2d_canvas()

传递两个参数:即

目标Tile的地址

canvas的名称

。这样

arm_2d_canvas()

就会为我们提供的目标

Tile

创建一个我们指定名称的

canvas

注意:这里

arm_2d_canvas()

所生成的

canvas

不能在花括号外使用。

例如:

static

IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)

{

ARM_2D_UNUSED(ptTile); /* 目标屏幕 /

...

arm_2d_canvas(ptTile, __top_canvas) {

/ 在此处放置绘制代码 */

}

arm_2d_op_wait_async(NULL);

return arm_fsm_rt_cpl;

}

上面的代码是一个典型的场景绘制函数,其中

ptTile

指向代表屏幕的目标

Tile

。为了在屏幕上绘图,我们需要为它创建一个

canvas

,即示例中的

__top_canvas

什么是容器(Container)

Region

只是一个描述信息。如何解释

Region

的含义完全取决于我们所使用的API。同样,在使用

Canvas

进行布局时,通常会出现实际的图形元素超出

Canvas

范围的情况。此时,是否对超出的部分进行裁剪则取决于具体所使用的API。

如果我们明确希望将超出

Canvas

范围的部分裁剪掉,则需要引入容器(

Container

)的概念。

Container

的本质是一个

子Tile

,而任何超出

子Tile

矩形范围的部分都将被裁剪。通过宏

arm_2d_container()

我们可以轻松地创建容器,其具体语法如下:

arm_2d_container(<目标Tile的地址>, <新子Tile的名称>, <目标Region的地址>) {

}

这里,我们需要向

arm_2d_container()

函数传递三个参数:即

目标Tile的地址

新子Tile的名称

以及

目标Tile内Region的地址

。这里,

arm_2d_container()

函数不仅会根据给定的目标

Region

为用户定义指定名称的子

Tile

,还会为其自动成相应的

Canvas

(以

__canvas

为后缀)。例如:假设子Tile叫

my_container

,则对应的的

Canvas

将被命名为

my_container_canvas

需要注意的是:

目标

Region

的地址可以为

NULL

。此时子

Tile

与目标

Tile

的大小相同。

arm_2d_container()

所生成的子

Tile

Canvas

不能在花括号外使用。

下面的代码是一段自控件模板的例子:

void control_template_show(user_control_template_t *ptThis,

const arm_2d_tile_t *ptTile,

const arm_2d_region_t *ptRegion,

bool bIsNewFrame)

{

...

arm_2d_container(ptTile, __control, ptRegion) {

/* 在此处放置绘制代码

* - &__control是目标Tile(请不要再使用ptTile了)

* - __control_canvas是Canvas

*/

}

arm_2d_op_wait_async(NULL);

}

在一般的GUI设计中,超出控件矩形区域的部分理所当然需要被裁剪——这就是为什么我们会在控件模板中默认创建一个容器的原因。

【如何进行对齐】

在界面设计中,对齐是最基本的布局方法。在一个给定的矩形区域内,常见的9种对齐方式如图所示:

嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!

无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。

点击这里找小助理0元领取:

加微信领取资料

Arm-2D

为这9种对齐方式提供了风格统一的宏:

这些宏的语法如下:

语法1:

arm_2d_align_(<目标区域:arm_2d_region_t对象>,

<目标区域的宽度:int16_t>,

<目标区域的高度:int16_t>)

{

/* 您可以在大括号内定义的范围内使用名称为___region的区域 */

...

}

这里,我们需要向

arm_2d_align_xxxx()

传递三个参数:即目标

Region

、目标

Region

Width

Height

注意:

这里,我们要传递的是

arm_2d_region_t

对象,而不是该对象的地址。

语法2:

arm_2d_align_xxxx(<目标区域:arm_2d_region_t对象>,

<目标区域的大小:arm_2d_size_t对象>)

{

/* 您可以在大括号内定义的范围内使用名称为___region的区域 */

...

}

这里,我们需要向宏

arm_2d_align_xxxx

传递

两个参数,即目标Region对象和目标Region的大小(arm_2d_size_t)。

注意:

这里我们所要传递的

Region

arm_2d_region_t

类型的对象而不是它的地址;同样,

我们所要传递的Size是

arm_2d_size_t

类型的对象而不是它的地址。

基于上述语法,前面图中的9种对齐方式其代码如下:

static

IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)

{

user_scene_0_t *ptThis = (user_scene_0_t *)pTarget;

ARM_2D_UNUSED(ptTile);

ARM_2D_UNUSED(bIsNewFrame);

arm_2d_canvas(ptTile, __top_canvas) {

arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);

arm_2d_align_top_left(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__top_left_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

arm_2d_align_top_centre(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__top_centre_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

arm_2d_align_top_right(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__top_right_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

arm_2d_align_mid_left(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__mid_left_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

arm_2d_align_centre(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__centre_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

arm_2d_align_mid_right(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__mid_right_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

arm_2d_align_bottom_left(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__bottom_left_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

arm_2d_align_bottom_centre(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__bottom_centre_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

arm_2d_align_bottom_right(__top_canvas, 60, 60 ) {

draw_round_corner_border( ptTile,

&__bottom_right_region,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 255-64, 255-64},

(arm_2d_corner_opacity_t)

{0, 128, 128, 128});

}

}

arm_2d_op_wait_async(NULL);

return arm_fsm_rt_cpl;

}

【如何进行流式布局】

在设计图形界面时,除了上面描述的对齐方式之外,我们通常还会遇到需要将一串图形元素按照某种规则在给定区域内顺次排列的情况,在Arm-2D中,这个过程通常被称为布局(Layout),其中常用的布局规则有两大类:

线性流式布局(Line Stream Layout)

以线性方式(垂直或者水平)顺次布局

流式布局(Stream Layout)

:以行优先或者列优先的方式将元素在整个区域内平铺

在进行布局时,我们只需要列举所有的图形元素,指定每个元素的的大小、间距。在此过程中,由于用户无需手动计算每个元素的坐标,当屏幕分辨率发生变化时,界面也能自动的做出相应的调整,因而在实际的界面开发中大受欢迎。

线性流式布局(Line Stream Layout)

线性流式布局是一种常见的布局方法,它按顺序一个接一个地将元素放置在指定区域内。

如果任何元素超出了给定区域,线性流式布局将不会换行/换列。

水平排列是线性流式布局的一种常见方式,其语法如下:

arm_2d_layout()

{

/* Syntax 1 */

__item_line_horizontal(, )

{

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* Syntax 2 */

__item_line_horizontal()

{

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* more of the __item_line_horizontal segments */

...

}

这里,

arm_2d_layout()

arm_2d_region_t

对象作为目标

Region

,并且

__item_line_horizontal()

必须在

arm_2d_layout()

结构内使用。

我们可以使用任意数量的

__item_line_horizontal()

__item_line_horizontal()

有两个参数:即图形元素的

Width

Height

,或者,你也可以直接传递

arm_2d_size_t

类型的对象作为元素的大小。

注意:

请将

arm_2d_region_t

类型的对象而不是该对象的地址传递给

arm_2d_layout()

在使用

arm_2d_size_t

来描述大小信息时,请直接传递对象而不是它的指针给

__item_line_horizontal()

下图展示了线性流式布局的一个简单示例:将四个按钮顺次水平排列,按钮间无空隙。为了便于观察,我们通过源代码将目标区域用红色标记——这里,我们可以看到第四个按钮实际上超出了目标区域。

对应的源代码如下:

static void draw_buttom(const arm_2d_tile_t *ptTile,

arm_2d_region_t *ptRegion,

const char *pchString,

COLOUR_INT tColour,

uint8_t chOpacity)

{

arm_2d_size_t tTextSize = ARM_2D_FONT_A4_DIGITS_ONLY

.use_as__arm_2d_user_font_t

.use_as__arm_2d_font_t

.tCharSize;

tTextSize.iWidth *= strlen(pchString);

arm_2d_container(ptTile, __button, ptRegion) {

draw_round_corner_border( &__button,

&__button_canvas,

GLCD_COLOR_BLACK,

(arm_2d_border_opacity_t)

{32, 32, 32, 32},

(arm_2d_corner_opacity_t)

{32, 32, 32, 32});

arm_2d_align_centre(__button_canvas, tTextSize) {

arm_lcd_text_set_target_framebuffer((arm_2d_tile_t *)&__button);

arm_lcd_text_set_font((arm_2d_font_t *)&ARM_2D_FONT_A4_DIGITS_ONLY);

arm_lcd_text_set_draw_region(&__centre_region);

arm_lcd_text_set_colour(tColour, GLCD_COLOR_WHITE);

arm_lcd_text_set_opacity(chOpacity);

arm_lcd_printf("%s", pchString);

arm_lcd_text_set_opacity(255);

}

}

}

static

IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)

{

arm_2d_canvas(ptTile, __top_canvas) {

arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);

arm_2d_align_centre(__top_canvas, 100, 100 ) {

/* 用红色标记目标区域 */

arm_2d_helper_draw_box( ptTile,

&__centre_region,

1,

GLCD_COLOR_RED,

128);

arm_2d_op_wait_async(NULL);

arm_2d_layout(__centre_region) {

__item_line_horizontal(28,28) {

draw_buttom(ptTile, &__item_region, "1", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28) {

draw_buttom(ptTile, &__item_region, "2", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28) {

draw_buttom(ptTile, &__item_region, "3", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28) {

draw_buttom(ptTile, &__item_region, "4", GLCD_COLOR_BLUE, 64);

}

}

}

}

arm_2d_op_wait_async(NULL);

return arm_fsm_rt_cpl;

}

如果我想把超出的部分裁减掉,如下图所示:

就应该创建一个

Container

,更新后的代码如下:

static

IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)

{

arm_2d_canvas(ptTile, __top_canvas) {

arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);

arm_2d_align_centre(__top_canvas, 100, 100 ) {

/* 用红色标记目标区域 */

arm_2d_helper_draw_box( ptTile,

&__centre_region,

1,

GLCD_COLOR_RED,

128);

arm_2d_op_wait_async(NULL);

arm_2d_container(ptTile, __panel, &__centre_region) {

arm_2d_layout(__panel_canvas) {

__item_line_horizontal(28,28) {

draw_buttom(&__panel, &__item_region, "1", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28) {

draw_buttom(&__panel, &__item_region, "2", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28) {

draw_buttom(&__panel, &__item_region, "3", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28) {

draw_buttom(&__panel, &__item_region, "4", GLCD_COLOR_BLUE, 64);

}

}

}

}

}

arm_2d_op_wait_async(NULL);

return arm_fsm_rt_cpl;

}

除了基本的尺寸信息外,通过

__item_line_horizontal()

宏我们还可以指定当前元素与上下左右邻居之间的间隔,其语法如下:

arm_2d_layout() {

/* Syntax 1 */

__item_line_horizontal(,

[, , , , ]) {

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* Syntax 2 */

__item_line_horizontal(

[, , , , ]) {

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* more of the __item_line_horizontal segments */

...

}

需要特别注意的是:

虽然这些间距信息(Padding)是可选的参数,但在使用时,四个位置必须同时指定,且顺序不能改变。

下图展示了4个按钮采用不同间距时的效果:

对应的代码如下:

static

IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)

{

arm_2d_canvas(ptTile, __top_canvas) {

arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);

arm_2d_align_centre(__top_canvas, 200, 50 ) {

arm_2d_helper_draw_box( ptTile,

&__centre_region,

1,

GLCD_COLOR_RED,

128);

arm_2d_op_wait_async(NULL);

arm_2d_container(ptTile, __panel, &__centre_region) {

arm_2d_layout(__panel_canvas) {

__item_line_horizontal(28,28) {

draw_buttom(&__panel, &__item_region, "1", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28, 2, 2, 10, 10) {

draw_buttom(&__panel, &__item_region, "2", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28, 10, 10, 20, 20 ) {

draw_buttom(&__panel, &__item_region, "3", GLCD_COLOR_BLUE, 64);

}

__item_line_horizontal(28,28) {

draw_buttom(&__panel, &__item_region, "4", GLCD_COLOR_BLUE, 64);

}

}

}

}

}

arm_2d_op_wait_async(NULL);

return arm_fsm_rt_cpl;

}

纵向的线性流式布局(

Vertical Line Stream Layout

)与横向的线性流式布局(

Horizontal Line Stream Layout

)类似,其语法如下:

arm_2d_layout() {

/* Syntax 1 */

__item_line_vertical(,

[, , , , ]) {

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* Syntax 2 */

__item_line_vertical(

[, , , , ]) {

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* more of the __item_line_vertical segments */

...

}

下图展示了一个纵向线性流式布局的例子:

对应的代码如下:

static

IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)

{

arm_2d_canvas(ptTile, __top_canvas) {

arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);

arm_2d_align_centre(__top_canvas, 120, 120 ) {

arm_2d_helper_draw_box( ptTile,

&__centre_region,

1,

GLCD_COLOR_RED,

128);

arm_2d_op_wait_async(NULL);

arm_2d_layout(__centre_region) {

__item_line_vertical(28, 28, 2, 2, 2, 2) {

draw_buttom(ptTile, &__item_region, "1", GLCD_COLOR_BLUE, 64);

}

__item_line_vertical(28, 28, 2, 2, 2, 2) {

draw_buttom(ptTile, &__item_region, "2", GLCD_COLOR_BLUE, 64);

}

__item_line_vertical(28, 28, 2, 2, 2, 2 ) {

draw_buttom(ptTile, &__item_region, "3", GLCD_COLOR_BLUE, 64);

}

__item_line_vertical(28, 28, 2, 2, 2, 2) {

draw_buttom(ptTile, &__item_region, "4", GLCD_COLOR_BLUE, 64);

}

}

}

}

arm_2d_op_wait_async(NULL);

return arm_fsm_rt_cpl;

}

流式布局(Stream Layout)

与现行流式布局类似,流式布局也很常用,只不过它可以将元素以行优先或者列优先的顺序排满指定的区域。

行优先的流式布局又叫横向流式布局,它的语法如下:

arm_2d_layout() {

/* Syntax 1 */

__item_horizontal(,

[, , , , ]) {

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* Syntax 2 */

__item_horizontal(

[, , , , ]) {

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* more of the __item_horizontal segments */

...

}

流式布局最常见的用途就是实现键盘,比如:

它对应的代码并不复杂:

static

IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)

{

arm_2d_canvas(ptTile, __top_canvas) {

arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);

arm_2d_align_centre(__top_canvas, 96, 128 ) {

arm_2d_helper_draw_box( ptTile,

&__centre_region,

1,

GLCD_COLOR_RED,

128);

arm_2d_op_wait_async(NULL);

arm_2d_layout(__centre_region) {

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "1", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "2", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "3", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "4", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "5", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "6", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "7", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "8", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "9", GLCD_COLOR_BLUE, 64);

}

__item_horizontal(28,28,34,34,2,2) {

draw_buttom(ptTile, &__item_region, "0", GLCD_COLOR_BLUE, 64);

}

}

}

}

arm_2d_op_wait_async(NULL);

return arm_fsm_rt_cpl;

}

值得注意的是:

大部分按钮之间的间距都是2,实际间距就是

2+2=4

为了实现最后一个按钮“0”居中的效果,它与左右的间隔都被设置为了按钮的宽度

+2+2+2

整个键盘的大小是

96*128

纵向优先的流式布局与横向优先类似,其语法如下:

arm_2d_layout() {

/* Syntax 1 */

__item_vertical(,

[, , , , ]) {

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* Syntax 2 */

__item_vertical(

[, , , , ]) {

/* you can use __item_region in the scope defined by the curly braces */

...

}

/* more of the __item_vertical segments */

...

}

作为对比,我们可以将前面的数字键盘改个方向:

虽然看起来怪怪的,但它的确是纵向优先排布的。这里,我们将键盘的尺寸由原先的

96 * 128

调整为了

128 * 96

,并将

__item_horizontal()

替换成了

__item_vertical()

其它几乎保持不变,修改后的代码如下:

static

IMPL_PFB_ON_DRAW(__pfb_draw_scene0_handler)

{

arm_2d_canvas(ptTile, __top_canvas) {

arm_2d_fill_colour(ptTile, NULL, GLCD_COLOR_WHITE);

arm_2d_align_centre(__top_canvas, 128, 96 ) {

arm_2d_helper_draw_box( ptTile,

&__centre_region,

1,

GLCD_COLOR_RED,

128);

arm_2d_op_wait_async(NULL);

arm_2d_layout(__centre_region) {

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "1", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "2", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "3", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "4", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "5", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "6", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "7", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "8", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,2,2) {

draw_buttom(ptTile, &__item_region, "9", GLCD_COLOR_BLUE, 64);

}

__item_vertical(28,28,2,2,34,34) {

draw_buttom(ptTile, &__item_region, "0", GLCD_COLOR_BLUE, 64);

}

}

}

}

arm_2d_op_wait_async(NULL);

return arm_fsm_rt_cpl;

}

【说在后面的话】

Arm-2D不是GUI,只要你的系统资源充足,还是应该避免使用Arm-2D直接进行界面设计。但如果出现下面的情况:

芯片资源(Flash、SRAM等)捉襟见肘,或者留给图形界面的资源非常有限

界面较为简单,可以通过基于面板的图形范式来构筑

交互较为简单(简单的触控或者完全基于实体按钮)

则推荐使用

Arm-2D

来进行界面设计,降低产品整体的成本,同时提最终用户的交互体验。

如果你不幸沦落到要使用

Arm-2D

来进行用户界面设计,也不要灰心,毕竟还有吸收了现代

GUI

设计器精华的

Layout Assistant

来简化我们的工作,将我们从繁重的坐标计算中解放出来,甚至还能在一定程度上实现对不同屏幕分辨率的自适应。

Layout Assistant

虽然主要是以宏来实现的,但我劝你把

这些宏都当做是 Arm-2D图形设计脚本的专用关键字

为妙——不要去深究它们是如何实现的——因为它们是来简化你的设计的,而不是来演示宏是怎样的一种奇技淫巧。

另外,

Layout Assistant 也不是必须的

,你如果不喜欢它,或者无法适应这种由宏所构建的“脚本语言风格”,完全可以丢掉它们。

Arm-2D所有的API都不依赖 Layout Assistant——你完全可以自己计算Region

——怎么舒服怎么来。

转载自:裸机思维

文章来源于【例说Arm-2D界面设计】还在手算坐标?试试Layout Assistant吧!

原文链接:https://mp.weixin.qq.com/s/Tm7BhTJ27gn3R7XMb9ih3w

光学测量仪公司

ogp影像仪怎么样

ogp光学影像测量机

相关内容

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至举报,一经查实,本站将立刻删除。
上一篇: 【你点我检】江西省药监局抽检药品152批均合格-国药108多少钱 下一篇: 【供应链观察】华域汽车应着力提升运营效率-华域汽车股份有限公司

相关资讯