如何在Flutter中添加破折号

Bad*_*iat 6 flutter flutter-layout

像这样在Flutter中如何使虚线破折号?

图片

Ant*_*nko 23

class DashedLinePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    double dashWidth = 9, dashSpace = 5, startX = 0;
    final paint = Paint()
      ..color = Colors.grey
      ..strokeWidth = 1;
    while (startX < size.width) {
      canvas.drawLine(Offset(startX, 0), Offset(startX + dashWidth, 0), paint);
      startX += dashWidth + dashSpace;
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}
Run Code Online (Sandbox Code Playgroud)

  • 像 CustomPaint(painter: DashedLinePainter()); 一样使用它 (8认同)

hnn*_*lch 19

以下代码不仅为线条创建虚线路径,而且为任何想要虚线的路径创建虚线路径。

演示:

在此输入图像描述

这个想法是originalPath沿着它移动,交替添加破折号和间隙,直到提取整个路径:

Path _getDashedPath(
  Path originalPath,
  double dashLength,
  double dashGapLength,
) {
  final metricsIterator = originalPath.computeMetrics().iterator;
  while (metricsIterator.moveNext()) {
    final metric = metricsIterator.current;
    _dashedPathProperties.extractedPathLength = 0.0;
    while (_dashedPathProperties.extractedPathLength < metric.length) {
      if (_dashedPathProperties.addDashNext) {
        _dashedPathProperties.addDash(metric, dashLength);
      } else {
        _dashedPathProperties.addDashGap(metric, dashGapLength);
      }
    }
  }
  return _dashedPathProperties.path;
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个类DashedPathProperties来跟踪 currentextractedPathLength或 the 等内容_remainingDashLength,如果originalPath包含多个子路径并且必须在下一个子路径上继续使用破折号(或破折号间隙),则该类将变得相关:

class DashedPathProperties {
  double extractedPathLength;
  Path path;

  final double _dashLength;
  double _remainingDashLength;
  double _remainingDashGapLength;
  bool _previousWasDash;

  DashedPathProperties({
    required this.path,
    required double dashLength,
    required double dashGapLength,
  })  : assert(dashLength > 0.0, 'dashLength must be > 0.0'),
        assert(dashGapLength > 0.0, 'dashGapLength must be > 0.0'),
        _dashLength = dashLength,
        _remainingDashLength = dashLength,
        _remainingDashGapLength = dashGapLength,
        _previousWasDash = false,
        extractedPathLength = 0.0;

  //...
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用(如果你想确保画家不能在边界之外绘画,你可以将你的CustomPaint包裹起来):ClipRect

CustomPaint(
  painter: DashedPathPainter(
    originalPath: Path()
      ..addOval(
        const Rect.fromLTWH(0, 0, 100, 100),
      ),
    pathColor: Colors.white,
  ),
  size: const Size(100.0, 100.0),
)
Run Code Online (Sandbox Code Playgroud)

您可以在 DartPad 中运行的完整示例代码:

import 'dart:ui' as ui;
import 'dart:math' as math;

import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: const Scaffold(
        body: Center(
          child: ExampleDashedPath(),
        ),
      ),
    );
  }
}

class ExampleDashedPath extends StatelessWidget {
  const ExampleDashedPath({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const SizedBox(height: 50),
        CustomPaint(
          painter: DashedPathPainter(
            originalPath: Path()..lineTo(100, 0),
            pathColor: Colors.red,
            strokeWidth: 5.0,
            dashGapLength: 10.0,
            dashLength: 10.0,
          ),
          size: const Size(100.0, 2.0),
        ),
        const SizedBox(height: 50),
        CustomPaint(
          painter: DashedPathPainter(
            originalPath: Path()
              ..addOval(
                const Rect.fromLTWH(0, 0, 100, 100),
              ),
            pathColor: Colors.white,
          ),
          size: const Size(100.0, 100.0),
        ),
        const SizedBox(height: 50),
        CustomPaint(
          painter: DashedPathPainter(
            originalPath: Path()
              ..addRect(
                const Rect.fromLTWH(0, 0, 100, 100),
              )
              ..lineTo(100, 100),
            pathColor: Colors.grey,
            strokeWidth: 2.0,
            dashLength: 25.0,
          ),
          size: const Size(100.0, 100.0),
        ),
      ],
    );
  }
}

class DashedPathPainter extends CustomPainter {
  final Path originalPath;
  final Color pathColor;
  final double strokeWidth;
  final double dashGapLength;
  final double dashLength;
  late DashedPathProperties _dashedPathProperties;

  DashedPathPainter({
    required this.originalPath,
    required this.pathColor,
    this.strokeWidth = 3.0,
    this.dashGapLength = 5.0,
    this.dashLength = 10.0,
  });

  @override
  void paint(Canvas canvas, Size size) {
    _dashedPathProperties = DashedPathProperties(
      path: Path(),
      dashLength: dashLength,
      dashGapLength: dashGapLength,
    );
    final dashedPath = _getDashedPath(originalPath, dashLength, dashGapLength);
    canvas.drawPath(
      dashedPath,
      Paint()
        ..style = PaintingStyle.stroke
        ..color = pathColor
        ..strokeWidth = strokeWidth,
    );
  }

  @override
  bool shouldRepaint(DashedPathPainter oldDelegate) =>
      oldDelegate.originalPath != originalPath ||
      oldDelegate.pathColor != pathColor ||
      oldDelegate.strokeWidth != strokeWidth ||
      oldDelegate.dashGapLength != dashGapLength ||
      oldDelegate.dashLength != dashLength;

  Path _getDashedPath(
    Path originalPath,
    double dashLength,
    double dashGapLength,
  ) {
    final metricsIterator = originalPath.computeMetrics().iterator;
    while (metricsIterator.moveNext()) {
      final metric = metricsIterator.current;
      _dashedPathProperties.extractedPathLength = 0.0;
      while (_dashedPathProperties.extractedPathLength < metric.length) {
        if (_dashedPathProperties.addDashNext) {
          _dashedPathProperties.addDash(metric, dashLength);
        } else {
          _dashedPathProperties.addDashGap(metric, dashGapLength);
        }
      }
    }
    return _dashedPathProperties.path;
  }
}

class DashedPathProperties {
  double extractedPathLength;
  Path path;

  final double _dashLength;
  double _remainingDashLength;
  double _remainingDashGapLength;
  bool _previousWasDash;

  DashedPathProperties({
    required this.path,
    required double dashLength,
    required double dashGapLength,
  })  : assert(dashLength > 0.0, 'dashLength must be > 0.0'),
        assert(dashGapLength > 0.0, 'dashGapLength must be > 0.0'),
        _dashLength = dashLength,
        _remainingDashLength = dashLength,
        _remainingDashGapLength = dashGapLength,
        _previousWasDash = false,
        extractedPathLength = 0.0;

  bool get addDashNext {
    if (!_previousWasDash || _remainingDashLength != _dashLength) {
      return true;
    }
    return false;
  }

  void addDash(ui.PathMetric metric, double dashLength) {
    // Calculate lengths (actual + available)
    final end = _calculateLength(metric, _remainingDashLength);
    final availableEnd = _calculateLength(metric, dashLength);
    // Add path
    final pathSegment = metric.extractPath(extractedPathLength, end);
    path.addPath(pathSegment, Offset.zero);
    // Update
    final delta = _remainingDashLength - (end - extractedPathLength);
    _remainingDashLength = _updateRemainingLength(
      delta: delta,
      end: end,
      availableEnd: availableEnd,
      initialLength: dashLength,
    );
    extractedPathLength = end;
    _previousWasDash = true;
  }

  void addDashGap(ui.PathMetric metric, double dashGapLength) {
    // Calculate lengths (actual + available)
    final end = _calculateLength(metric, _remainingDashGapLength);
    final availableEnd = _calculateLength(metric, dashGapLength);
    // Move path's end point
    ui.Tangent tangent = metric.getTangentForOffset(end)!;
    path.moveTo(tangent.position.dx, tangent.position.dy);
    // Update
    final delta = end - extractedPathLength;
    _remainingDashGapLength = _updateRemainingLength(
      delta: delta,
      end: end,
      availableEnd: availableEnd,
      initialLength: dashGapLength,
    );
    extractedPathLength = end;
    _previousWasDash = false;
  }

  double _calculateLength(ui.PathMetric metric, double addedLength) {
    return math.min(extractedPathLength + addedLength, metric.length);
  }

  double _updateRemainingLength({
    required double delta,
    required double end,
    required double availableEnd,
    required double initialLength,
  }) {
    return (delta > 0 && availableEnd == end) ? delta : initialLength;
  }
}
Run Code Online (Sandbox Code Playgroud)


mal*_*aki 13

// garis putus putus
Row(
children: List.generate(150~/10, (index) => Expanded(
 child: Container(
  color: index%2==0?Colors.transparent
  :Colors.grey,
  height: 2,
 ),
 )),
),
Run Code Online (Sandbox Code Playgroud)

  • 虽然此代码可以回答问题,但提供有关此代码为何和/或如何回答问题的附加上下文可以提高其长期价值。 (2认同)
  • 看起来不错,但为什么是 150~/10 ?为什么不只使用 15、16、17 这样的数字......? (2认同)

mak*_*imr 12

作为一种解决方法,您可以执行以下操作

class MySeparator extends StatelessWidget {
  final double height;
  final Color color;

  const MySeparator({this.height = 1, this.color = Colors.black});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        final boxWidth = constraints.constrainWidth();
        final dashWidth = 10.0;
        final dashHeight = height;
        final dashCount = (boxWidth / (2 * dashWidth)).floor();
        return Flex(
          children: List.generate(dashCount, (_) {
            return SizedBox(
              width: dashWidth,
              height: dashHeight,
              child: DecoratedBox(
                decoration: BoxDecoration(color: color),
              ),
            );
          }),
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          direction: Axis.horizontal,
        );
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

并使用它 const MySeparator()

class App extends StatelessWidget {
  const App();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Material(
        child: Container(
          color: Colors.blue,
          child: Center(
            child: Container(
              height: 600, width: 350,
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.all(Radius.circular(16.0)),
              ),
              child: Flex(
                direction: Axis.vertical,
                children: [
                  Expanded(child: Container()),
                  const MySeparator(color: Colors.grey),
                  Container(height: 200),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

演示


小智 10

CustomPainter 也可以在这里提供帮助。在这个例子中是一条垂直的虚线,但可以很容易地改变。

class LineDashedPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint()..strokeWidth = 2;
    var max = 35;
    var dashWidth = 5;
    var dashSpace = 5;
    double startY = 0;
    while (max >= 0) {
      canvas.drawLine(Offset(0, startY), Offset(0, startY + dashWidth), paint);
      final space = (dashSpace + dashWidth);
      startY += space;
      max -= space;
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}
Run Code Online (Sandbox Code Playgroud)

并且使用 CustomPaint 小部件:

CustomPaint(painter: LineDashedPainter())
Run Code Online (Sandbox Code Playgroud)


Lê *_*Huy 10

我已经编写了flutter_dash库来绘制那个破折号。只有一行,你应该有一个破折号:D

Dash(length: 200, dashColor: Colors.red)
Run Code Online (Sandbox Code Playgroud)

试一试!


Lia*_*iar 6

感谢marksimr的回答,这里是垂直和水平虚线的代码。

水平使用:

DashLineView(
  fillRate: 0.7,
),
Run Code Online (Sandbox Code Playgroud)

垂直用途:

DashLineView(
  fillRate: 0.7,
  direction: Axis.vertical,
),
Run Code Online (Sandbox Code Playgroud)

完整代码:

class DashLineView extends StatelessWidget {
  final double dashHeight;
  final double dashWith;
  final Color dashColor;
  final double fillRate; // [0, 1] totalDashSpace/totalSpace
  final Axis direction;

  DashLineView(
      {this.dashHeight = 1,
      this.dashWith = 8,
      this.dashColor = Colors.black,
      this.fillRate = 0.5,
      this.direction = Axis.horizontal});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        final boxSize = direction == Axis.horizontal
            ? constraints.constrainWidth()
            : constraints.constrainHeight();
        final dCount = (boxSize * fillRate / dashWith).floor();
        return Flex(
          children: List.generate(dCount, (_) {
            return SizedBox(
              width: direction == Axis.horizontal ? dashWith : dashHeight,
              height: direction == Axis.horizontal ? dashHeight : dashWith,
              child: DecoratedBox(
                decoration: BoxDecoration(color: dashColor),
              ),
            );
          }),
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          direction: direction,
        );
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)