简体   繁体   中英

Wrapping text inside a circle (Flutter)

is it possible to wrap text inside a circle in Flutter? Here is a failed example. Ideally the text would fit inside the circle and overflow at the end only.

ClipOval(
  child: SizedBox.expand(
    child: Text(
      "Round and round the rugged rocks, the rascally rascals ran. Round and round the rugged rocks, the rascally rascals ran. Round and round the rugged rocks, the rascally rascals ran. Round and round the rugged rocks, the rascally rascals ran. ",
      softWrap: true,
      overflow: TextOverflow.fade,
    ),
  ),
),

在此处输入图像描述

As of now (July 2019), Flutter does not directly support laying out text in non-rectangular shapes.

Using existing API, it should be possible to achieve a similar custom effect by implementing something that performs the following steps:

  • Create a column.
  • Layout single line text with width of circle at line 1
  • Get the character index of the last laid out character (using getBoxesForRange and getPositionForOffset)
  • Truncate the front of the text you want to layout at the index to obtain remaining text.
  • Layout the remaining text as a single line text with width of circle at line 2. The y position at line 2 can be obtained by adding the height of the single line 1.
  • Repeat until no more text or circle is filled. Place all text within the column centered.

That should be able to get you something close. The implementation will have to handle all of the calculations of the widths of the circle at each y-position as well as manually position each line of text.

Solution for small text

I propose this solution, which works very well for small text:

ClipOval(
    child: Container(
        height: 30.0,
        margin: const EdgeInsets.all(20),
        width:  price.length * 10.0,
        decoration: BoxDecoration(color: Colors.white70,
        border: Border.all(color: Color(0x00ffffff), width: 0.0),
            borderRadius: BorderRadius.all(Radius.elliptical(price.length * 10.0, 30))), // this line makes the coffee.
        child: Center(child:Text(price, style: const TextStyle(color: Color(0xff2200ff))))
)),

NB: 0xff2200ff is the blue color, Colors.white70 is the background color.

If you want the shape to be very round like a circle just replace 30.0 by text.length * 10.0 for the height of container and border radius.

For those who want a solution working with long text you can take my solution and add your own function that will create a round shape of text (by adding \\n) based on the length of the text.

在此处输入图片说明

I hope that it will help.

Something like this.

import 'dart:math' as math;
import 'package:flutter/material.dart';

class CircleTextWrapper extends StatelessWidget {
  const CircleTextWrapper({
    Key? key,
    this.radius = 110,
    this.text =
        "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.",
    this.textStyle = const TextStyle(fontSize: 20),
    this.startAngle = 0,
  }) : super(key: key);
  final double radius;
  final String text;
  final double startAngle;
  final TextStyle textStyle;
  @override
  Widget build(BuildContext context) => CustomPaint(
        painter: _Painter(
          radius,
          text,
          textStyle,
        ),
      );
}

class _Painter extends CustomPainter {
  _Painter(this.radius, this.text, this.textStyle, {this.padding = 12});
  final double radius;
  final String text;
  final double padding;

  final TextStyle textStyle;
  final _textPainter = TextPainter(textDirection: TextDirection.ltr);
  final Paint _paint = Paint()
    ..blendMode
    ..color = Colors.white
    ..strokeWidth = 2
    ..style = PaintingStyle.stroke;
  @override
  void paint(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);
    canvas.drawCircle(Offset.zero, radius + padding, _paint);

    String lineText = "";
    _textPainter.text = TextSpan(text: lineText, style: textStyle);
    _textPainter.layout(
      minWidth: 0,
      maxWidth: double.maxFinite,
    );

    double y = -radius + _textPainter.height * .6;
    double x = math.sqrt(radius * radius - y * y);
    for (int i = 0; i < text.length; i++) {
      lineText += text[i];
      _textPainter.text = TextSpan(text: lineText, style: textStyle);
      _textPainter.layout(
        minWidth: 0,
        maxWidth: double.maxFinite,
      );

      if (_textPainter.width >=
          (Offset(-x, y) - Offset(x, y)).distance - textStyle.fontSize! * .5) {
        _textPainter.paint(canvas, Offset(-x, y - _textPainter.height * .6));
        // canvas.drawLine(Offset(-x, y), Offset(x, y), _paint);
        y += _textPainter.height;
        x = math.sqrt(radius * radius - y * y);
        lineText = "";
      }

      if (i == text.length - 1) {
        _textPainter.paint(canvas, Offset(-x, y - _textPainter.height * .6));
        //  canvas.drawLine(Offset(-x, y), Offset(x, y), _paint);
      }
    }
  }

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

Result:

所需结果的屏幕截图,圆圈内包含的文本

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM