curved_render_text 1.1.0 copy "curved_render_text: ^1.1.0" to clipboard
curved_render_text: ^1.1.0 copied to clipboard

The text is bent according to the curvature, which is realized by custom rendering parts, and the actual width and height of the parts can be returned after bending.

curved_render_text #

Version Generic badge

用来将文本根据曲率进行弯曲,通过自定义渲染Widget实现,通过计算弯曲后的文本实际宽高来重新赋值Widget的Size.

使用场景:弯曲文本后需要测量实际的文本显示部分的宽高,用以给其添加跟随文本长度以及曲率变化的边框

支持TextSpan以及WidgetSpan渲染,支持拓展绘制前和绘制后的方法,允许使用者自定义绘制文本装饰线,如:文本上划线、删除线、下划线,绘制时建议启用忽略文本装饰等。

该插件在flutter_arc_text的基础上大幅修改的,删除了 许多原有功能及属性。

🖼️ Preview #

Demo Preview Demo Preview2

准备工作 🍭 #

Flutter #

执行 flutter pub add curved_render_text, 或者将 curved_render_text 手动添加至 pubspec.yaml 引用。

dependencies:
  curved_render_text: ^latest_version

🕹️ 使用方法 #

建议看demo示例代码

import 'package:curved_render_text/curved_render_text.dart';
...
CurvedText(
  text: '文本根据曲率设置弯曲并返回size',
  textStyle: const TextStyle(fontSize: 18, color: Colors.black),
  textSpan: TextSpan(...),//传入TextSpan
  curvature: 0.5,//曲率范围-1到1
  beforeDrawing: ...,//文本绘制前绘制
  afterDrawing: ...,//文本绘制后绘制
  ignoreDecoration: true,//是否忽略TextStyle的decoration属性
)
...

PainterDelegate回调参数

typedef PainterDelegate = void Function(
    PaintingContext context,
    Offset offset,
    Size size,
    double radius,//圆半径
    double startAngle,//绘制开始角度
    double sweepAngle,//绘制弧度范围
    double finalAngle,//绘制结束角度
    Offset centerOffset,//圆中心点偏移
    double curvature,//曲率
    double letterHeight,//参与计算的字体高度
    List<TextRun> textRuns,//文本的绘制信息
    );

Demo #

完整示例代码如下

import 'package:curved_render_text/curved_render_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        // useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter CurvedText Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double curvature = 100;
  final TextStyle _textStyle = const TextStyle(fontSize: 18, color: Colors.black);
  final TextEditingController _textEditingController = TextEditingController
    (text: '文本根据曲率弯曲,通过自定义渲染widget实现,弯曲后可返回widget的实际宽度和高度');
  bool ignoreDecoration = true;
  TextDecoration textDecoration = TextDecoration.none;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: SizedBox(
        width: double.infinity,
        height: double.infinity,
        child: Column(
          children: [
            Expanded(child: Stack(
              alignment: Alignment.center,
              clipBehavior: Clip.none,
              children: [
                OverflowBox(
                  maxWidth: double.infinity,
                  maxHeight: double.infinity,
                  child: DecoratedBox(
                    decoration: BoxDecoration(
                      border: Border.all(
                        color: Theme.of(context).primaryColor,
                        width: 1,
                      ),
                    ),
                    child: CurvedText(
                      ignoreDecoration: ignoreDecoration,
                      text: _textEditingController.text,
                      textStyle: _textStyle.copyWith(
                        fontSize: 14,
                        decoration: textDecoration,
                        decorationColor: _textStyle.color,
                        decorationThickness: 2,
                      ),
                      textSpan: TextSpan(
                        children: [
                          WidgetSpan(child: Icon(Icons.ac_unit,size: 40,color: Colors.green,),alignment: PlaceholderAlignment.middle),
                          WidgetSpan(child: Icon(Icons.sailing_sharp,size: 20,color: Colors.blueAccent,),alignment: PlaceholderAlignment.middle),
                          TextSpan(
                            text: 'TextSpan',
                            style: _textStyle.copyWith(
                              color: Colors.blue,
                              decoration: textDecoration,
                              decorationColor: Colors.blue,
                              decorationThickness: 2,
                            ),
                          ),
                          WidgetSpan(child: Icon(Icons.access_alarm,size: 20,color: Colors.purple,),alignment: PlaceholderAlignment.middle),
                          WidgetSpan(child: Icon(Icons.local_activity,size: 20,color: Colors.amber,),alignment: PlaceholderAlignment.middle),
                          TextSpan(
                            text: 'TextSpan',
                            style: _textStyle.copyWith(
                              decoration: textDecoration,
                              decorationColor: _textStyle.color,
                              decorationThickness: 2,
                            ),
                          ),
                        ],
                      ),
                      curvature: curvature/100.0,
                      afterDrawing: _makeDelegate(),
                    ),
                  ),
                )
              ],
            ),),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Column(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                    SizedBox(
                      width: 200,
                      child:Slider(
                        value: curvature,
                        divisions: 200,
                        label: '弯曲程度${curvature.toInt()}%',
                        min: -100,
                        max: 100,
                        onChanged: (value){
                          setState(() {
                            curvature = value.floorToDouble();
                          });
                        },
                      ),
                    ),
                    Row(
                      children: [
                        Column(
                          children: [
                            Row(
                              children: [
                                CupertinoSwitch(value: textDecoration==TextDecoration.overline,
                                  activeColor: Theme.of(context).primaryColor,
                                  onChanged: (value){
                                    setState(() {
                                      textDecoration = value?TextDecoration.overline:TextDecoration.none;
                                    });
                                  },),
                                Text('上划线',style: TextStyle(fontSize: 14,color: Theme.of(context).primaryColor),),
                              ],
                            ),
                            Row(
                              children: [
                                CupertinoSwitch(value: textDecoration==TextDecoration.lineThrough,
                                  activeColor: Theme.of(context).primaryColor,
                                  onChanged: (value){
                                    setState(() {
                                      textDecoration = value?TextDecoration.lineThrough:TextDecoration.none;
                                    });
                                  },),
                                Text('删除线',style: TextStyle(fontSize: 14,color: Theme.of(context).primaryColor),),
                              ],
                            ),
                            Row(
                              children: [
                                CupertinoSwitch(value: textDecoration==TextDecoration.underline,
                                  activeColor: Theme.of(context).primaryColor,
                                  onChanged: (value){
                                    setState(() {
                                      textDecoration = value?TextDecoration.underline:TextDecoration.none;
                                    });
                                  },),
                                Text('下划线',style: TextStyle(fontSize: 14,color: Theme.of(context).primaryColor),),
                              ],
                            ),
                          ],
                        ),
                        SizedBox(width: 20,),
                        Column(
                          children: [
                            Row(
                              children: [
                                CupertinoSwitch(value: ignoreDecoration,
                                  activeColor: Theme.of(context).primaryColor,
                                  onChanged: (value){
                                    setState(() {
                                      ignoreDecoration = !ignoreDecoration;
                                    });
                                  },),
                                Text('忽略默认文本装饰',style: TextStyle(fontSize: 14,color: Theme.of(context).primaryColor),),
                              ],
                            ),
                          ],
                        ),
                      ],
                    ),
                  ],
                ),
                SizedBox(width: 20,),
                SizedBox(width: 200,height: 80,child: CupertinoTextField(
                  showCursor: true,
                  controller: _textEditingController,
                  style: TextStyle(
                    fontSize: 12,
                    color: Theme.of(context).primaryColor,
                  ),
                  maxLines: null,
                  onChanged: (value){
                    setState(() {});
                  },
                )),
              ],
            ),
          ],
        ),
      ),
    );
  }

  PainterDelegate _makeDelegate() =>
          (PaintingContext context,
          Offset offset,
          Size size,
          double radius,
          double startAngle,
          double sweepAngle,
          double finalAngle,
          Offset centerOffset,
          double curvature,
          double letterHeight,
          List<TextRun> textRuns,) {
        for (var textRun in textRuns) {
          Rect? rect;
          if(textRun.style?.decoration == TextDecoration.overline){
            rect = Rect.fromCircle(
              center: centerOffset,
              radius: radius+(curvature>=0?1:-1)*letterHeight/2,
            );
          } else if(textRun.style?.decoration == TextDecoration.lineThrough){
            rect = Rect.fromCircle(
              center: centerOffset,
              radius: radius,
            );
          } else if(textRun.style?.decoration == TextDecoration.underline){
            rect = Rect.fromCircle(
              center: centerOffset,
              radius: radius+(curvature>=0?-1:1)*letterHeight/2,
            );
          }
          if (rect!=null) {
            context.canvas.drawArc(
              rect,
              textRun.startAngle,
              textRun.sweepAngle,
              false,
              Paint()
                ..style = PaintingStyle.stroke
                ..strokeCap = StrokeCap.round
                ..strokeWidth = textRun.textSpan.style?.decorationThickness??1
                ..color = textRun.textSpan.style?.decorationColor??textRun.textSpan.style?.color??Colors.black,
            );
          }
        }
      };
}

4
likes
150
points
55
downloads

Publisher

unverified uploader

Weekly Downloads

The text is bent according to the curvature, which is realized by custom rendering parts, and the actual width and height of the parts can be returned after bending.

Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

characters, flutter, vector_math

More

Packages that depend on curved_render_text