0

尝试使用 CustomPainter 选中和取消选中动画来创建 MyRadio。Drwing all...但无法从另一个元素更改无线电组中的视图状态(运行动画)。无线电代码:

import 'package:flutter/material.dart';

class MyRadio<T> extends StatefulWidget {
  final T value;
  final T? groupValue;
  final String label;
  final String text;
  final ValueChanged<T?> onChanged;
  final double size;

  const MyRadio(
      {Key? key,
      required this.value,
      this.groupValue,
      required this.label,
      required this.text,
      required this.onChanged,
      this.size = 20.0})
      : super(key: key);

  @override
  State<MyRadio<T>> createState() => _MyRadioState<T>();
}

class _MyRadioState<T> extends State<MyRadio<T>> with TickerProviderStateMixin {
  late Animation<double> radiusAnimation;
  late Animation<double> labelAnimation;
  late AnimationController radiusAnimationController;
  late AnimationController labelAnimationController;

  bool check() {
    return (widget.groupValue != null && widget.groupValue == widget.value)
        ? true
        : false;
  }

  @override
  void initState() {
    super.initState();

    radiusAnimationController = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 300));
    labelAnimationController = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 300));
    Tween<double> _radiusTween = Tween(begin: widget.size, end: 0.0);

    Tween<double> _labelTween = Tween(begin: 0.0, end: widget.size);

    radiusAnimation = _radiusTween.animate(radiusAnimationController)
      ..addListener(() => setState(() {}))
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          labelAnimationController.forward();
        }
        if (status == AnimationStatus.dismissed) {
          labelAnimationController.repeat();
        }
      });
    labelAnimation = _labelTween.animate(labelAnimationController)
      ..addListener(() => setState(() {}))
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          labelAnimationController.forward();
        } else if (status == AnimationStatus.dismissed) {
          labelAnimationController.forward();
        }
      });
    if (check()) {
      radiusAnimationController.forward();
    }
  }

  @override
  void dispose() {
    radiusAnimationController.dispose();
    labelAnimationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: AnimatedBuilder(
        builder: (context, snapshot) {
          return CustomPaint(
            painter: ShapePainter(
                radius: radiusAnimation.value,
                labelScale: labelAnimation.value),
            child: Container(
              decoration: BoxDecoration(border: Border.all()),
              width: widget.size * 2,
              height: widget.size * 2,
            ),
          );
        },
        animation: radiusAnimation,
      ),
      onTap: () {
        widget.onChanged(widget.value);

        if (!check()) {
          radiusAnimationController.forward();
        }
      },
    );
  }
}

class ShapePainter extends CustomPainter {
  final double radius;
  final double labelScale;

  ShapePainter({required this.labelScale, required this.radius});

  @override
  void paint(Canvas canvas, Size size) {
    var animateBrush = Paint()
      ..color = Colors.white
      ..strokeWidth = 3
      ..strokeCap = StrokeCap.round;

    var fillBrush = Paint()
      ..color = Colors.teal
      ..strokeWidth = 3
      ..strokeCap = StrokeCap.round;

    var labelBrush = Paint()
      ..color = Colors.white
      ..strokeWidth = 4
      ..style = PaintingStyle.stroke
      ..strokeCap = StrokeCap.round;

    Offset center = Offset(size.width / 2, size.height / 2);

    canvas.drawCircle(center, size.width / 2, fillBrush);
    canvas.drawCircle(center, radius - 3, animateBrush);

    canvas.drawPath(_getCheckIconPath(labelScale * 2, size.width), labelBrush);
  }

  Path _getCheckIconPath(double s, ws) {
    Path path = Path();
    double size = s * 0.15;
    double x = -3 / 2 * size + ws / 2;
    double y = ws / 2;
    path.moveTo(x, y);
    path.lineTo(x + size, y + size);
    path.lineTo(x + 3 * size, y - size);
    return path;
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

演示代码:

import 'package:flutter/material.dart';
import 'package:testapp/ui/my_radio.dart';

class RadioDemo extends StatefulWidget {
  const RadioDemo({Key? key}) : super(key: key);

  @override
  State createState() => _RadioDemoState();
}

class _RadioDemoState extends State<RadioDemo> {
  String _groupValue = "1";

  ValueChanged<String?> _valueChangedHandler() {
    return (value) => setState(() => _groupValue = value!);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Test'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(_groupValue),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              MyRadio<String>(
                value: '1',
                groupValue: _groupValue,
                onChanged: _valueChangedHandler(),
                label: '1',
                text: 'Phone Gap',
              ),
              const SizedBox(
                width: 30,
              ),
              MyRadio<String>(
                value: '2',
                groupValue: _groupValue,
                onChanged: _valueChangedHandler(),
                label: '2',
                text: 'Appcelerator',
              ),
            ],
          )
        ],
      ),
    );
  }
}

使用来源:https ://medium.com/flutterdevs/exploring-custom-radio-button-in-flutter-4a93a7892185

SetState 不工作!!!!

4

0 回答 0