Flutter投票组件使用方法详解

2022-08-24 09:42:11

本文实例为大家分享了Flutter投票组件的使用方法,供大家参考,具体内容如下前景基于公司项目需求,仿照微博实现投票功能。开发遇到的问题1.选项列表的高度,自适应的问题;2.进度条动画的问题;3.列表...

本文实例为大家分享了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()
js
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);
  paphpint.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 cophpntext) =>
   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,
  );
 }
}

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