在Flutter中如何实现带有文本的水平分割线?

76

Flutter中是否有内置小部件来创建带有文本的分隔符? 有关如何执行此操作的任何指南吗? 就像这样:(水平线中间的“OR”文本)

这里是我想要实现的截图


const Divider(), - carloswm85
9个回答

206
您可以尝试使用 Row widget。
Row(
    children: <Widget>[
        Expanded(
            child: Divider()
        ),       

        Text("OR"),        

        Expanded(
            child: Divider()
        ),
    ]
)

60

带有文本的分割线示例

针对Jerome的回答,这里提供一个示例,展示如何将其嵌入其他内容,并且具有额外的边界集以更接近您想要的实际图片:

          Column(children: <Widget>[
            Row(
              children: <Widget>[Text("above")],
            ),
            Row(children: <Widget>[
              Expanded(
                child: new Container(
                    margin: const EdgeInsets.only(left: 10.0, right: 20.0),
                    child: Divider(
                      color: Colors.black,
                      height: 36,
                    )),
              ),
              Text("OR"),
              Expanded(
                child: new Container(
                    margin: const EdgeInsets.only(left: 20.0, right: 10.0),
                    child: Divider(
                      color: Colors.black,
                      height: 36,
                    )),
              ),
            ]),
            Row(
              children: <Widget>[Text("below ")],
            ),
          ])

这实际上是一个很好的例子! - undefined

12

目前还没有Flutter小部件可以做到这一点,我为自己创建了一个。 您可以按照以下方式操作

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

class HorizontalOrLine extends StatelessWidget {
  const HorizontalOrLine({
    this.label,
    this.height,
  });

  final String label;
  final double height;

  @override
  Widget build(BuildContext context) {

    return Row(children: <Widget>[
      Expanded(
        child: new Container(
            margin: const EdgeInsets.only(left: 10.0, right: 15.0),
            child: Divider(
              color: Colors.black,
              height: height,
            )),
      ),

      Text(label),

      Expanded(
        child: new Container(
            margin: const EdgeInsets.only(left: 15.0, right: 10.0),
            child: Divider(
              color: Colors.black,
              height: height,
            )),
      ),
    ]);
  }
}

使用方法如下:

HorizontalOrLine(height: 10,label: "OR")

10

我稍微美化了一下,代码如下

Row(
   mainAxisAlignment: MainAxisAlignment.center,
   children: const [
                     Expanded(
                       child: Divider(
                                indent: 20.0,
                                endIndent: 10.0,
                                thickness: 1,
                              ),
                     ),
                     Text(
                          "OR",
                          style: TextStyle(color: Colors.blueGrey),
                     ),
                     Expanded(
                          child: Divider(
                                  indent: 10.0,
                                  endIndent: 20.0,
                                  thickness: 1,
                          ),
                      ),
                ],
),

3

最佳解决方案是创建一个CustomPainter并绘制一条线。

按照以下步骤进行:enter image description here

CustomPainter:

class Drawhorizontalline extends CustomPainter {
      Paint _paint;
      bool reverse;

   Drawhorizontalline(this.reverse) {
     _paint = Paint()
          ..color = PPColors.tertiaryColor
          ..strokeWidth = 1
          ..strokeCap = StrokeCap.round;
   }

  @override
  void paint(Canvas canvas, Size size) {
      if (reverse) {
         canvas.drawLine(Offset(-250.0, 0.0), Offset(-10.0, 0.0), _paint);
      } else {
         canvas.drawLine(Offset(10.0, 0.0), Offset(250.0, 0.0), _paint);
      }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
     return false;
  }
}

使用这个CustomPainter。
Widget getSeparateDivider() {
return Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    CustomPaint(painter: Drawhorizontalline(true)),
    Text(
      "OR",
      style: TextStyle(
          color: PPColors.primaryColor,
          fontWeight: FontWeight.bold,
          fontSize: PPUIHelper.FontSizeLarge),
    ),
    CustomPaint(painter: Drawhorizontalline(false))
  ],
 );
}

2
您可以使用容器来实现这一点:

您只需使用一个容器即可:

new Container(height: 40, width: 1, color: Colors.grey,
                        margin: const EdgeInsets.only(left: 10.0, right: 10.0),),

如果你想要一条竖线,改变高度来确定大小,并通过宽度控制线条的“粗细”。
如果你想画一条水平线,请在宽度/高度之间反转这个逻辑。
将其与文本放在两个容器的中间,使用行。

请尽量解释您的答案,因为现在我很难理解您想说/做什么。 - Roet
由于有Divider()小部件可用,我们无需创建外观类似的Container。 - Maruf Hassan

1
import 'package:flutter/material.dart';

class HorizontalLineTitle extends StatelessWidget {
  final String title;
  final Color color;
  final double lineHeight;
  final double lineWidth;
  final double paddingTop;
  final double paddingBottom;

  HorizontalLineTitle({
    @required this.title,
    @required this.color,
    this.lineHeight,
    this.lineWidth,
    this.paddingTop,
    this.paddingBottom,
  });

  Widget _line() {
    return LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        final boxWidth = constraints.constrainWidth();
        final dashWidth = lineWidth ?? 10.0;
        final dashHeight = lineHeight ?? 1.0;
        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,
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    var widgets = <Widget>[];
    widgets.add(Expanded(child: _line()));
    if (title != null && title != '') {
      widgets.add(Padding(
        padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
        child: Text(
          title,
          style: Theme.of(context).textTheme.title,
        ),
      ));
    } else {
      widgets.add(Container(width: 2.0));
    }
    widgets.add(Expanded(child: _line()));
    return Padding(
      padding: EdgeInsets.fromLTRB(
          0.0, paddingTop ?? 0.0, 0.0, paddingBottom ?? 0.0),
      child: Row(
        children: widgets,
      ),
    );
  }
}

这个小部件可以用于需要虚线的相同事物。只是想发布这个,让人们可以使用它来自定义它们的需求。


1
Row(
    children: <Widget>[
        Expanded(
            child: Divider()
        ),       

        Text("OR"),        

        Expanded(
            child: Divider()
        ),
    ]
)

1
欢迎来到SO!这个回答似乎与被接受的回答相同。请不要发布完全相同的答案,而是给它点赞(一旦你有足够的声望)。目前,我建议你删除这个回答。 - MendelG

0

enter image description here

另一种解决方案是使用Stack小部件,我们可以将两个小部件 - Divider和Container堆叠在一起。
通过在Stack小部件上使用alignment属性,我们可以使所有子小部件居中。
Container有两个我们需要的属性。
1. padding属性:用于在文本周围创建边距。 2. decoration属性:以与背景相同的颜色填充整个空间。
Stack(
 alignment: Alignment.center,
 children: [
   const Divider(),
   Container(
     padding: const EdgeInsets.all(8.0),
     decoration: BoxDecoration(
       color: Theme.of(context).scaffoldBackgroundColor,
     ),
     child: const Text(
       'OR',
       style: TextStyle(
         ...
        ),
      ),
    ),
  ],
),

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接