flutter 在尖圆的地方抖动油漆箭头

ngynwnxp  于 2023-11-21  发布在  Flutter
关注(0)|答案(3)|浏览(180)

我想要一个CustomPainter,它画一个三角形,顶部边缘有点圆,像这样:


的数据
我可以用这个画一个三角形:

class CustomStyleArrow extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()
      ..color = Colors.white
      ..strokeWidth = 1
      ..style = PaintingStyle.fill;
    final double triangleH = 10;
    final double triangleW = 25.0;
    final double width = size.width;
    final double height = size.height;

    final Path trianglePath = Path()
      ..moveTo(width / 2 - triangleW / 2, height)
      ..lineTo(width / 2, triangleH + height)
      ..lineTo(width / 2 + triangleW / 2, height)
      ..lineTo(width / 2 - triangleW / 2, height);
    canvas.drawPath(trianglePath, paint);
    final BorderRadius borderRadius = BorderRadius.circular(15);
    final Rect rect = Rect.fromLTRB(0, 0, width, height);
    final RRect outer = borderRadius.toRRect(rect);
    canvas.drawRRect(outer, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}

字符串
但是我不能得到圆角。我怎么能做到这一点?
另外,整个三角形应该尽可能动态,这样我就可以把它放在任何容器的顶部,最好的情况下,也传递位置,三角形应该在哪里。

zbdgwd5y

zbdgwd5y1#

1.首先,你不必自己绘制你的自定义油漆。事实上,实现复杂的绘图几乎是不可能的。相反,在这里,你可以使用这个Web应用程序,你可以在其中绘制你的绘画并导出它们的代码; Flutter Shape Maker。越来越漂亮的是,你可以在该应用程序中导入任何SVG文件,并将其代码导出为Dart File。这真的很完美!
1.在这里,我分享的图片,你可以按照
x1c 0d1x的数据
然后



注意:确保您选择了响应。这样,您可以在CustomPainter小部件中调整任何SVG文件的大小
1.让我们来看看你的问题。在这里,我选择了一个SVG文件为您的需要。(以后,你可以改变它根据您的愿望)

<svg width="800px" height="800px" viewBox="0 0 24 24" id="meteor-icon-kit__solid-triangle" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M13.7889 1.57769L23.5528 21.1056C24.0468 22.0935 23.6463 23.2949 22.6584 23.7888C22.3806 23.9277 22.0744 24 21.7639 24H2.23607C1.1315 24 0.236069 23.1046 0.236069 22C0.236069 21.6895 0.308359 21.3833 0.447214 21.1056L10.2111 1.57769C10.7051 0.589734 11.9065 0.189285 12.8944 0.683263C13.2815 0.876791 13.5953 1.19064 13.7889 1.57769Z" fill="#758CA3"/></svg>

字符串
1.我对上面的web应用程序做了导入和导出操作,结果如下:

class ArrowPaint extends CustomPainter {
      final Color color;
    
      ArrowPaint({required this.color});
    
      @override
      void paint(Canvas canvas, Size size) {
        Path path_0 = Path();
        path_0.moveTo(size.width * 0.5745375, size.height * 0.06573708);
        path_0.lineTo(size.width * 0.9813667, size.height * 0.8794000);
        path_0.cubicTo(
            size.width * 1.001950,
            size.height * 0.9205625,
            size.width * 0.9852625,
            size.height * 0.9706208,
            size.width * 0.9441000,
            size.height * 0.9912000);
        path_0.cubicTo(
            size.width * 0.9325250,
            size.height * 0.9969875,
            size.width * 0.9197667,
            size.height,
            size.width * 0.9068292,
            size.height);
        path_0.lineTo(size.width * 0.09316958, size.height);
        path_0.cubicTo(
            size.width * 0.04714583,
            size.height,
            size.width * 0.009836208,
            size.height * 0.9626917,
            size.width * 0.009836208,
            size.height * 0.9166667);
        path_0.cubicTo(
            size.width * 0.009836208,
            size.height * 0.9037292,
            size.width * 0.01284829,
            size.height * 0.8909708,
            size.width * 0.01863392,
            size.height * 0.8794000);
        path_0.lineTo(size.width * 0.4254625, size.height * 0.06573708);
        path_0.cubicTo(
            size.width * 0.4460458,
            size.height * 0.02457225,
            size.width * 0.4961042,
            size.height * 0.007886875,
            size.width * 0.5372667,
            size.height * 0.02846929);
        path_0.cubicTo(
            size.width * 0.5533958,
            size.height * 0.03653296,
            size.width * 0.5664708,
            size.height * 0.04961000,
            size.width * 0.5745375,
            size.height * 0.06573708);
        path_0.close();
    
        Paint paint_0_fill = Paint()..style = PaintingStyle.fill;
        paint_0_fill.color = color;
        canvas.drawPath(path_0, paint_0_fill);
      }
    
      @override
      bool shouldRepaint(covariant CustomPainter oldDelegate) {
        return true;
      }
    }


1.我创建了一个名为TextCloud的Widget;

class TextCloud extends StatelessWidget {
      final String text; // write here box content
      final Color color; // Set box Color
      final EdgeInsets padding; // Set content padding
      final double width; // Box width
      final double height; // Box Height
      final AxisDirection axisDirection; // Set triangle location up,left,right,down
      final double locationOfArrow; // set between 0 and 1, If 0.5 is set triangle position will be centered
      const TextCloud({
        super.key,
        required this.text,
        this.color = Colors.white,
        this.padding = const EdgeInsets.all(10),
        this.width = 200,
        this.height = 100,
        this.axisDirection = AxisDirection.down,
        this.locationOfArrow = 0.5,
      });
    
      @override
      Widget build(BuildContext context) {
        Size arrowSize = const Size(25, 25);
        return Stack(
          clipBehavior: Clip.none,
          children: [
            Container(
              width: width,
              height: height,
              padding: padding,
              decoration: BoxDecoration(
                color: color,
                borderRadius: BorderRadius.circular(5),
              ),
              child: Text(text),
            ),
            Builder(builder: (context) {
              double angle = 0;
              switch (axisDirection) {
                case AxisDirection.left:
                  angle = pi * -0.5;
                  break;
                case AxisDirection.up:
                  angle = pi * -2;
                  break;
                case AxisDirection.right:
                  angle = pi * 0.5;
                  break;
                case AxisDirection.down:
                  angle = pi;
                  break;
                default:
                  angle = 0;
              }
              return Positioned(
                left: axisDirection == AxisDirection.left
                    ? -arrowSize.width + 5
                    : (axisDirection == AxisDirection.up ||
                            axisDirection == AxisDirection.down
                        ? width * locationOfArrow - arrowSize.width / 2
                        : null),
                right: axisDirection == AxisDirection.right
                    ? -arrowSize.width + 5
                    : null,
                top: axisDirection == AxisDirection.up
                    ? -arrowSize.width + 5
                    : (axisDirection == AxisDirection.right ||
                            axisDirection == AxisDirection.left
                        ? height * locationOfArrow - arrowSize.width / 2
                        : null),
                bottom: axisDirection == AxisDirection.down
                    ? -arrowSize.width + 5
                    : null,
                child: Transform.rotate(
                  angle: angle,
                  child: CustomPaint(
                    size: arrowSize,
                    painter: ArrowPaint(color: color),
                  ),
                ),
              );
            })
          ],
        );
      }
    }


1.然后,使用它TextCloud(text: "Big Bang Theory is the best TV sitcom ever!")
结果;

TextCloud(
  text: "Big Bang Theory is the best TV sitcom ever!",
  axisDirection: AxisDirection.down,
  locationOfArrow: 0.5,
)

TextCloud(
  text: "Big Bang Theory is the best TV sitcom ever!",
  axisDirection: AxisDirection.left,
  locationOfArrow: 0.25,
)

祝你好运

kulphzqa

kulphzqa2#

下面是我如何设法创建上述使用自定义油漆
首先定义一个自定义的painter类,就像我下面所做的那样

class buttonBackground extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    double sw = size.width;
    double sh = size.height;
    var paint = Paint();
    Path greyWave = Path();
    greyWave.lineTo((sw * .5) - 20, 0);
    //The value 8 represent the amount of curve you can update to make it more or less rounded
    greyWave.conicTo(sw * .5, -30, (sw * .5) + 20, 0, 8);
    greyWave.close();
    paint.color = Colors.blue.shade200;
    canvas.drawPath(greyWave, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return oldDelegate != this;
  }
}

字符串
这就是你将如何实现它。

CustomPaint(
      painter: buttonBackground(),
      child: Container(
        height: 250,
        width: 250,
        decoration: BoxDecoration(
            color: Colors.green,
            borderRadius: BorderRadius.all(Radius.circular(20))),
      ),
    ),
  )


上面的代码应该会给给予一个指针,指向任何用它 Package 的小部件。
这是输出,谢谢。


的数据

vaqhlq81

vaqhlq813#

从k.spoyraz那里得到灵感,我得到了一个完美的解决方案,你可以用ArrowIndicator Package 任何小部件,并将箭头放在你想要的地方:

import 'dart:math';

import 'package:bling_ui/extensions/build_context.dart';
import 'package:flutter/material.dart';

class ArrowIndicator extends StatefulWidget {
  final Widget child;

  /// Set triangle location up,left,right,down
  final AxisDirection axisDirection;

  /// Position of the arrow between 0 and 1, where 0.5 is centered.
  final double fractionalPosition;

  /// Height of the arrow when axisDirection is AxisDirection.up or AxisDirection.down.
  final double height;

  final Color? color;

  const ArrowIndicator({
    super.key,
    required this.child,
    this.axisDirection = AxisDirection.down,
    this.fractionalPosition = 0.5,
    this.height = 30,
    this.color,
  });

  @override
  State<ArrowIndicator> createState() => _ArrowIndicatorState();
}

class _ArrowIndicatorState extends State<ArrowIndicator> {
  // Without this the arrow would be right on the edge of its child and since all corners of the arrow
  // are rounded, it looks cleaner if the child slightly overlaps with the arrow.
  late double extraSmoothness;
  // This is taken from the triangle_rounded_corners_up.svg height and width.
  final double arrowAspectRatio = 51 / 30;

  final key = GlobalKey();
  Size childSize = const Size(0, 0);

  late double angle;

  @override
  void initState() {
    extraSmoothness = widget.height * 0.2;

    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {
        childSize = getChildSize(key.currentContext!);
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final arrowSize = Size(
      arrowAspectRatio * widget.height,
      widget.height,
    );
    initAngle();

    return Stack(
      children: [
        _buildArrow(arrowSize, context),
        Container(
          color: Colors.transparent,
          key: key,
          padding: childPaddingToMakeArrowVisible(),
          child: widget.child,
        ),
      ],
    );
  }

  Positioned _buildArrow(Size arrowSize, BuildContext context) {
    return Positioned(
      left: widget.axisDirection == AxisDirection.left
          // You can not simply take 0 here since the rotation messes up the width
          ? -(arrowSize.width - arrowSize.height) / 2 + extraSmoothness
          : (widget.axisDirection == AxisDirection.up ||
                  widget.axisDirection == AxisDirection.down
              ? childSize.width * widget.fractionalPosition -
                  arrowSize.width / 2
              : null),
      right: widget.axisDirection == AxisDirection.right
          // You can not simply take 0 here since the rotation messes up the width
          ? -(arrowSize.width - arrowSize.height) / 2 + extraSmoothness
          : null,
      top: widget.axisDirection == AxisDirection.up
          ? extraSmoothness
          : (widget.axisDirection == AxisDirection.right ||
                  widget.axisDirection == AxisDirection.left
              ? childSize.height * widget.fractionalPosition -
                  arrowSize.width / 2
              : null),
      bottom:
          widget.axisDirection == AxisDirection.down ? extraSmoothness : null,
      child: Transform.rotate(
        angle: angle,
        child: context.icons.triangleRoundedCornersUpSVG.copyWith(
          color: widget.color,
          height: arrowSize.height,
          width: arrowSize.width,
        ),
      ),
    );
  }

  Size getChildSize(BuildContext context) {
    final box = context.findRenderObject() as RenderBox;
    return box.size;
  }

  void initAngle() {
    switch (widget.axisDirection) {
      case AxisDirection.left:
        angle = pi * -0.5;
        break;
      case AxisDirection.up:
        angle = pi * -2;
        break;
      case AxisDirection.right:
        angle = pi * 0.5;
        break;
      case AxisDirection.down:
        angle = pi;
        break;
    }
  }

  EdgeInsets childPaddingToMakeArrowVisible() {
    switch (widget.axisDirection) {
      case AxisDirection.up:
        return EdgeInsets.only(top: widget.height);
      case AxisDirection.right:
        return EdgeInsets.only(right: widget.height);
      case AxisDirection.down:
        return EdgeInsets.only(bottom: widget.height);
      case AxisDirection.left:
        return EdgeInsets.only(left: widget.height);
    }
  }
}

字符串

相关问题