Flutter投票组件使用方法详解

 更新时间:2022年08月24日 09:09:37   作者:怀君  
这篇文章主要为大家详细介绍了Flutter投票组件的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了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,
    );
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Kotlin中的反射机制深入讲解

    Kotlin中的反射机制深入讲解

    反射,简单来说,是一种在运行时动态地访问对象属性和方法的方式,而不需要事先确定这些属性是什么。下面这篇文章主要给大家介绍了关于Kotlin中反射机制的相关资料,需要的朋友可以参考下
    2018-11-11
  • Android 中ListView点击Item无响应问题的解决办法

    Android 中ListView点击Item无响应问题的解决办法

    如果listitem里面包括button或者checkbox等控件,默认情况下listitem会失去焦点,导致无法响应item的事件,怎么解决呢?下面小编给大家分享下listview点击item无响应的解决办法
    2016-12-12
  • Android架构组件LiveData使用详解

    Android架构组件LiveData使用详解

    这篇文章主要介绍了Android架构组件LiveData使用详解的相关资料,需要的朋友可以参考下
    2023-07-07
  • 深入解析android5.1 healthd

    深入解析android5.1 healthd

    这篇文章主要为大家详细介绍了android5.1 healthd的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • Android编程记录ListView标记行状态的方法

    Android编程记录ListView标记行状态的方法

    这篇文章主要介绍了Android编程记录ListView标记行状态的方法,结合实例分析了ListView标记的相关实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • Android实现闹钟小程序

    Android实现闹钟小程序

    这篇文章主要为大家详细介绍了Android实现闹钟小程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-06-06
  • Android BroadcastReceiver广播注册方式总结

    Android BroadcastReceiver广播注册方式总结

    这篇文章主要介绍了Android BroadcastReceiver广播注册方式总结的相关资料,需要的朋友可以参考下
    2017-01-01
  • 详解 WebView 与 JS 交互传值问题

    详解 WebView 与 JS 交互传值问题

    这篇文章主要介绍了详解 WebView 与 JS 交互传值问题的相关资料,需要的朋友可以参考下
    2017-06-06
  • flutter项目引入iconfont阿里巴巴图标

    flutter项目引入iconfont阿里巴巴图标

    这篇文章主要为大家介绍了flutter项目引入iconfont阿里巴巴图标的过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • 超酷炫的Android碎纸机效果推荐

    超酷炫的Android碎纸机效果推荐

    这篇文章运用xml和java实现了Android版的碎纸机动画,效果非常好,推荐给有需要的小伙伴们使用。
    2016-07-07

最新评论