Flutter-Ink家族

概述

Ink翻译为墨水,墨汁的意思,就是点击某一组件时具有水波纹的效果。Android中MaterialButton中有类似的效果,Flutter中和Ink相关的有Ink、InkWell、InkFeature、Ink.image、InkSplash、InkRipple、InkResponse、InkDecoration、InkHighlight,有些是组件,有些是效果,有些是属性。

Ink

Ink的构造如下:

  Ink({
    Key? key,
    this.padding,
    Color? color,
    Decoration? decoration,
    this.width,
    this.height,
    this.child,
  }) 
复制代码

Ink和Container最大的不同在于使用InkWell时,Ink可以展示点击出现的水波纹的效果,而Contaier没有任何点击效果。除此之外,Ink和Container相似,只是比Container少了一些参数而已,若无明确指明,官方和民间都建议使用Container。Ink一般搭配InkWell使用,主要是设置InkWell的样式。decoration和Container中的decoration一样,使用BoxDecoration就好,若BoxDecoration不是很清楚,可以看看Flutter-Container详解

效果 说明
在这里插入图片描述 没有使用decoration
在这里插入图片描述 使用decoration设置圆角
在这里插入图片描述 使用Container

通过观察效果图可以发现,使用Container确实无法展示InkWell的点击效果。当使用decoration设置圆角的时候,虽然按钮形状是由圆角的,但水波纹扩散的范围依然是矩形,想要使水波纹扩散的范围是圆角矩阵,在InkWell中把borderRadius的圆角弧度设置为和decoration中圆角弧度一致即可。当在decoration中设置了color,InkWell中自带的color就不要设置了,否则报错。

InkWell,InkResponse

class InkWell extends InkResponse {  ...   }
复制代码

InkWell属于完全继承InkResponse,没有一点自己属于自己的属性,只是比InkResponse 少了一些属性,估计那些属性不常用,所以InkWell相对简单,才会导致InkWell使用的比较多,而InkResponse使用的相对较少吧。InkResponse的构造如下:

  const InkResponse({
    Key? key,
    this.child,
    this.onTap,
    this.onTapDown,
    this.onTapCancel,
    this.onDoubleTap,
    this.onLongPress,
    this.onHighlightChanged,
    this.onHover,
    this.mouseCursor,
    this.containedInkWell = false,
    this.highlightShape = BoxShape.circle,
    this.radius,
    this.borderRadius,
    this.customBorder,
    this.focusColor,
    this.hoverColor,
    this.highlightColor,
    this.overlayColor,
    this.splashColor,
    this.splashFactory,
    this.enableFeedback = true,
    this.excludeFromSemantics = false,
    this.focusNode,
    this.canRequestFocus = true,
    this.onFocusChange,
    this.autofocus = false,
  })
复制代码

下表则对属性进行说明:

属性 说明
child 子组件
onTap 点击
onTapDown 按下
onTapCancel 点击取消
onDoubleTap 双击
onLongPress 长按
onHighlightChanged 高亮色变化
onHover 悬停改变
mouseCursor 光标
containedInkWell 范围裁切
highlightShape 高亮色形状
radius 水波纹半径
borderRadius 边框弧度
customBorder 边框
focusColor 焦点色
hoverColor 悬停色
highlightColor 高亮色
overlayColor 覆盖色
splashColor 散点色
splashFactory splash形状
enableFeedback 是否反馈
excludeFromSemantics 是否删除语义
focusNode 焦点结点
canRequestFocus 是否可以请求焦点
onFocusChange 焦点改变
autofocus 自动获取焦点

针对这些属性直接翻译很多不通顺,也不好说清楚,没有效果图直观,下面则对部分属性进行效果展示

  • onTap

点击事件,当用户点击此组件时,onTap会被调用,通常会在onTap中进行点击事件处理。

  • onTapDown

按下动作,准确来讲应该是当用户执行点击动作,手机接触到屏幕的一瞬间,该方法会被调用,通常用来对用户动作进行监听来执行较为复杂的交互,比如特效、游戏、动画、计算等以手机接触为起点。

  • onTapCancel

点击取消,当用户点击在屏幕上,手指还没有离开屏幕,此时又后悔了,不想进行目前的操作了,手指随意滑动一下后松开,该方法会被调用,代表此次点击取消了,无效。

  • onDoubleTap

双击,连续点击两次,时间尽可能短,此时该方法会被调用。

  • onLongPress

长按,手指按下之后在屏幕上停留一段时间,此时该方法会被调用。
-highlightColor 、onHighlightChanged 、highlightShape
当设置高亮色,点击时onHighlightChanged会被调用。

当在InkWell中设置的时候:

在这里插入图片描述

当在InkResponse中设置的时候:

在这里插入图片描述

对比发现,同意属性在不同组件中设置的时候,效果不同。highlightShape默认为BoxShape.circle,也可以选择BoxShape.rectangle,当InkResponse中设置BoxShape.rectangle时效果如下:
在这里插入图片描述

效果和InkWell类似,因为InkWell的highlightShape(InkWell中该属性不可设置)为BoxShape.rectangle,而InkResponse的highlightShape默认为BoxShape.circle,效果的差异主要是BoxShape形状的差异。

  • hoverColor,onHover

悬停状态是由用户使用光标在交互式元素上暂停时发起的。它们可以应用于所有的交互组件,并且应该被淡化以避免从内容上分散注意力。它可以应用于整个组件、组件内的元素,或者作为组件部分上的圆形形状。悬停状态可以由以下组件继承:按钮、切换按钮、选择控件、网格列表项、列表项、卡片、芯片、文本字段和图标。这里还没有设置出明显的效果所以无法展示,后续还需仔细研究。

  • mouseCursor

光标样式,这里默认为MaterialStateMouseCursor.clickable,当然还有MaterialStateMouseCursor.textable供选择,主要是一个是点击光标,一个是文本光标。

  • splashColor,splashFactory

在InkWell中设置splashColor为Colors.red时,splashFactory 不同效果不同:

属性 效果
InkSplash.splashFactory 在这里插入图片描述
InkRipple.splashFactory 在这里插入图片描述

InkSplash.splashFactory 和InkRipple.splashFactory不同之处可能在于水波纹的开始及结束状态。

  • containedInkWell

InkWill中不可设置该属性,但是在继承InkResponse时被设置为true,InkResponse中默认为false:

属性 效果
true 在这里插入图片描述
false 在这里插入图片描述

containedInkWell 设为true时,超出容器的水波纹会被裁剪,false的时候不会被裁剪。

  • radius,borderRadius

当水波纹为圆形的时候,radius为水波纹半径。borderRadius为InkWell或InkResponse的边框圆角,当设置后水波纹扩散有角的地方,会被才切成有弧度的,而不是以直角的显示:

属性 效果
radius: 22.0 在这里插入图片描述
radius: 66.0 在这里插入图片描述
borderRadius: BorderRadius.circular(16.0),radius: 66.0 在这里插入图片描述

radius值不同,水波纹的半径是有区别的。borderRadius需要仔细观察第二幅和第三幅图,在点击的时候,四角是否有灰色的直角背景显示出来,如果有就没有设置,如果没有就是设置了。

  • customBorder

边框。

  • overlayColor

覆盖层颜色,覆盖层是指元素上显示其状态的半透明覆盖层。overlay提供了一种使用不透明度来可视化状态的系统方法。一个覆盖层可以应用到整个元素或在一个圆形的形状。覆盖颜色与它所应用的元素上的文本或图标的颜色相匹配。如果文本或图标在状态改变期间改变颜色,覆盖层应该匹配结束状态的颜色。一次只应用一个状态层。例如,如果一个元素首先被聚焦然后被悬停,悬停状态层将只显示悬停完成,然后返回到焦点状态层如果元素仍然被聚焦。详细效果还没有弄出来。

  • enableFeedback

默认为false,没有反馈,有时点击按钮需要手机震动一下,就是这个意思。

  • focusNode,canRequestFocus ,onFocusChange ,autofocus

这些都是字面意思,不需要什么解释。

InkFeature、Ink.image、InkSplash、InkRipple、InkDecoration、InkHighlight

  • InkDecoration继承自InkFeature,在Ink中进行装饰。
    if (_ink == null) {
      _ink = InkDecoration(
        decoration: widget.decoration,
        configuration: createLocalImageConfiguration(context),
        controller: Material.of(context)!,
        referenceBox: context.findRenderObject()! as RenderBox,
        onRemoved: _handleRemoved,
      );
    } else {
      _ink!.decoration = widget.decoration;
      _ink!.configuration = createLocalImageConfiguration(context);
    }
复制代码

InkDecoration直接将Ink中设置的decoration进一步包装,添加一些配置。

  • Ink.image

Ink.image是decoraton中配置的一种,用于给Ink装饰图片。

  Ink.image({
    Key? key,
    this.padding,
    required ImageProvider image,
    ImageErrorListener? onImageError,
    ColorFilter? colorFilter,
    BoxFit? fit,
    AlignmentGeometry alignment = Alignment.center,
    Rect? centerSlice,
    ImageRepeat repeat = ImageRepeat.noRepeat,
    bool matchTextDirection = false,
    this.width,
    this.height,
    this.child,
  })
复制代码

观察发现,Ink.image和BoxDecoration中的image指定的DecorationImage是一模一样,用法也一样。若不太清楚,可以参考Flutter-Container详解

  • InkSplash、InkRipple、InkHighlight

InkSplash、InkRipple、InkHighlight都是继承自InteractiveInkFeature,而InteractiveInkFeature继承自InkFeature,所以InkSplash、InkRipple和InkDecoration都是属于Ink装饰。以InkRipple.splashFactory为例

class _InkRippleFactory extends InteractiveInkFeatureFactory {
  const _InkRippleFactory();
  
  @override
  InteractiveInkFeature create({
    required MaterialInkController controller,
    required RenderBox referenceBox,
    required Offset position,
    required Color color,
    required TextDirection textDirection,
    bool containedInkWell = false,
    RectCallback? rectCallback,
    BorderRadius? borderRadius,
    ShapeBorder? customBorder,
    double? radius,
    VoidCallback? onRemoved,
  }) {
    return InkRipple(
      controller: controller,
      referenceBox: referenceBox,
      position: position,
      color: color,
      containedInkWell: containedInkWell,
      rectCallback: rectCallback,
      borderRadius: borderRadius,
      customBorder: customBorder,
      radius: radius,
      onRemoved: onRemoved,
      textDirection: textDirection,
    );
  }
}
...
  /// Used to specify this type of ink splash for an [InkWell], [InkResponse]
  /// or material [Theme].
  static const InteractiveInkFeatureFactory splashFactory = _InkRippleFactory();
  ...
复制代码

所以InkSplash、InkRipple是上文中提到的InkSplash.splashFactory 和InkRipple.splashFactory工厂具体实现。
工厂模式就是定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行,主要解决接口选择的问题,是 Java 中最常用的设计模式之一。在任何需要生成复杂对象的地方,都可以使用工厂方法模式。复杂对象适合使用工厂模式,而简单对象只需简单通过构造创建对象即可,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

Flutter中IButton、BottomNavigationBar、CalendarDatePicker、DataTable、NavigationRail、Stepperden等使用了InkResponse或InkWell,所以很多组件也有水波纹效果。

文中有一些错误、遗漏和不准确,欢迎批评指正。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享