flutter如何做一个点击后有动画的组件

[TOC]

AnimationController动画控制器

说明

  • 只可以为double值,因此我们才需要Animation来做动画对象,AnimationController做控制器
AnimationController({
    double? value,
    this.duration,
    this.reverseDuration,
    this.debugLabel,
    this.lowerBound = 0.0,
    this.upperBound = 1.0,
    this.animationBehavior = AnimationBehavior.normal,
    required TickerProvider vsync,
  })

示例

class _MyHomePageState extends State<MyHomePage> with SingleTickerProvider特性StateMixin  //具备TickerProvider特性

//定义动画初始值
AnimationController _controller;
double _size = 100;

//动画监听
  @override
  void initState() {
    super.initState();
     _controller =  AnimationController(
        vsync: this,
        duration: Duration(milliseconds: 500),
       //初始值
        lowerBound: 100,
       //value最大值
        upperBound: 200)
      ..addStatusListener((AnimationStatus status) {
        if(status == AnimationStatus.completed){
          _controller.reverse();
        }else if(status == AnimationStatus.dismissed){
          _controller.forward();
        }
      })
      ..addListener(() {
        setState(() {
          _size = _controller.value;
        });
      });
  }
//body
 Center(
        child: GestureDetector(
          onTap: (){_controller.forward();},
          child: Container(
            height: _size,
            width: _size,
            color: Colors.blue,
            alignment: Alignment.center,
            child: Text("点我,开始动画"),
          ),
        ),
        )
//释放资源        
@override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }        

vsync

  • vsync:TickerProvider(抽象类),用于接收动画变化过程中的通知,类似于接口回调
  • 用户在使用时可以选择TickerProviderStateMixin或SingleTickerProviderStateMixin
  • 混入mixins时,使用关键字with,mixin是一种在多个类层次结构中重用类代码的方法
  • 单个 AnimationController 的时候使用 SingleTickerProviderStateMixin
  • 多个 AnimationController 使用 TickerProviderStateMixin

Animation动画

说明

  • 可以为任意的值
  • 可以是非线性执行
  • 是一个抽象类

Tween

  • 继承了Animatable
  • Tween是一个无状态(stateless)对象,需要begin和end值。Tween的唯一职责就是定义从输入范围到输出范围的映射。输入范围通常为0.0到1.0,但这不是必须的。
  • Tween对象不存储任何状态。相反,它提供了evaluate(Animation animation)方法获取动画当前值。 Animation对象的当前值可以通过value()方法取到。evaluate函数还执行一些其它处理,例如分别确保在动画值为0.0和1.0时返回开始和结束状态,这个方法一般不需要使用,除非想要获取特定时间的动画值
  • 通常需要使用它的animation()的方法创建一个 Animation 对象。

示例

_animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 3000));
    _animation = new CurvedAnimation(parent: _animationController, curve: Curves.easeIn)
      ..addListener((){
        setState(() {
        });
      });
    _sizeTween = new Tween(begin: 0.0,end: 300.0);
    _colorTween = new ColorTween(begin: Colors.transparent,end: Colors.amberAccent);

    _animationController.forward();
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('animation'),
      ),
      body: new Center(
        child: new Container(
          color: _colorTween.evaluate(_animation),
          width: _sizeTween.evaluate(_animation),
          height: _sizeTween.evaluate(_animation),
        ),
      ),
    );

源码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class UserMsg extends StatefulWidget {
  UserMsg({super.key, required this.text});
  String text;
  @override
  State<UserMsg> createState() => _UserMsgState();
}

class _UserMsgState extends State<UserMsg> with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _scaleAnimation;
  final _initialScale = 1.0;
  final _tappedScale = 1.1;
  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      duration: const Duration(milliseconds: 300),
      vsync: this,
    );

    _scaleAnimation = Tween<double>(
      begin: _initialScale,
      end: _tappedScale,
    ).animate(_animationController);
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  void _onEnter(PointerEnterEvent event) {
    if (_animationController.status != AnimationStatus.forward) {
      //动画开始执行
      _animationController.forward();
    }
  }

  void _onExit(PointerExitEvent event) {
    //反向执行
    _animationController.reverse();
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
        onEnter: _onEnter,
        onExit: _onExit,
        child: GestureDetector(
          child: ScaleTransition(
            scale: _scaleAnimation,
            child: Container(
              width: MediaQuery.of(context).size.width * 0.3,
              height: MediaQuery.of(context).size.width * 0.04,
              decoration: BoxDecoration(
                borderRadius: const BorderRadius.all(Radius.circular(20)),
                border: Border.all(
                  color: Colors.black, // 边框颜色
                  width: 4.0, // 边框宽度
                ),
              ),
              child: Center(
                child: Text(
                  widget.text,
                  style: TextStyle(
                    fontSize: MediaQuery.of(context).size.width * 0.02,
                  ),
                ),
              ),
            ),
          ),
        ));
  }
}

Tags:

Comments are closed

       

粤公网安备44011302004556号