Home > OS >  Flutter border around container with text in the middle (divider?)
Flutter border around container with text in the middle (divider?)

Time:10-26

I try to create a border around a container, that is not that difficult ofcourse, but i need also a text IN the border with space around it. Like horizontal divder but i need a complete border.

Attached what i like to achieve.

Any one who can help me how to approach this?

Thanks!

enter image description here

Tried to use the horizontal and vertical divider packages, but then the border is not in full.

CodePudding user response:

You can use CustomPainter like this:

class CustomDraw extends CustomPainter {
  late Paint painter;
  late double radius;
  late double textWidth;

  CustomDraw(Color color, this.textWidth, {this.radius = 0}) {
    painter = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2
      ..color = color;
  }

  @override
  void paint(Canvas canvas, Size size) {
    var path = Path();

    path.moveTo(size.width - ((size.width - textWidth) / 2), 0);

    path.lineTo(size.width - radius, 0);
    path.cubicTo(size.width - radius, 0, size.width, 0, size.width, radius);
    path.lineTo(size.width, size.height - radius);
    path.cubicTo(size.width, size.height - radius, size.width, size.height,
        size.width - radius, size.height);

    path.lineTo(radius, size.height);
    path.cubicTo(radius, size.height, 0, size.height, 0, size.height - radius);

    path.lineTo(0, radius);
    path.cubicTo(0, radius, 0, 0, radius, 0);
    path.lineTo(((size.width - textWidth) / 2), 0);

    canvas.drawPath(path, painter);
  }

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

and this widget:

class CustomTitleWidget extends StatefulWidget {
  final double height;
  final double width;
  final double? radius;
  final String title;
  const CustomTitleWidget(
      {Key? key,
      required this.height,
      required this.width,
      required this.title,
      this.radius})
      : super(key: key);

  @override
  State<CustomTitleWidget> createState() => _CustomTitleWidgetState();
}

class _CustomTitleWidgetState extends State<CustomTitleWidget> {
  GlobalKey textKey = GlobalKey();
  double textHeight = 0.0;
  double textWidth = 0.0;

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {
        final textKeyContext = textKey.currentContext;
        if (textKeyContext != null) {
          final box = textKeyContext.findRenderObject() as RenderBox;
          textHeight = box.size.height;
          textWidth = box.size.width;
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      clipBehavior: Clip.none,
      alignment: Alignment.topCenter,
      children: [
        CustomPaint(
          child: Container(
            height: widget.height,
            width: widget.width,
          ),
          painter: CustomDraw(
            Colors.red,
            textWidth,
            radius: widget.radius ?? 0,
          ),
        ),
        Positioned(
          top: -textHeight / 2,
          child: Padding(
            key: textKey,
            padding: EdgeInsets.symmetric(horizontal: 8.0),
            child: Text(
              widget.title,
            ),
          ),
        )
      ],
    );
  }
}

use like this:

CustomTitleWidget(
                height: 200,
                width: double.infinity,
                title: 'asdasdasdasdasd',
                radius: 16),

enter image description here

CodePudding user response:

@Maenda, We can implement such kind of structure using Stack, take one container with a border & put the other container over the first one.

Here is an example:

Stack(
      children: [
        Positioned(
            top: 12,
            left: 0,
            right: 0,
            child: Container(
              height: 120,
              width: MediaQuery.of(context).size.width,
              margin: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
              padding: EdgeInsets.all(8),
              decoration: BoxDecoration(
                  color: Colors.green,
                  border: Border.all(width: 1.2),
                  borderRadius: BorderRadius.circular(3)),
            )),
        Container(
          margin: EdgeInsets.symmetric(
            horizontal: 21,
          ),
          child: Column(
            children: [
              Container(
                width: 100,
                margin: EdgeInsets.only(top: 12, bottom: 5),
                alignment: Alignment.center,
                color: Colors.blue,
                child: Text(
                  "Any Text",
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w500,
                  ),
                ),
              ),
              Text(
                "Nature, in the broadest sense, is the physical world or universe. Nature can refer to the phenomena of the physical world, and also to life in general.",
                textAlign: TextAlign.center,
              ),
              SizedBox(
                height: 8,
              )
            ],
          ),
        ),
      ],
    );

Hope this works! You can customize as per the design.

  • Related