91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用Flutter StrikeThroughTextAnimation實現文字中劃線動畫

發布時間:2023-04-04 16:05:19 來源:億速云 閱讀:85 作者:iii 欄目:開發技術

這篇文章主要介紹“怎么使用Flutter StrikeThroughTextAnimation實現文字中劃線動畫”,在日常操作中,相信很多人在怎么使用Flutter StrikeThroughTextAnimation實現文字中劃線動畫問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用Flutter StrikeThroughTextAnimation實現文字中劃線動畫”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

    基本使用

    StrikeThroughText(
        text: "1. Task Item StrikeThroughText",
        textStyle: const TextStyle(
            fontSize: 18,
        ),
        inactiveTextColor: Colors.red,
        textColor: Colors.blue,
        strikethrough: isCheck,
        onChange: (value) {
            setState(() {
                isCheck = value;
            });
        },
    )

    實現

    1、布局

    首先完成 widget 的布局和樣式,這里采用了 Stack 布局,首先添加文字和文字樣式,在文字的中間放置一個橫線作為中劃線。 大致布局如下:

     Stack(
          children: [
            Text(
              "Task Item",
              maxLines: 1,
              softWrap: false,
              style: TextStyle(
                fontSize: 18,
              ),
            ),
            Positioned(
              top: 0,
              bottom: 0,
              left: 0,
              right: 0,
              child: CustomPaint(
                  painter: StrikeThroughTextPainter(
                      ...,
                  ),
              ),
            ),
          ],
        );

    2、繪制中劃線

    繪制中劃線,首先需要知道要繪制多長。這里可以使用 TextPainter 來測繪文字的寬高,這里寫成一個通用的方法,傳入 Text 的text和textStyle,返回文字的寬高:

    class TextSizeBox {
      final double width;
      final double height;
      TextSizeBox({required this.width, required this.height});
      factory TextSizeBox.fromText(String text, {TextStyle? textStyle}) {
        final TextPainter textPainter = TextPainter(
          text: TextSpan(text: text, style: textStyle),
          maxLines: 1,
          textDirection: TextDirection.ltr,
        )..layout(minWidth: 0, maxWidth: double.infinity);
        return TextSizeBox(width: textPainter.width, height: textPainter.height);
      }
    }

    知道了文字的寬就等于知道繪制文字的中劃線寬度了。

    StrikeThroughTextPainter(
        width: TextSizeBox.fromText(widget.text,  textStyle: widget.textStyle).width,
        height: 2.0,
        color: Colors.grey,
    )
    class StrikeThroughTextPainter extends CustomPainter {
      final double width;
      final double height;
      final Color color;
      StrikeThroughTextPainter(
          {required this.width, required this.height, required this.color});
      @override
      void paint(Canvas canvas, Size size) {
        final paint = Paint()
          ..color = color
          ..strokeWidth = height
          ..strokeCap = StrokeCap.round;
        if (width > 0) {
          canvas.drawLine(
              Offset(0, size.height / 2),
              Offset(width > size.width ? size.width : width, size.height / 2),
              paint);
        }
      }
      @override
      bool shouldRepaint(StrikeThroughTextPainter oldDelegate) {
        return width != oldDelegate.width || height != oldDelegate.height;
      }
    }

    3、動畫

    首先是左右移動動畫,先創建一個 AnimationController ,在創建一個Tween<Offset>來控制左右移動的偏移量

     _offsetController = AnimationController(
          vsync: this,
          duration: const Duration(milliseconds: 100),
        );
    _offsetAnimation = Tween<Offset>(
          begin: const Offset(0.0, 0.0),
          end: const Offset(0.2, 0.0),
        ).animate(CurvedAnimation(
          parent: _offsetController,
          curve: Curves.easeInOut,
        ));

    使用 SlideTransition 來控制左右平移偏移量

    SlideTransition(
    	position: _offsetAnimation,
    	child: Stack(
    		......
    	),
    )

    因為顏色變化和劃中劃線是同步進行的,所以只需要創建一個AnimationController來控制顏色和進度的動畫

    _animationController = AnimationController(
          vsync: this,
          duration: const Duration(milliseconds: 300),
          value: 1,
        );
    _animation = Tween(begin: 0.0, end: 1.0).animate(_animationController);
    _animationColor = ColorTween(
                begin: Colors.black87,
                end: Colors.grey)
            .animate(_animationController);

    接下來就是在需要動畫的 widget 上放上動畫就可以了.

    完整代碼

    import 'package:flutter/material.dart';
    class StrikeThroughText extends StatefulWidget {
      final String text;
      final TextStyle textStyle;
      final bool strikethrough;
      final Color? textColor;
      final Color? inactiveTextColor;
      final ValueChanged? onChange;
      const StrikeThroughText({
        Key? key,
        required this.text,
        required this.textStyle,
        this.strikethrough = false,
        this.textColor,
        this.inactiveTextColor,
        this.onChange,
      }) : super(key: key);
      @override
      StrikeThroughTextState createState() => StrikeThroughTextState();
    }
    class StrikeThroughTextState extends State<StrikeThroughText>
        with TickerProviderStateMixin {
      late AnimationController _animationController;
      late Animation<double> _animation;
      late Animation _animationColor;
      late AnimationController _offsetController;
      late Animation<Offset> _offsetAnimation;
      @override
      void initState() {
        super.initState();
        _animationController = AnimationController(
          vsync: this,
          duration: const Duration(milliseconds: 300),
          value: widget.strikethrough ? 1 : 0,
        );
        _animation = Tween(begin: 0.0, end: 1.0).animate(_animationController);
        _animationColor = ColorTween(
                begin: widget.textColor ?? Colors.black87,
                end: widget.inactiveTextColor ?? Colors.grey)
            .animate(_animationController);
        _offsetController = AnimationController(
          vsync: this,
          duration: const Duration(milliseconds: 100),
        );
        _offsetAnimation = Tween<Offset>(
          begin: const Offset(0.0, 0.0),
          end: const Offset(0.2, 0.0),
        ).animate(CurvedAnimation(
          parent: _offsetController,
          curve: Curves.easeInOut,
        ));
      }
      @override
      void didUpdateWidget(covariant StrikeThroughText oldWidget) {
        super.didUpdateWidget(oldWidget);
        if (oldWidget.strikethrough != widget.strikethrough) {
          if (widget.strikethrough) {
            startAnimation();
          } else {
            reset();
          }
        }
      }
      @override
      void dispose() {
        _animationController.dispose();
        _offsetController.dispose();
        super.dispose();
      }
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          onTap: () {
            if (widget.strikethrough) {
              widget.onChange?.call(false);
            } else {
              widget.onChange?.call(true);
            }
          },
          child: SlideTransition(
            position: _offsetAnimation,
            child: Stack(
              children: [
                AnimatedBuilder(
                    animation: _animationController,
                    builder: (context, child) {
                      return Text(
                        widget.text,
                        maxLines: 1,
                        softWrap: false,
                        style: widget.textStyle.copyWith(
                          color: _animationColor.value,
                          overflow: TextOverflow.clip,
                        ),
                      );
                    }),
                // AnimatedDefaultTextStyle(
                //   style: widget.textStyle..copyWith(color: _animationColor.value),
                //   duration: const Duration(milliseconds: 500),
                //   child: Text(widget.text),
                // ),
                AnimatedBuilder(
                  animation: _animation,
                  builder: (context, child) {
                    return Positioned(
                      left: 0,
                      right: 0,
                      top: 0,
                      bottom: 0,
                      child: CustomPaint(
                        painter: StrikeThroughTextPainter(
                          width: TextSizeBox.fromText(widget.text,
                                      textStyle: widget.textStyle)
                                  .width *
                              _animation.value,
                          height: 2.0,
                          color: widget.inactiveTextColor ?? Colors.grey,
                        ),
                      ),
                    );
                  },
                ),
              ],
            ),
          ),
        );
      }
      void startAnimation() async {
        _animationController.reset();
        await _offsetController.forward();
        await _offsetController.reverse();
        _animationController.forward();
      }
      void reset() {
        _animationController.reset();
      }
    }
    class StrikeThroughTextPainter extends CustomPainter {
      final double width;
      final double height;
      final Color color;
      StrikeThroughTextPainter(
          {required this.width, required this.height, required this.color});
      @override
      void paint(Canvas canvas, Size size) {
        final paint = Paint()
          ..color = color
          ..strokeWidth = height
          ..strokeCap = StrokeCap.round;
        if (width > 0) {
          canvas.drawLine(
              Offset(0, size.height / 2),
              Offset(width > size.width ? size.width : width, size.height / 2),
              paint);
        }
      }
      @override
      bool shouldRepaint(StrikeThroughTextPainter oldDelegate) {
        return width != oldDelegate.width || height != oldDelegate.height;
      }
    }
    class TextSizeBox {
      final double width;
      final double height;
      TextSizeBox({required this.width, required this.height});
      factory TextSizeBox.fromText(String text, {TextStyle? textStyle}) {
        final TextPainter textPainter = TextPainter(
          text: TextSpan(text: text, style: textStyle),
          maxLines: 1,
          textDirection: TextDirection.ltr,
        )..layout(minWidth: 0, maxWidth: double.infinity);
        return TextSizeBox(width: textPainter.width, height: textPainter.height);
      }
    }

    到此,關于“怎么使用Flutter StrikeThroughTextAnimation實現文字中劃線動畫”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    阳原县| 友谊县| 靖州| 凌云县| 温泉县| 太仓市| 鄱阳县| 锦州市| 嘉峪关市| 府谷县| 浏阳市| 来安县| 牙克石市| 女性| 凌海市| 沙坪坝区| 襄垣县| 吉安县| 大埔区| 诸暨市| 茶陵县| 莲花县| 资源县| 民勤县| 右玉县| 融水| 盐池县| 富民县| 普格县| 石阡县| 封开县| 南安市| 兴化市| 大安市| 安远县| 文水县| 共和县| 大荔县| 图们市| 宣化县| 宁化县|