Flutter菜品选择动画按钮

329 阅读1分钟

效果如下图

使用Flow实现水平展开/收起的功能

import 'package:flutter/material.dart';

class TakeAwaySelectWidget extends StatefulWidget {
  @override
  _TakeAwaySelectWidgetState createState() => _TakeAwaySelectWidgetState();
}

class _TakeAwaySelectWidgetState extends State<TakeAwaySelectWidget>
    with SingleTickerProviderStateMixin {
  Animation _animation;
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    /// 创建线性动画
    _controller =
        AnimationController(duration: Duration(milliseconds: 300), vsync: this);
    _animation = Tween(begin: 100.0, end: 200.0)
        .chain(CurveTween(curve: Curves.linear))
        .animate(_controller);
    _animation.addListener(() {
      setState(() {});
    });
  }

  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("菜品添加按钮"),
      ),
      body: Center(
        child: Container(
            decoration: BoxDecoration(
                color: Colors.green,
                borderRadius: BorderRadius.all(Radius.circular(35))),
            child: Flow(
              delegate: MyFlowDelegate(_animation),
              children: [
                InkWell(
                    onTap: () {
                      if (_count == 0) {
                        _controller.forward();
                      } else {
                        setState(() {});
                      }
                      _count++;
                    },
                    child: Text(
                      "+",
                      style: TextStyle(color: Colors.white, fontSize: 36),
                    )),
                InkWell(
                    splashColor: Colors.red,
                    onTap: () {
                      setState(() {
                        _count--;
                      });
                      if (_count == 0) {
                        _controller.reverse();
                      }
                    },
                    child: Text(
                      "-",
                      style: TextStyle(color: Colors.white, fontSize: 36),
                    )),
                Text(
                  "${_count}",
                  style: TextStyle(color: Colors.white, fontSize: 30),
                )
              ],
            )),
      ),
    );
  }
}
class MyFlowDelegate extends FlowDelegate {
  final Animation animation;

  MyFlowDelegate(this.animation);

  @override
  void paintChildren(FlowPaintingContext context) {
    Size parentSize = context.size;
    /// 计算动画执行的百分比
    double percentage = (parentSize.width - 100) / 100;
    for (int i = 0; i < context.childCount; ++i) {
      Size childSize = context.getChildSize(i);
      /// widget从开始位置到最后位置总共的偏移
      double offset = parentSize.width / 2 - childSize.width / 2 - 35;
      double x;
      if (i == 0) {
        /// 添加widget的x轴位置
        x = parentSize.width / 2 - childSize.width / 2 + offset * percentage;
      } else if (i == 1) {
        /// 减少widget的x轴位置
        x = parentSize.width / 2 - childSize.width / 2 - offset * percentage;
      } else if (i == 2) {
        /// 显示个数widget的x轴位置
        x = parentSize.width / 2 - childSize.width / 2;
      }
      double y = parentSize.height / 2 - childSize.height / 2;
      context.paintChild(
        i,
        transform: Matrix4.translationValues(x, y, 0),
      );
      /// 开始的的状态,只绘制添加Widget
      if (animation.value == 100 && i == 0) {
        return;
      }
    }
  }

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

  @override
  bool shouldRelayout(FlowDelegate oldDelegate) {
    return true;
  }

  @override
  Size getSize(BoxConstraints constraints) {
    /// width 使用animation.value 100--200
    return Size(animation.value, 70);
  }
}