【pub 】 【github 】

dependencies:
  toggle_rotate: $lastVersion
Copy the code

A, description,

Goal: Make a component rotate when clicked, and rotate back when clicked.

The simplest use Duration, curve, direction Can contain all components Rotation Angle
1. All attributes:
The name of the type function note The default
rad double Rotation Angle Radian system pi / 2
durationMs int Animation duration ms 200
curve Curve The animation curve Curves.fastOutSlowIn
clockwise bool Whether to rotate clockwise true
onTap Function Click on the event @required null
child Widget Child components @required null

2. Simplest use:

ToggleRotate(child: Icon(Icons. Arrow_upward,size: 60,color: Colors. OrangeAccent), onTap: () {}, // Click the event),Copy the code

3. Specify the duration, curve, and direction

ToggleRotate(Curve: Curves. Activity, durationMs: 400,// Animation length approval: false, // Clockwise child: Icon(Icons.arrow_upward,size: 60,color: Colors.orangeAccent), onTap: () {}, ),Copy the code

4. Rotate and switch all components

ToggleRotate(
  curve: Curves.decelerate,
  durationMs: 400,
  child: Image(width:60,height: 60,image: AssetImage("assets/images/icon_28.jpg")),
  onTap: () {},
)
Copy the code

5. Angle that can be rotated

ToggleRotate(
  rad: pi / 4,
  curve: Curves.linear,
  child: Image(width:60,height: 60,image: AssetImage("assets/images/icon_28.jpg")),
  onTap: () {},
)
Copy the code

Two, the implementation principle

Click on some animation effect is better, by the way, pull out into a component to share

This widget is a classic example of animation, so it’s interesting to look at the implementation


1. Customize components

Let’s start analyzing if we have any states. Obviously, we need to rotate the component when we click

Component has a rotation is a state variable, in the process of rotating Angle is also a state Can be said to want to achieve animation, basically is based on the StatefulWidget, first to write a basic components Due to the movie, to be with SingleTickerProviderStateMixin

library toggle_rotate; import 'dart:math'; import 'package:flutter/material.dart'; class ToggleRotate extends StatefulWidget { final Widget child; final Function onTap; final double rad; final int durationMs; final bool clockwise; final Curve curve; ToggleRotate( {this.child, @required this.onTap, this.rad = pi / 2, this.clockwise = true, this.durationMs = 200, this.curve = Curves.fastOutSlowIn}); @override _ToggleRotateState createState() => _ToggleRotateState(); } class _ToggleRotateState extends State<ToggleRotate> with SingleTickerProviderStateMixin { @override void initState() { super.initState(); } @override void dispose() super.dispose(); } @override Widget build(BuildContext context) { return Container(); }}Copy the code

2. Animator creation and destruction

The value of states includes arc rad of rotation, whether it was rotated or not.

The AnimationController is responsible for making the number change evenly between 0.0 and 1.0. To make the number change rate to the core of the curve through the CurvedAnimation is to determine the size of the radian during each update of the state. The addListener allows you to listen every time the animator is refreshed and the state of the animation can be monitored by the addStatusListener if it’s done _rotated

class _ToggleRotateState extends State<ToggleRotate> with SingleTickerProviderStateMixin { double _rad = 0; bool _rotated = false; AnimationController _controller; Animation _rotate; @override void initState() { _controller = AnimationController( duration: Duration(milliseconds: widget.durationMs), vsync: this) .. addListener(() => setState(() => _rad = (_rotated ? (1 - _rotate.value) : _rotate.value) * widget.rad)) .. addStatusListener((status) { if (status == AnimationStatus.completed) { _rotated = ! _rotated; }}); _rotate = CurvedAnimation(parent: _controller, curve: widget.curve); super.initState(); } @override void dispose() { _controller.dispose(); super.dispose(); }Copy the code

3. Use Transform to Transform

Reset the controller when clicked, and then execute. Otherwise it won’t move the second time

In this case, just the onTap callback click event is exposed for external processing. Deciding if the rotation is clockwise is then complete with the component.

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _controller.reset();
        _controller.forward();
        widget.onTap();
      },
      child: Transform(
        transform: Matrix4.rotationZ(widget.clockwise ? _rad : -_rad),
        alignment: Alignment.center,
        child: widget.child,
      ),
    );
  }
Copy the code

Although it’s a small piece of code, it’s only about 60 lines of code, but it contains a lot of knowledge.

If you want a component that is less stuffy when clicked, use it


The end of the

In addition, I have a Flutter wechat communication group. You are welcome to join and discuss Flutter issues together. I look forward to exchanging ideas with you.

@ZhangFengjietele 2019.02.23 not allowed to transfer

My official number: King of programming contact me – email :[email protected] – wechat :zdl1994328 ~ END ~