Flutter Demo: 径向菜单动画

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math.dart' show radians;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SizedBox.expand(
          child: RadialMenu(),
        ),
      ),
    );
  }
}

class RadialMenu extends StatefulWidget {
  @override
  _RadialMenuState createState() => _RadialMenuState();
}

class _RadialMenuState extends State<RadialMenu>
    with SingleTickerProviderStateMixin {
  AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      duration: Duration(milliseconds: 900),
      vsync: this,
    );
  }

  @override
  Widget build(BuildContext context) {
    return RadialAnimetion(
      controller: controller,
    );
  }
}

class RadialAnimetion extends StatelessWidget {
  RadialAnimetion({Key key, this.controller})
      : scale = Tween<double>(
          begin: 1.0,
          end: 0.0,
        ).animate(
          CurvedAnimation(
            parent: controller,
            curve: Curves.fastOutSlowIn,
          ),
        ),
        translation = Tween<double>(
          begin: 0.0,
          end: 100.0,
        ).animate(
          CurvedAnimation(
            parent: controller,
            curve: Curves.linear,
          ),
        ),
        rotation = Tween<double>(
          begin: 0.0,
          end: 360.0,
        ).animate(
          CurvedAnimation(
            parent: controller,
            curve: Interval(0.0, 0.8), // 到80%结束
          ),
        ),
        super(key: key);
  final AnimationController controller;
  final Animation<double> scale;
  final Animation<double> translation;
  final Animation<double> rotation;

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: (context, builder) {
        return Transform.rotate(
          angle: radians(rotation.value),
          child: Stack(
            alignment: Alignment.center,
            children: <Widget>[
              _buildButton(0, color: Colors.orange, icon: Icons.cloud_upload),
              _buildButton(45, color: Colors.yellow, icon: Icons.comment),
              _buildButton(90, color: Colors.pink, icon: Icons.color_lens),
              _buildButton(135, color: Colors.green, icon: Icons.date_range),
              _buildButton(180, color: Colors.blueGrey, icon: Icons.details),
              _buildButton(225,
                  color: Colors.purple, icon: Icons.do_not_disturb_on),
              _buildButton(270, color: Colors.lime, icon: Icons.drafts),
              _buildButton(315,
                  color: Colors.indigo, icon: Icons.error_outline),
              Transform.scale(
                scale: scale.value - 1,
                child: FloatingActionButton(
                  child: Icon(Icons.close),
                  onPressed: _close,
                  backgroundColor: Colors.red,
                ),
              ),
              Transform.scale(
                scale: scale.value,
                child: FloatingActionButton(
                  child: Icon(Icons.menu),
                  onPressed: _open,
                  backgroundColor: Colors.blue,
                ),
              ),
            ],
          ),
        );
      },
    );
  }

  _buildButton(double angle, {Color color, IconData icon}) {
    // 将[度]转换为弧度。
    final double rad = radians(angle);
    return Transform(
      transform: Matrix4.identity()
        ..translate(
          translation.value * cos(rad),
          translation.value * sin(rad),
        ),
      child: FloatingActionButton(
        backgroundColor: color,
        child: Icon(icon),
        onPressed: () {},
      ),
    );
  }

  _open() {
    controller.forward();
  }

  _close() {
    controller.reverse();
  }
}

猜你喜欢

转载自www.cnblogs.com/ajanuw/p/11127141.html