flutter开发实战-卡片翻转动画效果Transform+IndexedStack+rotateAnimation

news2024/11/26 4:25:18

flutter开发实战-实现卡片翻转动画效果

之前开发中遇到了商品卡片翻转,商品正面是商品图片、商品名称;背面是商品价格,需要做卡片翻转动画。
动画实现即:在一段时间内,快速地多次改变UI外观;由于人眼会产生视觉暂留,所以最终看到的就是一个“连续”的动画。
这里实现翻转动画,实现方案Transform+IndexedStack
IndexedStack在翻转角度不同,显示对应的card信息
index: _rotateAnimation.value < pi / 2.0 ? 0 : 1,

一、效果图

运行后效果图如下

在这里插入图片描述
在这里插入图片描述

二、代码实现

IndexedStack

IndexedStack({
    super.key,
    super.alignment,
    super.textDirection,
    super.clipBehavior,
    StackFit sizing = StackFit.loose,
    this.index = 0,
    super.children,
  }) : super(fit: sizing);

完整动画效果代码如下

import 'dart:async';
import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';

class GoodsCardFlip extends StatefulWidget {
  const GoodsCardFlip({super.key, required this.cardSize});

  final Size cardSize;

  
  State<GoodsCardFlip> createState() => _GoodsCardFlipState();
}

class _GoodsCardFlipState extends State<GoodsCardFlip>
    with TickerProviderStateMixin {
  late AnimationController _animationController;

  // 翻转动画
  late Animation<double> _rotateAnimation;

  late AnimationStatus _lastStatus = AnimationStatus.dismissed;

  Timer? _globalFlipTimer;

  // 定义一个翻转从左往右,为false,如果为true,则从右往左开始翻转
  bool _flipReversal = false;
  int _flipDelay = 0; // 从左向右延迟翻转时间
  int _flipReversalDelay = 0; // 从右向左延迟翻转时间
  bool _isSetFlipDelay = false;

  bool _isDisposed = false;

  
  void initState() {
    // TODO: implement initState
    super.initState();
    _isDisposed = false;

    _flipReversal = false;
    _animationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 500));

    //使用弹性曲线
    _rotateAnimation =
        CurvedAnimation(parent: _animationController, curve: Curves.linear);
    _rotateAnimation = Tween(begin: 0.0, end: pi).animate(_rotateAnimation);

    _animationController.addListener(() {
      if (mounted) {
        setState(() {});
      }
    });

    _animationController.addStatusListener((status) {
      if (status == _lastStatus) return;
      _lastStatus = status;
    });


    // 横屏的全部翻转到价值的控制定时器
    _globalFlipTimer = new Timer.periodic(new Duration(seconds: 15), (timer) {
      // 整体翻转动画
      flipCards();
    });
  }

  void timerDispose() {
    _globalFlipTimer?.cancel();
    _globalFlipTimer = null;
  }

  void animationDispose() {
    _animationController.dispose();
  }

  
  void dispose() {
    // TODO: implement dispose
    animationDispose();
    timerDispose();
    super.dispose();
    _isDisposed = true;
  }

  void switchCard() {}

  
  Widget build(BuildContext context) {
    return buildGlobal();
  }

  Matrix4 _buildTransform() {
    final matrix = Matrix4.identity()
      ..rotateY(_rotateAnimation.value);
    return matrix;
  }

  Widget buildGlobal() {
    return Container(
      width: widget.cardSize.width,
      height: widget.cardSize.height,
      alignment: Alignment.center,
      child: ClipRRect(
        borderRadius:
        BorderRadius.all(Radius.circular(13.0)),
        child: Transform(
          transform: _buildTransform(),
          alignment: Alignment.center,
          child: IndexedStack(
            alignment: Alignment.center,
            children: <Widget>[
              buildFront(),
              buildBack(),
            ],
            index: _rotateAnimation.value < pi / 2.0 ? 0 : 1,
          ),
        ),
      ),
    );
  }

  Widget buildFront() {
    return GoodsImageCard(
      cardSize: widget.cardSize,
    );
  }

  Widget buildBack() {
    return Transform(
      alignment: Alignment.center,
      transform: Matrix4.identity()
        ..rotateY(pi),
      child: GoodsPriceCard(
        cardSize: widget.cardSize,
      ),
    );
  }

// 处理定时器
  void flipCards() {
    int delay = 0;
    if (_isSetFlipDelay == false) {
      // 如果从右向左,翻转时,则卡片在右侧的delay小于卡片在左侧的delay
      // 每次间隔的翻转延迟时间,100毫秒
      double perDelay = 100.0;
      _flipDelay = delay;
      // 如果从右向左,翻转时,则卡片在右侧的delay小于卡片在左侧的delay
      int reversalDelay =
      100;
      _flipReversalDelay = reversalDelay;
    } else {
      if (_flipReversal) {
        // 如果从右向左,翻转时,则卡片在右侧的delay小于卡片在左侧的delay
        delay = _flipReversalDelay;
      } else {
        delay = _flipDelay;
      }
    }

    _isSetFlipDelay = true;

    Future.delayed(Duration(milliseconds: delay), () {
      cardFlip(_flipReversal);
    });
  }

  // 翻转动画
  void cardFlip(bool reverse) {
    if (_isDisposed == true) {
      return;
    }

    if (_animationController.isAnimating) return;
    if (reverse) {
      _animationController.reverse();
    } else {
      _animationController.forward();
    }
    _flipReversal = !_flipReversal;

    if (_flipReversal == true) {
      Future.delayed(Duration(seconds: 5), () {
        flipCards();
      });
    }
  }
}

class GoodsImageCard extends StatelessWidget {
  const GoodsImageCard({super.key, required this.cardSize});
  final Size cardSize;

  
  Widget build(BuildContext context) {
    return Container(
      width: cardSize.width,
      height: cardSize.height,
      color: Colors.greenAccent,
      alignment: Alignment.center,
      child: Text('详情card',style: TextStyle(
        fontSize: 26,
        fontWeight: FontWeight.w700,
        fontStyle: FontStyle.normal,
        color: Colors.white,
        decoration: TextDecoration.none,
      ),),
    );
  }
}

class GoodsPriceCard extends StatelessWidget {
  const GoodsPriceCard({super.key, required this.cardSize});
  final Size cardSize;

  
  Widget build(BuildContext context) {
    return Container(
      width: cardSize.width,
      height: cardSize.height,
      color: Colors.blueAccent,
      alignment: Alignment.center,
      child: Text('价格card',style: TextStyle(
        fontSize: 26,
        fontWeight: FontWeight.w700,
        fontStyle: FontStyle.normal,
        color: Colors.white,
        decoration: TextDecoration.none,
      ),),
    );
  }
}

三、小结

flutter开发实战-Canvas绘图之Path路径动画

flutter开发实战-实现卡片翻转动画效果,实现方案Transform+IndexedStack,IndexedStack在翻转角度不同,显示对应的card信息。

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/764802.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ext JS中定义和使用类Ext JS风格的html 按钮

Ext JS 的按钮样式如下: 按钮的背景色默认为应用的主色调或是灰色系, 也可以通过样式设置按钮的背景色, 详细可以参考: Ext JS 如何设置工具栏按钮和一般按钮保持统一样式 但是, 在实际开发的场景中有可能某些按钮是不能通过Ext JS的Button 类进行创建的, 但是页面效果…

第三章:内存管理——C++的内存管理方式

系列文章目录 文章目录 系列文章目录前言C/C内存分布C语言中动态内存管理方式面试题 C内存管理模式new/delete操作内置类型new和delete操作自定义类型 operator new与operator delete函数new和delete的实现原理内置类型自定义类型 定位new表达式(placement-new)常见面试题mallo…

JDBC 驱动程序类型

什么是JDBC驱动程序&#xff1f; JDBC驱动程序在JDBC API中实现了已定义的接口&#xff0c;用于与数据库服务器进行交互。 例如&#xff0c;使用JDBC驱动程序&#xff0c;您可以通过发送SQL或数据库命令&#xff0c;然后使用Java接收结果来打开数据库连接并与其进行交互。 J…

el-date-picker 宽度溢出浏览器问题

原文链接&#xff1a; el-date-picker 宽度溢出浏览器问题 问题由来 <el-date-picker v-model"Time" type"datetimerange"range-separator"至"start-placeholder"年/月/日 时:分:秒"end-placeholder"年/月/日 时:分:秒"…

通过迁移加速计划迁移到亚马逊云科技

公司出于许多不同的原因迁移到云。也许他们需要关闭一个老化的数据中心。或者&#xff0c;他们正在寻找太昂贵或太难在内部构建和维护的新功能。无论出于何种原因&#xff0c;在开始规划迁移之前&#xff0c;他们还有另一个问题需要回答&#xff1a;哪种云服务适合他们的需求&a…

基于互一致性学习的半监督医学图像分割

文章目录 Mutual Consistency Learning for Semi-supervised Medical Image Segmentation摘要本文方法实验结果 Mutual Consistency Learning for Semi-supervised Medical Image Segmentation 摘要 提出了一种新的互一致性网络(MC-Net)来有效地利用未标记数据进行半监督医学…

修复git diff正文中文乱码

Linux git diff正文中文乱码 在命令行下输入以下命令&#xff1a; $ git config --global core.quotepath false # 显示 status 编码 $ git config --global gui.encoding utf-8 # 图形界面编码 $ git config --global i18n.commit.encoding utf-8 # …

安装linux子系统时,出现的问题

目录 一、事故原因&#xff1a;适配linux子系统问题 二、事故问题&#xff1a;wsl版本问题 一、事故原因&#xff1a;适配linux子系统问题 事故全文&#xff1a; Installing, this may take a few minutes... WslRegisterDistribution failed with error: 0x8007019e Err…

springboot sentinel 安装 整合 样例-分布式/微服务流量控制

sentinel控制台安装 下载地址&#xff1a;https://github.com/alibaba/Sentinel/releases 本次版本&#xff1a;1.8.6 后台启动&#xff1a; nohup java -Dserver.port7080 -Dcsp.sentinel.dashboard.serverlocalhost:7080 -Dproject.namesentinel-dashboard -jar sentinel-…

基于文本内容的垃圾短信识别实战

1、实战的背景与目标 背景&#xff1a; 垃圾短信形式日益多变&#xff0c;相关报告可以在下面网站查看 360互联网安全中心&#xff08;http://zt.360.cn/report/&#xff09; 目标&#xff1a; 基于短信文本内容&#xff0c;建立识别模型&#xff0c;准确地识别出垃圾短信…

【LeetCode热题100】打卡第38天:课程表实现前缀树

文章目录 【LeetCode热题100】打卡第38天&#xff1a;课程表&实现前缀树⛅前言 课程表&#x1f512;题目&#x1f511;题解 实现前缀树&#x1f512;题目&#x1f511;题解 【LeetCode热题100】打卡第38天&#xff1a;课程表&实现前缀树 ⛅前言 大家好&#xff0c;我是…

udx实现揭秘之---------udx的慢启动带宽探测

我们都知道bew wnd*1000/rtt 当慢启动的时候&#xff0c;每收一个ack,可以这样调整发送速度当前sendspeed sendspeed mss/rtt.并且更新wnd->wnd1. udx的变形版本是sendspeed checksize/rtt; 但是这种增加速度太快&#xff0c;在到达临界点的时候&#xff0c;很容易击…

低功耗设计:为可持续发展带来能源效率的突破

引言&#xff1a; 低功耗设计是面向电子设备和系统的一种设计理念&#xff0c;旨在降低设备的能耗和功耗&#xff0c;提高能源利用效率。在当前节能环保的背景下&#xff0c;低功耗设计成为了电子行业的热门话题&#xff0c;它对于延长电池寿命、提高设备性能和减少能源消耗具有…

选读SQL经典实例笔记08_区间查询

1. 计算同一组或分区的行之间的差 1.1. 最终结果集 1.1.1. sql DEPTNO ENAME SAL HIREDATE DIFF ------ ---------- ---------- ----------- ----------10 CLARK 2450 09-JUN-1981 -255010 KING 5000 17-NOV-1981 370010 …

20 - 队列 - 链队列——队列的链式表示和实现

前面我们学习了 先进先出、后进后出 的线性表- 队列,并且我们是使用数组进行了实现,那么这节课我们来使用链表来实现队列,即链队列! 队列的定义 队列(Queue)也是一种线性表, 但是它仅能在一端进行插入,而另一端进行删除的操作 ,插入的一端称为 队尾rear,删除的一端…

针对Weblogic上的shiro漏洞利用工具

工具介绍 日常项目中&#xff0c;可能会碰见部署在weblogic上的shiro&#xff0c;所以先写了这个生成攻击payload的小Demo&#xff0c;方便后面使用。但目前只支持无回显命令执行&#xff0c;后续回显、内存马功能后面出差后再写。 关注【Hack分享吧】公众号&#xff0c;回复关…

【HCIA】12.网络服务与应用

文件传输协议FTP FTP基于TCP&#xff0c;传输较慢&#xff0c;但是比较可靠。典型的C/S架构。双通道协议。TFTP基于UDP&#xff0c;传输较快&#xff0c;但是不可靠。FTP有两种不同的传输模式 ASCII模式 传输文本文件时会对文本内容进行编码方式转换&#xff0c;提高传输效率&…

音视频技术开发周刊 | 302

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 ChatGPT神器Code Interpreter终于开放&#xff0c;到底怎么用&#xff1f;这里有一份保姆级教程 Code Interpreter 已经正式开放。 上海世界AI大会&#xff1a;MidJourney…

Fedproto:原型聚合的联邦学习框架

题目&#xff1a;FedProto: Federated Prototype Learning across Heterogeneous Clients 网址&#xff1a;http://arxiv.org/abs/2105.00243 目录 前言 什么是原型&#xff1f; Fedproto框架 fedproto settings Fedproto算法 优化目标 全局聚合 局部更新 伪代码 前言…

抖音seo源码搭建,抖音矩阵系统源码分发,抖音矩阵账号管理

前言&#xff1a; 抖音seo源码&#xff0c;抖音矩阵系统源码搭建&#xff0c;抖音矩阵同步分发。抖音seo源码部署是需要对接到这些正规接口再来做开发的&#xff0c;目前账号矩阵程序开发的功能&#xff0c;围绕一键管理多个账号&#xff0c;做到定时投放&#xff0c;关键词自动…