Flutter投票组件使用方法详解

作者:怀君 时间:2022-05-25 19:07:05 

本文实例为大家分享了Flutter投票组件的使用方法,供大家参考,具体内容如下

前景

基于公司项目需求,仿照微博实现投票功能。

开发遇到的问题

1.选项列表的高度,自适应的问题;
2.进度条动画的问题;
3.列表回收机制,导致进度条动画重复;
4.自定义进度条四周圆角;

如何解决问题

  • 拿到数组列表最长的数据,然后根据屏幕宽度计算,超出一行则设定两行高度,否则使用一行的高度;

_didExceedOneMoreLines(String text, double width, TextStyle style) {
    final span = TextSpan(text: text, style: style);
    final tp =
        TextPainter(text: span, maxLines: 1, textDirection: TextDirection.ltr);
    tp.layout(maxWidth: width);
    if (tp.didExceedMaxLines) {
    //设置item选项的高度
      _itemHeight = 100.w;
    }
  }
  • Widget控件初始化(initState)方法时,使用AnimationController动画,并实现SingleTickerProviderStateMixin,在build方法当中调用 _controller.animateTo()

AnimationController _controller;
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 1),
    )..addListener(() {
        setState(() {});
      });
//触发动画,执行的位置
_controller.animateTo()
  • 在列表数据当中给动画标记字段,让其是否执行动画;当用户投票成功,改变状态执行进度条动画。用户滑动列表之后,将标记改为false。关闭动画效果。

  • 针对修改部分源码,设置进度条圆角控件;

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class RoundLinearProgressPainter extends ProgressIndicator {
  const RoundLinearProgressPainter({
    Key key,
    double value,
    Color backgroundColor,
    Color color,
    Animation<Color> valueColor,
    this.minHeight,
    String semanticsLabel,
    String semanticsValue,
  })  : assert(minHeight == null || minHeight > 0),
        super(
          key: key,
          value: value,
          backgroundColor: backgroundColor,
          color: color,
          valueColor: valueColor,
          semanticsLabel: semanticsLabel,
          semanticsValue: semanticsValue,
        );

  final double minHeight;

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

class _RoundLinearProgressPainterState extends State<RoundLinearProgressPainter>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 1),
      vsync: this,
    )..addListener(() {
        setState(() {});
      });
    if (widget.value != null) _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return widget._buildSemanticsWrapper(
      context: context,
      child: Container(
        constraints: BoxConstraints(
          minWidth: double.infinity,
          minHeight: widget.minHeight ?? 4.0,
        ),
        child: CustomPaint(
          painter: _LinearProgressIndicatorPainter(
            backgroundColor: widget._getBackgroundColor(context),
            valueColor: widget._getValueColor(context),
            value: widget.value,
            animationValue: _controller.value,
          ),
        ),
      ),
    );
  }

  @override
  void didUpdateWidget(RoundLinearProgressPainter oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.value == null && !_controller.isAnimating)
      _controller.repeat();
    else if (widget.value != null && _controller.isAnimating)
      _controller.stop();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

class _LinearProgressIndicatorPainter extends CustomPainter {
  const _LinearProgressIndicatorPainter({
    this.backgroundColor,
    this.valueColor,
    this.value,
    this.animationValue,
  });

  final Color backgroundColor;
  final Color valueColor;
  final double value;
  final double animationValue;

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()
      ..color = backgroundColor
      ..isAntiAlias = true
      ..style = PaintingStyle.fill;
    canvas.drawRect(Offset.zero & size, paint);
    paint.color = valueColor;
    void drawBar(double x, double width) {
      if (width <= 0.0) return;
      RRect rRect;
      ///圆角的宽度
      var radius = Radius.circular(8.w);
      if (value == 1.0) {
      ///当进度条为1时,设置四周圆角
        rRect = RRect.fromRectAndRadius(
            Offset(0.0, 0.0) & Size(width, size.height), radius);
      } else {
        ///小于1时,设置左侧圆角
        rRect = RRect.fromRectAndCorners(
            Offset(0.0, 0.0) & Size(width, size.height),
            topLeft: radius,
            bottomLeft: radius);
      }
      canvas.drawRRect(rRect, paint);
    }

    if (value != null) {
      drawBar(0.0, value.clamp(0.0, 1.0) * size.width);
    }
  }

  @override
  bool shouldRepaint(_LinearProgressIndicatorPainter oldPainter) {
    return oldPainter.backgroundColor != backgroundColor ||
        oldPainter.valueColor != valueColor ||
        oldPainter.value != value ||
        oldPainter.animationValue != animationValue;
  }
}

abstract class ProgressIndicator extends StatefulWidget {
  const ProgressIndicator({
    Key key,
    this.value,
    this.backgroundColor,
    this.color,
    this.valueColor,
    this.semanticsLabel,
    this.semanticsValue,
  }) : super(key: key);

  final double value;

  final Color backgroundColor;

  final Color color;

  final Animation<Color> valueColor;

  final String semanticsLabel;

  final String semanticsValue;

  Color _getBackgroundColor(BuildContext context) =>
      backgroundColor ?? Theme.of(context).colorScheme.background;

  Color _getValueColor(BuildContext context) =>
      valueColor?.value ?? color ?? Theme.of(context).colorScheme.primary;

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(PercentProperty('value', value,
        showName: false, ifNull: '<indeterminate>'));
  }

  Widget _buildSemanticsWrapper({
    BuildContext context,
    Widget child,
  }) {
    String expandedSemanticsValue = semanticsValue;
    if (value != null) {
      expandedSemanticsValue ??= '${(value * 100).round()}%';
    }
    return Semantics(
      label: semanticsLabel,
      value: expandedSemanticsValue,
      child: child,
    );
  }
}

来源:https://blog.csdn.net/u013290250/article/details/120484975

标签:Flutter,投票组件
0
投稿

猜你喜欢

  • java8中:: 用法示例(JDK8双冒号用法)

    2023-11-25 06:21:21
  • 通过图例了解PowerDesigner使用方法

    2021-06-05 23:16:24
  • Android自定义view实现列表内左滑删除Item

    2021-10-28 17:19:50
  • java利用url实现网页内容的抓取

    2023-05-14 11:10:21
  • Android如何实现APP自动更新

    2021-10-31 06:09:27
  • C# Winform中如何绘制动画示例详解

    2022-03-28 13:26:26
  • SpringBoot中@ConfigurationProperties 配置绑定

    2023-04-07 04:02:57
  • 解决springboot配置logback-spring.xml不起作用问题

    2022-09-10 11:21:24
  • Spring Cloud Gateway 记录请求应答数据日志操作

    2021-12-27 07:25:53
  • 移动开发Spring Boot外置tomcat教程及解决方法

    2023-08-25 11:47:33
  • Java实现pdf转图片案例

    2022-08-11 21:45:41
  • Java文本文件操作方法实例详解

    2021-12-14 10:03:21
  • Android编程中EditText限制文字输入的方法

    2023-07-19 07:30:48
  • Android用PopupWindow实现自定义overflow

    2021-08-08 22:56:06
  • mybatis中数据加密与解密的实现

    2022-04-21 22:49:16
  • Java 爬虫工具Jsoup详解

    2022-04-11 03:46:16
  • Java读取txt文件中的数据赋给String变量方法

    2022-08-04 22:32:19
  • Android使用开源框架Fresco处理图片

    2022-01-24 09:30:08
  • Spring AOP如何自定义注解实现审计或日志记录(完整代码)

    2022-03-28 02:19:34
  • C#中委托用法实例详解

    2022-11-02 23:24:40
  • asp之家 软件编程 m.aspxhome.com