【问题标题】:How to add line dash in Flutter如何在 Flutter 中添加虚线
【发布时间】:2019-05-29 21:28:31
【问题描述】:

如何在 Flutter 中做这样的划线?

【问题讨论】:

标签: flutter flutter-layout


【解决方案1】:
 Row(
    children: List.generate(20, (index) {
                 return Expanded(
                   child: Padding(
                     padding: const EdgeInsets.only(left: 8.0),
                     child: Container(
                       height: 5,
                       width: 10,
                       color: Color(0XFFf2f2f2),
                     ),
                   ),
                 );
               }),
             )

【讨论】:

    【解决方案2】:

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

    横向用法:

    DashLineView(
      fillRate: 0.7,
    ),
    

    垂直用法:

    DashLineView(
      fillRate: 0.7,
      direction: Axis.vertical,
    ),
    

    完整代码:

    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,
            );
          },
        );
      }
    }
    

    【讨论】:

      【解决方案3】:

      我想出了这个解决方案。

      Row(                        // Dashed line
          children: [
            for (int i = 0; i < 25; i++)
              Container(
                width: 5,
                height: 1,
                decoration: BoxDecoration(
                  border: Border(
                    bottom: BorderSide(
                      width: 1,
                      color: i % 2 == 0
                          ? const Color.fromRGBO(214, 211, 211, 1)
                          : Colors.transparent,
                    ),
                  ),
                ),
              ),
          ],
        ),
      

      输出:

      【讨论】:

        【解决方案4】:
        Container(
                          color: Colors.white,
                          height: 40.0,
                          child: Center(
                            child: Text(
                              "---------------------------------------------------------------------------",
                              maxLines: 1,
                              style: typoNormalTextRegular.copyWith(
                                  color: colorABGray),
                            ),
                          ),
                        ),
        

        只使用Text Widget,简单的解决方案

        【讨论】:

          【解决方案5】:

          使用dotted_line: ^3.0.0 lib,它提供虚线和更多link

          import 'package:dotted_line/dotted_line.dart';
          
          DottedLine(
            direction: Axis.horizontal,
            lineLength: double.infinity,
            lineThickness: 1.0,
            dashLength: 4.0,
            dashColor: Colors.grey,
            dashRadius: 0.0,
            dashGapLength: 4.0,
            dashGapColor: Colors.transparent,
            dashGapRadius: 0.0,
          )
          

          输出:

          【讨论】:

            【解决方案6】:

            我通过整合解决方案 here 和来自 here 的数学创建了一个 CustomPainter。这个CustomPainter 允许通过指定虚线的长度和虚线之间的空间长度来绘制实线或虚线。但最好的是,您甚至可以在各个方向上绘制实线或虚线。我的意思是水平,垂直,甚至对角线!

            这是CustomPainter的代码:

            import 'dart:math';
            
            import 'package:flutter/material.dart';
            
            class LinePainter extends CustomPainter {
              final Offset firstOffset;
              final Offset secondOffset;
              final Color color;
              final double strokeWidth;
              final double dashLength;
              final double dashSpace;
            
              const LinePainter({
                required this.firstOffset,
                required this.secondOffset,
                this.color = Colors.black,
                this.strokeWidth = 2.0,
                this.dashLength = 4.0,
                this.dashSpace = 4.0,
              });
            
              @override
              void paint(Canvas canvas, Size size) {
                final paint = Paint()
                  ..color = color
                  ..strokeWidth = strokeWidth;
                _drawDashedLine(
                    dashLength, dashSpace, firstOffset, secondOffset, canvas, size, paint);
              }
            
              @override
              bool shouldRepaint(covariant CustomPainter oldDelegate) {
                return false;
              }
            
              void _drawDashedLine(double dashLength, double dashSpace, Offset firstOffset,
                  Offset secondOffset, Canvas canvas, Size size, Paint paint) {
                var startOffset = firstOffset;
            
                var intervals = _getDirectionVector(firstOffset, secondOffset).length /
                    (dashLength + dashSpace);
            
                for (var i = 0; i < intervals; i++) {
                  var endOffset = _getNextOffset(startOffset, secondOffset, dashLength);
            
                  /// Draw a small line.
                  canvas.drawLine(startOffset, endOffset, paint);
            
                  /// Update the starting offset.
                  startOffset = _getNextOffset(endOffset, secondOffset, dashSpace);
                }
              }
            
              Offset _getNextOffset(
                Offset firstOffset,
                Offset secondOffset,
                double smallVectorLength,
              ) {
                var directionVector = _getDirectionVector(firstOffset, secondOffset);
            
                var rescaleFactor = smallVectorLength / directionVector.length;
                if (rescaleFactor.isNaN || rescaleFactor.isInfinite) {
                  rescaleFactor = 1;
                }
            
                var rescaledVector = Offset(directionVector.vector.dx * rescaleFactor,
                    directionVector.vector.dy * rescaleFactor);
            
                var newOffset = Offset(
                    firstOffset.dx + rescaledVector.dx, firstOffset.dy + rescaledVector.dy);
            
                return newOffset;
              }
            
              DirectionVector _getDirectionVector(Offset firstVector, Offset secondVector) {
                var directionVector = Offset(
                    secondVector.dx - firstVector.dx, secondVector.dy - firstVector.dy);
            
                var directionVectorLength =
                    sqrt(pow(directionVector.dx, 2) + pow(directionVector.dy, 2));
            
                return DirectionVector(
                  vector: directionVector,
                  length: directionVectorLength,
                );
              }
            }
            
            class DirectionVector {
              final Offset vector;
              final double length;
            
              const DirectionVector({
                required this.vector,
                required this.length,
              });
            }

            您可以通过设置CustomPaint 小部件的painter 参数来使用此CustomPainter,如下所示:

            CustomPaint(
              painter: LinePainter(
                firstOffset: Offset(0, 0),
                secondOffset: Offset(10, 10),
              ),
            ),

            结果如下图所示:

            【讨论】:

              【解决方案7】:

              你可以用这个:

              Widget dashedHorizontalLine(){
                return Row(
                  children: [
                    for (int i = 0; i < 20; i++)
                      Expanded(
                        child: Row(
                          children: [
                            Expanded(
                              child: Divider(
                                color: AppColors.darkGreen,
                                thickness: 2,
                              ),
                            ),
                            Expanded(
                              child: Container(),
                            ),
                          ],
                        ),
                      ),
                  ],
                );
              }
              

              【讨论】:

                【解决方案8】:

                您可以将 CustomPainter 与 线性渐变虚线着色器 一起用于线条。

                   // GradientRotation(3.14 / 2) — for vertical lines with dashes
                   // GradientRotation(0) — for horizontal lines with dashes
                   // .createShader(Rect.fromLTWH(0, 0, 10, 10) — 10 is the size of repeated shaders part
                   // This method can be tricky if you need a line oriented by some angle.
                
                Paint()..shader = LinearGradient(
                                  colors: [Colors.blue, Colors.transparent],
                                  stops: [0.5, 0.5],
                                  tileMode: TileMode.repeated,
                                  transform: GradientRotation(3.14 / 2))
                              .createShader(Rect.fromLTWH(0, 0, 10, 10))
                          ..style = PaintingStyle.stroke
                          ..strokeWidth = 6
                

                【讨论】:

                  【解决方案9】:

                  您应该更喜欢使用 CustomPainter,因为它具有更高的性能并且适合此类问题。

                  class DashLine extends StatelessWidget {
                    const DashLine({
                      Key key,
                      this.color,
                      this.dashWidth,
                      this.dashSpace,
                      this.strokeWidth,
                    }) : super(key: key);
                  
                    final Color color;
                    final double dashWidth;
                    final double dashSpace;
                    final double strokeWidth;
                  
                    @override
                    Widget build(BuildContext context) {
                      return CustomPaint(
                        painter: _DashLinePainter(
                          color: color,
                          dashWidth: dashWidth,
                          dashSpace: dashSpace,
                          strokeWidth: strokeWidth,
                        ),
                      );
                    }
                  }
                  
                  class _DashLinePainter extends CustomPainter {
                    _DashLinePainter({
                      Color color,
                      double dashWidth,
                      double dashSpace,
                      double strokeWidth,
                    })  : _color = color ?? Colors.red,
                          _dashWidth = dashWidth ?? 5.0,
                          _dashSpace = dashSpace ?? 5.0,
                          _strokeWidth = strokeWidth ?? 1.0;
                  
                    final Color _color;
                    final double _dashWidth;
                    final double _dashSpace;
                    final double _strokeWidth;
                  
                    @override
                    void paint(Canvas canvas, Size size) {
                      final paint = Paint()
                        ..color = _color
                        ..strokeWidth = _strokeWidth;
                  
                      var max = size.width;
                      var startX = 0.0;
                      while (max >= 0) {
                        canvas.drawLine(Offset(startX, 0), Offset(startX + _dashWidth, 0), paint);
                        final space = (_dashSpace + _dashWidth);
                        startX += space;
                        max -= space;
                      }
                    }
                  
                    @override
                    bool shouldRepaint(_DashLinePainter oldDelegate) {
                      return _color != oldDelegate._color ||
                          _dashWidth != oldDelegate._dashWidth ||
                          _dashSpace != oldDelegate._dashSpace ||
                          _strokeWidth != oldDelegate._strokeWidth;
                    }
                  }
                  

                  【讨论】:

                    【解决方案10】:

                    垂直虚线:
                    我修改了 maksimr 的例子:

                    class DashedLine extends StatelessWidget {
                      final double height;
                      final double heightContainer;
                      final Color color;
                    
                      const DashedLine({this.height = 3, this.color = Colors.black, this.heightContainer = 70});
                    
                      @override
                      Widget build(BuildContext context) {
                        return Container(
                          height: heightContainer,
                          child: LayoutBuilder(
                            builder: (BuildContext context, BoxConstraints constraints) {
                              final boxHeight = constraints.constrainHeight();
                              final dashWidth = 10.0;
                              final dashHeight = height;
                              final dashCount = (boxHeight / (2 * dashHeight)).floor();
                              return Flex(
                                children: List.generate(dashCount, (_) {
                                  return SizedBox(
                                    width: dashWidth,
                                    height: dashHeight,
                                    child: DecoratedBox(
                                      decoration: BoxDecoration(color: color),
                                    ),
                                  );
                                }),
                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                direction: Axis.vertical,
                              );
                            },
                          ),
                        );
                      }
                    }
                    

                    【讨论】:

                      【解决方案11】:
                      // garis putus putus
                      Row(
                      children: List.generate(150~/10, (index) => Expanded(
                       child: Container(
                        color: index%2==0?Colors.transparent
                        :Colors.grey,
                        height: 2,
                       ),
                       )),
                      ),
                      

                      【讨论】:

                      • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
                      • 这是实现的最简单的答案,无需任何依赖。
                      • 看起来不错,但为什么是 150~/10 ?你为什么不只使用像 15、16、17.... 这样的数字?
                      • @Deven 例如,你想应用小部件或屏幕的宽度,然后除以你想要的行数和“~”符号给出一个整数值,如果你想要它更简单的是,您可以使用固定数字(如 5、6,10 等)的建议
                      【解决方案12】:

                      创建这个类:

                      class DotWidget extends StatelessWidget {
                        final double totalWidth, dashWidth, emptyWidth, dashHeight;
                      
                        final Color dashColor;
                      
                        const DotWidget({
                          this.totalWidth = 300,
                          this.dashWidth = 10,
                          this.emptyWidth = 5,
                          this.dashHeight = 2,
                          this.dashColor = Colors.black,
                          Key key,
                        }) : super(key: key);
                      
                        @override
                        Widget build(BuildContext context) {
                          return Row(
                            mainAxisSize: MainAxisSize.min,
                            children: List.generate(
                              totalWidth ~/ (dashWidth + emptyWidth),
                                  (_) => Container(
                                width: dashWidth,
                                height: dashHeight,
                                color: dashColor,
                                margin: EdgeInsets.only(left: emptyWidth / 2, right: emptyWidth / 2),
                              ),
                            ),
                          );
                        }
                      }
                      

                      用法:

                      像使用任何其他小部件一样使用它

                       child: DotWidget(
                         dashColor: Colors.black,
                         dashHeight: 2,
                         dashWidth: 100,
                       )
                      

                      【讨论】:

                        【解决方案13】:

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

                        Dash(length: 200, dashColor: Colors.red)
                        

                        试一试!

                        【讨论】:

                        • 感谢我!非常感谢:)
                        • 我不推荐,这个库没有很好的优化,会导致你的应用加载屏幕变慢
                        • @SoufianeGhzal 请给我一些优化建议,谢谢
                        • @LêVũHuy 我真的不知道是什么问题。请去githubgithub.com/huy-lv/flutter_dash/issues/2
                        【解决方案14】:
                        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;
                        }
                        

                        【讨论】:

                        • 像 CustomPaint(painter: DashedLinePainter()); 一样使用它
                        【解决方案15】:

                        试试这个,

                        class DotDivider extends StatelessWidget {
                          final double width;
                          final double height;
                          final double gap;
                          final Color color;
                          final double lineHeight;
                        
                          const DotDivider(
                              {this.height = 1.0,
                              this.color = Colors.black,
                              this.width = 2.0,
                              this.gap = 2.0,
                              this.lineHeight = 10.0});
                        
                          @override
                          Widget build(BuildContext context) {
                            return LayoutBuilder(
                              builder: (BuildContext context, BoxConstraints constraints) {
                                final boxWidth = constraints.constrainWidth();
                                final dashWidth = width;
                                final dashHeight = height;
                                final dashCount = (boxWidth / dashWidth).floor();
                                return Container(
                                  height: (lineHeight * 2) + height,
                                  child: ListView.builder(
                                    physics: NeverScrollableScrollPhysics(),
                                    scrollDirection: Axis.horizontal,
                                    itemCount: dashCount,
                                    itemBuilder: (BuildContext context, int index) => Center(
                                      child: Container(
                                        width: dashWidth,
                                        height: dashHeight,
                                        margin:
                                            EdgeInsets.symmetric(vertical: lineHeight, horizontal: gap),
                                        decoration: BoxDecoration(color: color),
                                      ),
                                    ),
                                  ),
                                );
                              },
                            );
                          }
                        }
                        

                        【讨论】:

                          【解决方案16】:

                          这是水平虚线的代码,就像您的图像一样。 CustomPaint 是 Fl​​utter 团队强烈推荐的。它也可以快速高效地进行渲染。您可以使用 Offset 来改变方向。

                           class MyClass extends StatelessWidget {
                            @override
                            Widget build(BuildContext context) {
                              return Center(
                                child: CustomPaint(
                                  painter: MyLinePainter(),
                                ),
                              );
                            }
                          }
                          
                          class MyLinePainter extends CustomPainter {
                            @override
                            void paint(Canvas canvas, Size size) {
                              var max = 100;
                              var dashWidth, dashSpace = 5;
                              double startX = 0;
                              final paint = Paint()..color = Colors.grey;
                              while (max >= 0) {
                                canvas.drawLine(Offset(startX, 0), Offset(startX + dashWidth, 0), paint..strokeWidth = 1);
                                final space = (dashSpace + dashWidth);
                                startX += space;
                                max -= space;
                              }
                            }
                          

                          【讨论】:

                            【解决方案17】:

                            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;
                            }
                            

                            并且使用 CustomPaint 小部件:

                            CustomPaint(painter: LineDashedPainter())
                            

                            【讨论】:

                              【解决方案18】:

                              As a workaround,在你的情况下,你可以这样做

                              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,
                                      );
                                    },
                                  );
                                }
                              }
                              

                              并使用它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),
                                              ],
                                            ),
                                          ),
                                        ),
                                      ),
                                    ),
                                  );
                                }
                              }
                              

                              【讨论】:

                                猜你喜欢
                                • 2018-08-27
                                • 1970-01-01
                                • 2020-01-05
                                • 2022-12-25
                                • 2020-06-06
                                • 1970-01-01
                                • 2021-02-09
                                • 1970-01-01
                                • 2013-02-21
                                相关资源
                                最近更新 更多