Flutter —— Text文字渐变

Flutter Text 设置文本渐变色

 

API是使用TextStyle中的foreground 设置文字颜色渐变,如下图:

https://api.flutter.dev/flutter/painting/TextStyle-class.html

头文件import 'dart:ui' as ui; 

 

根据以上代码构造之后结果如下图行1所示,但是如果Text控件居中并缩短字符串长度后就会发现渐变颜色不同的,如下图行2所示。(最后有相关代码)

通过多次对比发现,渐变色是基于在整个window偏移的,代码中的offset 分别表示Offset from,Offset to 起点与终点偏移量,代码中const Offset(0, 20),const Offset(150, 20),表示从坐标(0,20),到(150,20,修改偏移量为const Offset(100, 20),const Offset(250, 20),结果图行3、4。

所以行2中Text居中后dx还是从0开始,颜色不是正红色开始,查看Gradient.linear,有一个colorStops属性,具体含义可查看相关注释,如下图

在偏移量超过其字符串最大dx的时候,设置colorStops,<double>[0.3,0.9],结果如结果图中的行5,通过调整colorStops,可以得到想要的渐变效果。

注意: 设置渐变色不能同时设置TextStyle的color属性,否则会报错,如下图:

设置渐变色还有另外一种写法:

Text(

  'Greetings, planet!',

  style: TextStyle(

      fontSize: 30,

      foreground: Paint()

        ..shader = LinearGradient(colors: [

          Colors.red,

          Colors.yellow,

        ]).createShader(Rect.fromLTWH(0, 0, 150, 0))),

)

或者

Gradient gradient =  LinearGradient(colors: [

  Colors.red,

  Colors.yellow,

]);

Text(

  'Greetings, planet!',

  style: TextStyle(

      fontSize: 30,

      foreground: Paint()

        ..shader = gradient.createShader(Rect.fromLTWH(0, 0, 100, 0))),

)

 

createShader中的Rect和上面的偏移量类似,又不完全相同,Rect.fromLTWH(0, 0, 100, 0),  width,表示渐变的宽度范围,结果如图行6。

这时候只是固定位置text设置渐变色,如果在不确定text坐标的时候如何使用渐变色

1、 设置Text的key值globalKey,通过globalKey 获取Text控件的size及position

final RenderBox box = globalKey.currentContext.findRenderObject();

final size = box.size;

final topLeftPosition = box.localToGlobal(Offset.zero);

2、如果设置的比较多可以封装组件widget,根据组件context获取位置大小,具体可查看以下的TextGradientColorWidget

 

验证相关代码:

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

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
        // This makes the visual density adapt to the platform that you run
        // the app on. For desktop platforms, the controls will be smaller and
        // closer together (more dense) than on mobile platforms.
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          // Here we take the value from the MyHomePage object that was created by
          // the App.build method, and use it to set our appbar title.
          title: Text(widget.title),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
                margin: EdgeInsets.only(top: 20, bottom: 20),
                child: Text(
                  '1.Greetings, planet!',
                  style: TextStyle(
                      fontSize: 30,
                      foreground: Paint()
                        ..shader = ui.Gradient.linear(
                            const Offset(0, 20), const Offset(150, 20), <Color>[
                          Colors.red,
                          Colors.yellow,
                        ])),
                )),
            Container(
                margin: EdgeInsets.only(top: 20, bottom: 20),
                child: Center(
                    child: Text(
                  '2.Greetings!',
                  style: TextStyle(
                      fontSize: 30,
                      foreground: Paint()
                        ..shader = ui.Gradient.linear(
                            const Offset(0, 20), const Offset(150, 20), <Color>[
                          Colors.red,
                          Colors.yellow,
                        ])),
                ))),
            Container(
                margin: EdgeInsets.only(top: 20, bottom: 20),
                child: Text(
                  '3.Greetings, planet!',
                  style: TextStyle(
                      fontSize: 30,
                      foreground: Paint()
                        ..shader = ui.Gradient.linear(const Offset(100, 20),
                            const Offset(250, 20), <Color>[
                          Colors.red,
                          Colors.yellow,
                        ])),
                )),
            Container(
              margin: EdgeInsets.only(top: 20, bottom: 20),
              child: Center(
                  child: Text(
                '4.Greetings!',
                style: TextStyle(
                    fontSize: 30,
                    foreground: Paint()
                      ..shader = ui.Gradient.linear(
                          const Offset(100, 20), const Offset(250, 20), <Color>[
                        Colors.red,
                        Colors.yellow,
                      ])),
              )),
            ),
            Container(
                margin: EdgeInsets.only(top: 20, bottom: 20),
                child: Center(
                    child: Text(
                  '5.Greetings!',
                  style: TextStyle(
                      fontSize: 30,
                      foreground: Paint()
                        ..shader = ui.Gradient.linear(const Offset(100, 20),
                            const Offset(250, 20), <Color>[
                          Colors.red,
                          Colors.yellow,
                        ], <double>[
                          0.3,
                          0.9
                        ])),
                ))),
            Container(
                margin: EdgeInsets.only(top: 20, bottom: 20),
                child: Text(
                  '6.Greetings, planet!',
                  style: TextStyle(
                      fontSize: 30,
                      foreground: Paint()
                        ..shader = LinearGradient(colors: [
                          Colors.red,
                          Colors.yellow,
                        ]).createShader(Rect.fromLTWH(0, 0, 150, 0))),
                )),
            Container(
              margin: EdgeInsets.only(top: 20, bottom: 20),
              child: Center(
                child: TextGradientColorWidget(data: "7.Greetings", colors: [
                  Colors.red,
                  Colors.yellow,
                ]),
              ),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                Center(
                  child: TextGradientColorWidget(data: "Greetings", colors: [
                    Colors.red,
                    Colors.yellow,
                  ]),
                ),
                Center(
                  child: TextGradientColorWidget(data: "Greetings", colors: [
                    Colors.red,
                    Colors.yellow,
                  ]),
                )
              ],
            )
          ],
        ) // This trailing comma makes auto-formatting nicer for build methods.
        );
  }
}
//根据实际需求设置相关参数
class TextGradientColorWidget extends StatefulWidget {
  String data;
  TextStyle style;
  List<Color> colors;

  TextGradientColorWidget({Key key, this.data, this.colors}) : super(key: key);

  @override
  _TextGradientColorState createState() => _TextGradientColorState();
}

class _TextGradientColorState extends State<TextGradientColorWidget> {
  WidgetsBinding widgetsBinding = WidgetsBinding.instance;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    if (widget.colors != null) {
      widgetsBinding.addPostFrameCallback((timeStamp) {
        final RenderBox box = context.findRenderObject();
        var left = 0.0;
        var width = 0.0;
        if (box != null) {
          final topLeftPosition = box.localToGlobal(Offset.zero);
          final size = box.size;
          left = topLeftPosition.dx;
          width = size.width;
          setState(() {
            widget.style = TextStyle(
                fontSize: 30,
                foreground: Paint()
                  ..shader =
                      LinearGradient(colors: widget.colors, stops: [0.3, 0.8])
                          .createShader(Rect.fromLTWH(left, 0, width, 0)));
          });

          //注意 TextStyle中color和foreground 中colors不能同时设置
        }
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Text(widget.data, style: widget.style);
  }
}
原文地址:https://www.cnblogs.com/lulushen/p/14169602.html