You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从抽象SolidShapeBorder继承,让copyWith/scale返回子类实例?

解决方案:无需重复代码实现子类的copyWith和scale

可以实现让子类(如StarBorder)的copyWith和scale返回自身实例,且无需在每个子类中重复编写逻辑。核心思路是在抽象类中定义一个抽象方法,让子类负责返回自身实例,父类复用通用的复制和缩放逻辑。

步骤1:修改抽象类SolidShapeBorder

添加一个抽象方法createInstance,让子类实现该方法来返回自身的实例。然后在copyWith和scale中调用这个方法:

abstract class SolidShapeBorder extends OutlinedBorder {
  const SolidShapeBorder({BorderSide side = BorderSide.none})
      : super(side: side);

  /// 由子类实现,返回当前类型的实例
  SolidShapeBorder createInstance({required BorderSide side});

  /// The aspect ratio of the shape
  double get aspectRatio;

  /// The width of the shape given a certain [height]
  double width(double height) => height / aspectRatio;

  Path _path(Rect size);

  @override
  OutlinedBorder copyWith({BorderSide? side}) {
    return createInstance(side: side ?? this.side);
  }

  @override
  EdgeInsetsGeometry get dimensions => EdgeInsets.all(side.width);

  @override
  Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
    return _path(rect.deflate(side.width));
  }

  @override
  Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
    return _path(rect);
  }

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
    switch (side.style) {
      case BorderStyle.none:
        break;
      case BorderStyle.solid:
        final adjustedRect = rect.deflate(side.width / 2);
        canvas.drawPath(
            _path(adjustedRect),
            Paint()
              ..style = PaintingStyle.stroke
              ..color = side.color
              ..strokeWidth = side.width);
    }
  }

  @override
  ShapeBorder scale(double t) =>
      createInstance(side: side.scale(t));
}

步骤2:实现子类StarBorder

在子类中实现createInstance方法,返回StarBorder的实例即可,无需重写copyWith和scale:

class StarBorder extends SolidShapeBorder {
  const StarBorder({BorderSide side = BorderSide.none}) : super(side: side);

  @override
  double get aspectRatio => 1.0; // 根据实际星星形状调整比例

  @override
  Path _path(Rect size) {
    // 这里实现星星的路径绘制逻辑
    final path = Path();
    // 示例:简单的五角星路径(仅作演示)
    final center = size.center;
    final radius = size.shortestSide / 2;
    for (int i = 0; i < 5; i++) {
      double angle = (i * 144 * pi / 180) - pi / 2;
      double x = center.dx + radius * cos(angle);
      double y = center.dy + radius * sin(angle);
      if (i == 0) {
        path.moveTo(x, y);
      } else {
        path.lineTo(x, y);
      }
    }
    path.close();
    return path;
  }

  @override
  SolidShapeBorder createInstance({required BorderSide side}) {
    return StarBorder(side: side);
  }
}

原理说明

抽象类SolidShapeBorder通过createInstance将实例化的逻辑委托给子类,自身只负责处理copyWith和scale的通用逻辑(替换BorderSide)。这样无论新增多少个子类,都只需要实现createInstance、aspectRatio和_path,无需重复编写复制和缩放的代码。

另外,修复了原paint方法中的硬编码问题:使用side.color和side.width替代固定值,同时调整了绘制的rect范围,避免边框超出形状区域。

内容的提问来源于stack exchange,提问作者UnicornsOnLSD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 12:25:29