0%

自定义ProxyWidget组件

自定义ProxyWidget组件

业务场景

滑动选择,根据手势判断选中的元素

需求分析

  1. 监听手势滑动
  2. 根据手势位置判断元素是否被选中
  3. 通知子元素做选中UI展示
监听手势滑动

通过GestureDetector包裹识别区域,默认使用:

  • onHorizontalDragStart
  • onHorizontalDragUpdate
  • onHorizontalDragEnd

三个方法,判断此次滑动区域起始点和结束点,以及滑动过程中选中部分。

根据手势位置判断元素是否被选中
  1. 自定义ProxyWidget

    • 标记当前widget标识,当前用下标做标识,方便状态同步。
    • 实现 createElement方法,创建一个ProxyElement 子类;
    • ProxyElement根据unmountmount生命周期,上报父容器元素自身挂载状态。
    • ProxyElement对象提供判断是否在父容器手势范围内,其中用到了renderObject,renderObject是Element的属性(Element>ComponentElement>ProxyElement)
    1
    2
    3
    4
    5
    bool containsOffset(RenderObject? ancestor, Offset offset) {
    final box = renderObject as RenderBox;
    final rect = box.localToGlobal(Offset.zero, ancestor: ancestor) & box.size;
    return rect.contains(offset);
    }
  2. 滑动过程中,获取手势当前位置信息
    在监听手势过程中,手势的回调都会返回position信息。
    _elements即子元素上报统计的集合

1
2
3
4
5
6
7
8
int _findIndexOfSelectable(Offset offset) {
final ancestor = context.findRenderObject();
final element = _elements.firstWhere(
(element) => element!.containsOffset(ancestor, offset),
orElse: () => null,
);
return (element == null) ? -1 : element.widget.index;
}

熟悉一下ProxyWidget常用子类

  1. ParentDataWidget
  2. InheritedWidget
  3. NotificationListener

ProxyWidget和ProxyElement的主要功能

ProxyWidget

  • 实现 createElement方法,创建一个ProxyElement 子类;
  • 定义widget对外属性
  • 提供子类接口
    • 例如InheritedWidgetupdateShouldNotifyInheritedWidget子类需要实现updateShouldNotify,从而决定是否通知重绘等;
    • updateShouldNotify提升到widget层,而不是在Element的notifyClients中判断,是为了让使用者不关注Element层。

ProxyElement

  • 重写notifyClients,用于对旧的数据进行对比,判断是否通知重绘等操作
  • 根据Element的生命周期,实现自定义业务需求。
  • 也可以在ProxyElement添加自定义方法,提供给业务使用。