AWTK 自定义控件篇
一,前序
之前上一篇文章中简单介绍了 AWTK 本身自带的控件(AWTK系统控件篇),但是实际上我们在写一些复杂的 UI 时候, AWTK 本身的控件其实是不够用的,尤其一些特殊的 UI 。这个时候我们该怎样办呢?
现在就引入我们本章节中的自定义控件篇,我们自定义一些控件,给我们专属的程序使用,但是这些自定义的控件最终还是会接入到 AWTK 的体系中,遵循 AWTK 的消息循环机制,来保证 AWTK 整个逻辑不会乱套了,所以我们的自定义控件,简单的来说就是重载 AWTK 控件的各种虚函数。
二,了解控件结构
在写自定义控件前,先了解一下 AWTK 控件的各种虚表函数指针:
/* awtk/src/base/widget.h 文件 */
struct _widget_vtable_t {
/* 省略了一些成员变量,为了聚焦需要重载的虚表函数 */
widget_create_t create;
widget_get_prop_t get_prop;
widget_set_prop_t set_prop;
widget_invalidate_t invalidate;
widget_find_target_t find_target;
widget_get_prop_default_value_t get_prop_default_value;
widget_on_copy_t on_copy;
widget_on_keyup_t on_keyup;
widget_on_keydown_t on_keydown;
widget_on_wheel_t on_wheel;
widget_on_paint_background_t on_paint_background;
widget_on_paint_self_t on_paint_self;
widget_on_paint_children_t on_paint_children;
widget_on_paint_border_t on_paint_border;
widget_on_paint_begin_t on_paint_begin;
widget_on_paint_end_t on_paint_end;
widget_on_pointer_down_t on_pointer_down;
widget_on_pointer_move_t on_pointer_move;
widget_on_pointer_up_t on_pointer_up;
widget_on_context_menu_t on_context_menu;
widget_on_layout_children_t on_layout_children;
widget_on_add_child_t on_add_child;
widget_on_remove_child_t on_remove_child;
widget_on_attach_parent_t on_attach_parent;
widget_on_detach_parent_t on_detach_parent;
widget_on_event_t on_event;
widget_on_event_before_children_t on_event_before_children;
widget_on_destroy_t on_destroy;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
上面的代码中,我们可以看到一个 widget 中有很多的函数指针,这些函数指针是用来给我们载重对应的触发事件用的,这就是 AWTK 的控件多态性的表现,但是这么多的函数指针,我们是不是要把所有的函数都重载呢?但是不需要,具体重载哪一些函数,就需要看我们实际的用法来决定,下面给出每个重载函数表的定义:
函数指针 | 用途 |
---|---|
create | 控件创建函数指针,一般都会重载,尤其是该控件有自己特有的成员变量的时候。 |
get_prop | 控件获取对应的成员变量的函数指针,一般是获取 UI 中的 XML 定义的特有的成员变量。 |
set_prop | 控件设置对应的成员变量的函数指针,一般是设置 UI 中的 XML 定义的其他特有的成员变量。 |
invalidate | 调用 widget_invalidate 函数(刷新控件)结束后,会触发该函数指针,一般不需要重载。 |
find_target | 在查找焦点是否落在该控件的函数 |
get_prop_default_value | 用来补充 get_prop 的函数指针,一般只重载 set_prop 就足够了。 |
on_copy | 调用 widget_clone 函数(克隆控件)后,会触发该函数指针 |
on_keyup | 当鼠标焦点在该控件中,同时触发鼠标弹起事件后触发该函数指针。 |
on_keydown | 当鼠标焦点在该控件中,同时触发鼠标按下事件后触发该函数指针。 |
on_wheel | 当鼠标焦点在该控件中,同时触发鼠标滚轮事件后触发该函数指针。 |
on_paint_background | 当绘制控件的背景的时候触发该函数指针 |
on_paint_self | 当绘制控件的背景的时候触发该函数指针,同时会取代默认绘制函数,改用该函数指针来绘制。 |
on_paint_children | 当绘制控件的子集对象的时候触发该函数指针,同时会取代默认的函数,改用该函数指针来绘制。 |
on_paint_border | 当绘制控件的边框的时候触发该函数指针,同时会取代默认的函数,改用该函数指针来绘制。 |
on_paint_begin | 当绘制控件之前的时候,触发该函数指针。 |
on_paint_end | 当绘制控件完成后的时候,触发该函数指针。 |
on_pointer_down | 当鼠标(或者触摸屏)点下在该控件中,触发该函数指针。 |
on_pointer_move | 当鼠标(或者触摸屏)在该控件中移动,触发该函数指针。 |
on_pointer_up | 当鼠标(或者触摸屏)弹起在该控件中,触发该函数指针。 |
on_context_menu | 弹出上下文菜单后,触发该函数指针。 |
on_layout_children | 重新布局子控件的时候,触发该函数指针。 |
on_add_child | 添加子控件的时候,触发该函数指针。 |
on_remove_child | 移除子控件的时候,触发该函数指针。 |
on_attach_parent | 当前控件添加到父控件的时候,触发该函数指针。 |
on_detach_parent | 当前控件被父控件移除的时候,触发该函数指针。 |
on_event | 接受各种事件的回调函数,一般都会重载这个函数来接受控件触发的事件。 |
on_event_before_children | 当鼠标按下后,回调查找其子对象前触发该函数指针。 |
on_destroy | 当控件释放后,触发该函数指针,一般是为了释放特有的成员变量的时候才会重载该函数。 |
备注:
- on_keyup 和 on_keydown 是属于窗口管理器直接把按键发给自己才会触发的函数指针,一般我们不用到这么细,所以可以不用理。而 on_pointer_XXXXX 函数指针是鼠标或者触摸事件直接触发的。
- 一般自定义控件都是为了画特有的 UI 为主,所以一般都会重载 on_paint_XXXX 的函数指针为主。
- 如果控件有特有的成员变量,同时希望通过 xml 上面定义后,直接传给控件的话,就可以通过重载 set_prop 和 get_prop 函数来实现。
三,自定义控件代码
这里打算抛砖引玉的做法,写一个简单的自定义控件,大概把上面的讲到的东西融入起来,让大家更加容易明白一点,这次只是简单写一个三角形的按钮控件,由于 AWTK 本身是不提供三角形的按钮,所以这个时候就需要用到自定义控件了,下面是创建自定义控件的步骤:
- 创建 triangle_button.h 文件,并写入下面的代码:
/* triangle_button.h */
#ifndef TK_TRANGLE_BUTTON_H
#define TK_TRANGLE_BUTTON_H
#include "base/widget.h"
BEGIN_C_DECLS
typedef struct _triangle_button_t {
widget_t widget;
/* 标记三角形向左还是向右 /
bool_t is_left;
/ 标记按钮是否按下 */
bool_t pressed;
} triangle_button_t;
/**
- @method triangle_button_create
- 创建triangle_button对象
- @annotation ["constructor", "scriptable"]
- @param {widget_t*} parent 父控件
- @param {xy_t} x x坐标
- @param {xy_t} y y坐标
- @param {wh_t} w 宽度
- @param {wh_t} h 高度
-
- @return {widget_t} 对象。
/
widget_t triangle_button_create(widget_t parent, xy_t x, xy_t y, wh_t w, wh_t h);
/**
- @method triangle_button_cast
- 转换为triangle_button对象(供脚本语言使用)。
- @annotation ["cast", "scriptable"]
- @param {widget_t*} widget triangle_button对象。
-
- @return {widget_t} triangle_button对象。
/
widget_t triangle_button_cast(widget_t widget);
#define WIDGET_TYPE_TRANGLE_BUTTON "triangle_button"
#define WIDGET_PROP_IS_LEFT "is_left"
#define TRANGLE_BUTTON(widget) ((triangle_button_t*)(widget))
END_C_DECLS
#endif /TK_TRANGLE_BUTTON_H/
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 创建 triangle_button.c 文件,并写入下面的代码:
/* triangle_button.c */
#include "tkc/mem.h"
#include "triangle_button.h"
#include "base/widget_vtable.h"
static ret_t triangle_button_on_paint_self(widget_t widget, canvas_t c)
{
/* 不想使用默认的画图方法 */
return RET_OK;
}
/* 因为在风格中定义了背景色,默认的 on_paint_background 函数会根据风格中的 bg_color 或者 fg_color 填充整个控件 /
/ 因为这个控件是想让按钮呈现三角形的样子,所以就选择重载 on_paint_background 函数 /
static ret_t triangle_button_on_paint_background(widget_t widget, canvas_t c)
{
xy_t left_part_x = 0;
xy_t right_part_x = 0;
/ 获取控件风格 /
style_t style = widget->astyle;
color_t trans = color_init(0, 0, 0, 0);
vgcanvas_t vg = canvas_get_vgcanvas(c);
triangle_button_t triangle_button = TRANGLE_BUTTON(widget);
/* 获取风格中设置的 bg_color 颜色值 */
color_t color = style_get_color(style, STYLE_ID_BG_COLOR, trans);
<span class="token function">return_value_if_fail</span><span class="token punctuation">(</span>triangle_button <span class="token operator">!=</span> <span class="token constant">NULL</span><span class="token punctuation">,</span> RET_BAD_PARAMS<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>color<span class="token punctuation">.</span>rgba<span class="token punctuation">.</span>a <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>triangle_button<span class="token operator">-></span>is_left<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
left_part_x <span class="token operator">=</span> widget<span class="token operator">-></span>w<span class="token punctuation">;</span>
right_part_x <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
<span class="token punctuation">{<!-- --></span>
left_part_x <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
right_part_x <span class="token operator">=</span> widget<span class="token operator">-></span>w<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/* 保存之前 vgcanvas 的状态 */</span>
<span class="token function">vgcanvas_save</span><span class="token punctuation">(</span>vg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/* 使用 vgcanvas 来画出三角形的样子 */</span>
<span class="token function">vgcanvas_begin_path</span><span class="token punctuation">(</span>vg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/* 因为 vgcanvas 画图的坐标是绝对坐标,相对整个程序来说的 */</span>
<span class="token comment">/* 而 c->ox 等于控件的获取绝对坐标,y坐标同理 */</span>
<span class="token function">vgcanvas_move_to</span><span class="token punctuation">(</span>vg<span class="token punctuation">,</span> c<span class="token operator">-></span>ox <span class="token operator">+</span> left_part_x<span class="token punctuation">,</span> c<span class="token operator">-></span>oy <span class="token operator">+</span> widget<span class="token operator">-></span>h <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">vgcanvas_line_to</span><span class="token punctuation">(</span>vg<span class="token punctuation">,</span> c<span class="token operator">-></span>ox <span class="token operator">+</span> right_part_x<span class="token punctuation">,</span> c<span class="token operator">-></span>oy<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">vgcanvas_line_to</span><span class="token punctuation">(</span>vg<span class="token punctuation">,</span> c<span class="token operator">-></span>ox <span class="token operator">+</span> right_part_x<span class="token punctuation">,</span> c<span class="token operator">-></span>oy <span class="token operator">+</span> widget<span class="token operator">-></span>h<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">vgcanvas_close_path</span><span class="token punctuation">(</span>vg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/* 设置填充颜色 */</span>
<span class="token function">vgcanvas_set_fill_color</span><span class="token punctuation">(</span>vg<span class="token punctuation">,</span> color<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/* 开始填充 */</span>
<span class="token function">vgcanvas_fill</span><span class="token punctuation">(</span>vg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/* 还原到之前 vgcanvas 的状态 */</span>
<span class="token function">vgcanvas_restore</span><span class="token punctuation">(</span>vg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> RET_OK<span class="token punctuation">;</span>
}
static ret_t triangle_button_get_prop(widget_t widget, const char name, value_t v)
{
triangle_button_t triangle_button = TRANGLE_BUTTON(widget);
return_value_if_fail(widget != NULL && name != NULL && v != NULL, RET_BAD_PARAMS);
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">tk_str_eq</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> WIDGET_PROP_IS_LEFT<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token comment">/* 获取控件中的 is_left 属性 */</span>
<span class="token function">value_set_bool</span><span class="token punctuation">(</span>v<span class="token punctuation">,</span> triangle_button<span class="token operator">-></span>is_left<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> RET_OK<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> RET_NOT_FOUND<span class="token punctuation">;</span>
}
static ret_t triangle_button_set_prop(widget_t widget, const char name, const value_t v)
{
triangle_button_t triangle_button = TRANGLE_BUTTON(widget);
return_value_if_fail(widget != NULL && name != NULL && v != NULL, RET_BAD_PARAMS);
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">tk_str_eq</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> WIDGET_PROP_IS_LEFT<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token comment">/* 根据 UI 的 xml 文件中的属性设置控件中的 is_left 属性 */</span>
triangle_button<span class="token operator">-></span>is_left <span class="token operator">=</span> <span class="token function">value_bool</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> RET_OK<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> RET_NOT_FOUND<span class="token punctuation">;</span>
}
static ret_t triangle_button_on_event(widget_t widget, event_t e)
{
uint16_t type = e->type;
triangle_button_t* triangle_button = TRANGLE_BUTTON(widget);
return_value_if_fail(widget != NULL, RET_BAD_PARAMS);
<span class="token comment">/* 如果鼠标点击在控件上面,会设置其风格状态,让其改变 bg_color 的颜色 */</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>type<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token keyword">case</span> EVT_POINTER_DOWN<span class="token punctuation">:</span> <span class="token punctuation">{<!-- --></span>
triangle_button<span class="token operator">-></span>pressed <span class="token operator">=</span> TRUE<span class="token punctuation">;</span>
<span class="token function">widget_set_state</span><span class="token punctuation">(</span>widget<span class="token punctuation">,</span> WIDGET_STATE_PRESSED<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">widget_grab</span><span class="token punctuation">(</span>widget<span class="token operator">-></span>parent<span class="token punctuation">,</span> widget<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">case</span> EVT_POINTER_UP<span class="token punctuation">:</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">/* 发送点击事件 */</span>
pointer_event_t evt <span class="token operator">=</span> <span class="token operator">*</span><span class="token punctuation">(</span>pointer_event_t<span class="token operator">*</span><span class="token punctuation">)</span>e<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>triangle_button<span class="token operator">-></span>pressed <span class="token operator">&&</span> <span class="token function">widget_is_point_in</span><span class="token punctuation">(</span>widget<span class="token punctuation">,</span> evt<span class="token punctuation">.</span>x<span class="token punctuation">,</span> evt<span class="token punctuation">.</span>y<span class="token punctuation">,</span> FALSE<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
evt<span class="token punctuation">.</span>e <span class="token operator">=</span> <span class="token function">event_init</span><span class="token punctuation">(</span>EVT_CLICK<span class="token punctuation">,</span> widget<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">widget_dispatch</span><span class="token punctuation">(</span>widget<span class="token punctuation">,</span> <span class="token punctuation">(</span>event_t<span class="token operator">*</span><span class="token punctuation">)</span><span class="token operator">&</span>evt<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">case</span> EVT_POINTER_DOWN_ABORT<span class="token punctuation">:</span>
<span class="token keyword">case</span> EVT_POINTER_LEAVE<span class="token punctuation">:</span>
triangle_button<span class="token operator">-></span>pressed <span class="token operator">=</span> FALSE<span class="token punctuation">;</span>
<span class="token function">widget_ungrab</span><span class="token punctuation">(</span>widget<span class="token operator">-></span>parent<span class="token punctuation">,</span> widget<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">widget_set_state</span><span class="token punctuation">(</span>widget<span class="token punctuation">,</span> WIDGET_STATE_NORMAL<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token keyword">default</span><span class="token punctuation">:</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> RET_OK<span class="token punctuation">;</span>
}
static const char* const s_triangle_button_properties[] = { WIDGET_PROP_IS_LEFT, NULL };
const widget_vtable_t g_triangle_button_vtable = {
.size = sizeof(triangle_button_t), /* size 成员变量是给控件开辟内存时候使用的 /
.type = WIDGET_TYPE_TRANGLE_BUTTON, / type 用来获取风格属性用来的 /
.create = triangle_button_create, / 重载 create 函数指针 /
.persistent_properties = s_triangle_button_properties, / 标记永久保存成员变量 /
.on_event = triangle_button_on_event, / 重载 on_event 函数指针 /
.set_prop = triangle_button_set_prop, / 重载 set_prop 函数指针 /
.get_prop = triangle_button_get_prop, / 重载 get_prop 函数指针 /
.on_paint_self = triangle_button_on_paint_self, / 重载 on_paint_self 函数指针 /
.on_paint_background = triangle_button_on_paint_background / 重载 on_paint_background 函数指针 */
};
widget_t triangle_button_create(widget_t parent, xy_t x, xy_t y, wh_t w, wh_t h)
{
widget_t widget = widget_create(parent, &g_triangle_button_vtable, x, y, w, h);
triangle_button_t triangle_button = TRANGLE_BUTTON(widget);
triangle_button<span class="token operator">-></span>pressed <span class="token operator">=</span> FALSE<span class="token punctuation">;</span>
<span class="token keyword">return</span> widget<span class="token punctuation">;</span>
}
widget_t triangle_button_cast(widget_t widget)
{
return_value_if_fail(widget_is_instance_of(widget, &g_triangle_button_vtable), NULL);
<span class="token keyword">return</span> widget<span class="token punctuation">;</span>
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 注册到 AWTK 的控件列表中
/* window_main.c */
ret_t application_init(void)
{
/* 把 triangle_button 控件注册到 awtk 的控件列表中 */
widget_factory_register(widget_factory(), WIDGET_TYPE_TRANGLE_BUTTON, triangle_button_create);
/* ................ */
return RET_OK;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 在 UI 的 XML 中增加该控件
<!-- ui/main.xml -->
<window x="0" y="0" w="100%" h="100%" >
<view x="c" y="m" w="50%" h="50%" >
<triangle_button x="0" y="0" w="50%" h="100%" is_left="true" />
<triangle_button x="50%" y="0" w="50%" h="100%" is_left="false" />
</view>
</window>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 在 style 中增加控件的风格
<!-- style/default.xmll -->
<triangle_button>
<style name="default" >
<normal bg_color="#ff0000" />
<pressed bg_color="#ffff00"/>
<over bg_color="#ff0000" />
</style>
</triangle_button>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
到这里的话,恭喜你可以通过打开 ui/main.xml 的 UI 来看到自定义控件了,如下图效果:
四,总结
自定义控件是用来补充 AWTK 本身没有提供的控件,如果 AWTK 本身就存在这样的控件就没有必要自己重新写一个控件了,用 AWTK 本身的就可以了,上面的三角形按钮控件只是一个抛砖引玉的例子而已,其实自定义控件不单单可以显示不同的 UI, 还可以做到很多不同的功能,比如让子控件位移(如 slide_menu 控件效果)等等很多效果,所以希望大家多点去研究 AWTK 自带的控件,通过 AWTK 自带的控件来更加了解自定义控件的运行机理。
附上上面自定义三角形控件的项目源码 github 地址 (https://github.com/WNsACE/CSDN_AWTK_DEMO/tree/master/awtk_diy_widget_demo)
备注:如果 awtk_diy_widget_demo 项目修改资源后重新编译,可以直接双击项目中的 assets_gen.bat 来编译资源。