# 在自定义控件中使用 offset 的注意事项

当用户自己写自定义控件的时候,如果需要该自定义控件实现滚动效果效果的时候,此时需要引入一个 offset 的概念(水平方向用 xoffset,垂直方向用 yoffset),在控件中通过 offset 的变化来移动控件的子控件的位置到指定的区域中显示,从而达到滚动效果。(比如:每个子控件的 y 属性都根据 offset 来计算出来,那么 offset 改变了,那么每个子控件的 y 坐标都改变了,从而决定子控件显示的位置。)

同时 AWTK 的点击事件(鼠标或者触摸)都会受到控件的 offset 影响,所以 AWTK 提供了两个机会给控件把这个 offset 的数据传递给 AWTK:

方法 备注
作为属性通过 get_prop 或者 set_prop 方便外部动画等操作修改和读取属性
注册控件的 get_offset 函数指针 只能读取 offset 的数据

注意:如果两个方法一起使用的话,一定要注意的是获取的 offset 要保持一致。

# 1. 子控件显示问题

一般滚动效果都是为了存放更多的子控件,但是在 AWTK 显示子控件有三种方式:

  1. 在 on_paint_children 回调函数中,通过 offset 来把有需要的显示控件移动到父控件的显示区域中,而不需要显示的子控件会被移动到父控件显示区域外面,所以每个子控件的坐标未必是按照真实的布局来摆放的。
  2. 子控件是真实的控件布局,每个子控件都是按照父控件的虚拟空间中做真实的布局,然后通过 offset 来设置画布的偏移坐标,来实现真实的布局子控件正确显示到屏幕上面。

这两种方式都是可以正确的显示出来子控件,但是区别在于有没有真实的布局子控件。

如果只是为了显示,其子控件不需要接收点击事件(鼠标或者触摸)的话,直接使用功能第一种方式的话,比较简单快速。

但是如果需要子控件也接收到来自 AWTK 的消息事件的话,最好采用第二种方式来实现了(请查看 AWTK 的 scroll_view 的实现源码)

# 2. 受到 offset 影响的 API 以及问题

offset 会影响 AWTK 内部的 API 甚至会影响内部执行逻辑,从而导致一些消息事件的转发不正常和绘图不正常的问题。

API 影响
widget_to_screen 转化为屏幕坐标时候出错
widget_to_local 转化为控件坐标时候出错,导致无法通过坐标查找到具体的控件或者子控件
widget_invalidate_default 导致出现残影或者控件被裁剪到了

# 3. 总结

如果使用 offset 的话,尽量使用上面说的第二种方法来实现,这样可以减少很多问题,如果实在不行的话,可以通过重载 find_target 和 is_point_in 函数来处理,但是这样子也是把问题变复杂了。