Flutter-自定义表情雨下落动画

news2024/11/15 3:24:09
简述

今天给大家分享一个Flutter的表情雨的实现,具体的效果见下图,这个效果其实是工作中的一个小小的需求,这里面单独拿出来讲讲下这个效果的实现思路。

在以前特别是新手,遇到一些动画效果都是拿到需求后,在网络上去找寻类似的效果,然后修改修改就可以了,不知道你们是不是呢?其实从chatgpt出来以后,很多时候对于这种效果我们其实直接就可以问下gpt,gpt会给我们一些思路,只要我们表达的清晰,配合gpt我们会很快实现这个效果。

效果图

emoji.gif

分析

我们如何去问gpt,才能让gpt给出我们想要的结果呢?当然在以前我们都是自己先了解这个效果属于什么效果,比如说 “跑马灯”、“画廊”等等,然后在网络搜索这个关键字查询。但是现在我们不是单纯的搜关键字了,而是用自己的语言把效果用话语表达出来,让gpt知道到底怎么写代码,总结来说你就是产品,gpt是开发人员,你要把产品需求告诉gpt去开发。

ChatGpt问答

用户问:请使用Flutter实现一个widget,这个widget支持设置宽高,其内容是由n个表情从上往下落下,这些表情下落的时机是间隔落下,下落过程中透明度在高度一半的时候透明度逐渐隐藏。
注意: 这里我使用的gpt是3.5版本。

gpt回答代码如下:

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

import 'package:flutter/material.dart';

class FallingEmojisWidget extends StatefulWidget {
 final double width;
 final double height;
 final List<String> emojis;
 final Duration interval;

 const FallingEmojisWidget({
   Key? key,
   required this.width,
   required this.height,
   required this.emojis,
   this.interval = const Duration(milliseconds: 500),
 }) : super(key: key);

 @override
 _FallingEmojisWidgetState createState() => _FallingEmojisWidgetState();
}

class _FallingEmojisWidgetState extends State<FallingEmojisWidget>
   with TickerProviderStateMixin {
 late AnimationController _animationController;
 late Timer _timer;

 List<Widget> _emojiWidgets = [];

 @override
 void initState() {
   super.initState();
   _animationController = AnimationController(
     vsync: this,
     duration: Duration(milliseconds: 1000),
   );
   _timer = Timer.periodic(widget.interval, (_) => _addEmoji());
 }

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

 void _addEmoji() {
   setState(() {
     final emoji = widget.emojis[Random().nextInt(widget.emojis.length)];
     _emojiWidgets.add(_buildEmojiWidget(emoji));
   });
 }

 Widget _buildEmojiWidget(String emoji) {
   final initialOffset = Offset(
     Random().nextDouble() * widget.width,
     -50,
   );
   final targetOffset = Offset(
     initialOffset.dx,
     widget.height / 2,
   );

   final animation = Tween<Offset>(
     begin: initialOffset,
     end: targetOffset,
   ).animate(CurvedAnimation(
     parent: _animationController,
     curve: Curves.easeInOut,
   ));

   return AnimatedBuilder(
     animation: _animationController,
     builder: (context, child) {
       final opacity = _animationController.value < 0.5
           ? (_animationController.value * 2)
           : (1 - (_animationController.value - 0.5) * 2);

       return Positioned(
         left: animation.value.dx,
         top: animation.value.dy,
         child: Opacity(
           opacity: opacity,
           child: Text(
             emoji,
             style: TextStyle(fontSize: 24),
           ),
         ),
       );
     },
   );
 }

 @override
 Widget build(BuildContext context) {
   return Container(
     width: widget.width,
     height: widget.height,
     child: Stack(
       children: _emojiWidgets,
     ),
   );
 }
}`

gpt第一次回答你的代码其实已经告诉你实现思路了,比如上面的代码,通过gpt的回答我们知道可以使用Stack控件,然后在Stack中添加我们想要的数量的表情widget,然后通过AnimatedBuilder+Positioned实现表情下落的效果。是不是很6,从开始没有思路立马就知道如何实现了,你其实可以直接copy gpt的回答然后运行看看,在此基础上修改修改就ok了。下面是我修改后的完整代码。

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

/// 表情下落动画
class EmojiAnimWidget extends StatefulWidget {
  const EmojiAnimWidget(
      {Key? key,
      required this.width,
      required this.height,
      this.emojiNum = 6,
      this.duration = const Duration(seconds: 5)})
      : super(key: key);

  final double width;
  final double height;
  final int emojiNum;
  final Duration duration;

  @override
  State<EmojiAnimWidget> createState() => EmojiAnimWidgetState();
}

class EmojiAnimWidgetState extends State<EmojiAnimWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  List<Widget>? _emojis;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: widget.duration,
    );
  }

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

  /// 开始表情动画
  void startEmojiAnim(String emoji) {
    _emojis = List.generate(widget.emojiNum, (index) {
      var delay = Random().nextInt(150).toDouble() + 50;
      var fontSize = Random().nextInt(9).toDouble() + 18.0;
      var animation = Tween<double>(
        begin: 0.0,
        end: 1.0,
      ).animate(CurvedAnimation(
        parent: _animationController,
        curve: Interval(delay / 500, (delay + 300) / 500, curve: Curves.linear),
      ));
      return AnimatedBuilder(
        animation: _animationController,
        builder: (context, child) {
          var opacity = 1 - animation.value;
          return Positioned(
            left: (widget.width - 32) / widget.emojiNum * index,
            top: -delay + animation.value * (widget.height + delay),
            child: Opacity(
              opacity: (opacity > 0.5) ? 1 : opacity,
              child: Container(
                height: 50,
                color: Colors.transparent,
                alignment: Alignment.center,
                child: Text(
                  emoji,
                  style: TextStyle(fontSize: fontSize, height: 1.2),
                  textAlign: TextAlign.center,
                ),
              ),
            ),
          );
        },
      );
    });
    setState(() {
      _animationController.stop();
      _animationController.repeat();
      _animationController.forward();
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_emojis == null) return Container();
    return Container(
      alignment: Alignment.center,
      padding: const EdgeInsets.only(left: 16, right: 16),
      width: widget.width,
      height: widget.height,
      child: Stack(
        clipBehavior: Clip.none,
        children: _emojis!,
      ),
    );
  }
}

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

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

相关文章

day03vue学习

day03 一、今日目标 1.生命周期 生命周期介绍生命周期的四个阶段生命周期钩子声明周期案例 2.综合案例-小黑记账清单 列表渲染添加/删除饼图渲染 3.工程化开发入门 工程化开发和脚手架项目运行流程组件化组件注册 4.综合案例-小兔仙首页 拆分模块-局部注册结构样式完善…

以太坊开发学习-solidity(一)环境搭建

文章目录 一 前言以太坊/Ethereum是什么?以太坊/Ethereum虚拟机(EVM)什么是智能合约?如何构建智能合约&#xff1f;什么是Solidity&#xff1f; solidity 编译环境在线编译Remix 本地编译一. node安装使用1. 安装 nodejs / npm2. 安装 Solidity 编译器 solc3. 自定义项目4. 使…

DAY 15补 对称二叉树

对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false思路 首先想清楚&#xff0c;判断对称二叉树要比较的是哪两个节…

Redis各场景应用集合

应用场景 1、缓存&#xff08;Cache&#xff09;,分布式缓存 有一些存储于数据库中的数据会被频繁访问&#xff0c;如果频繁的访问数据库&#xff0c;数据库负载会升高&#xff0c;同时由于数据库IO比较慢&#xff0c;应用程序的响应会比较差。此时&#xff0c;如果引入Redis来…

javaAPI操作Elasticsearch

mapping属性 mapping是对索引库中文档的约束, 常见的mapping属性包括: type: 字段数据类型,常见的简单类型有: 字符串: text(可分词的文本), keyword(精确值, 例如: 品牌,国家)数值: long, integer, short, byte, double, float布尔: boolean日期: date对象: object index: 是否…

EI Scopus检索 | 第二届大数据、物联网与云计算国际会议(ICBICC 2024) |

会议简介 Brief Introduction 2024年第二届大数据、物联网与云计算国际会议(ICBICC 2024) 会议时间&#xff1a;2024年12月29日-2025年1月1日 召开地点&#xff1a;中国西双版纳 大会官网&#xff1a;ICBICC 2024-2024 International Conference on Big data, IoT, and Cloud C…

RediSearch比Es搜索还快的搜索引擎

1、介绍 RediSearch是一个Redis模块&#xff0c;为Redis提供查询、二次索引和全文搜索。要使用RediSearch&#xff0c;首先要在Redis数据上声明索引。然后可以使用重新搜索查询语言来查询该数据。RedSearch使用压缩的反向索引进行快速索引&#xff0c;占用内存少。RedSearch索…

Redis数据结构对象之集合对象和有序集合对象

集合对象 集合对象的编码可以是intset或者hashtable. 概述 intset编码的集合对象使用整数集合作为底层实现&#xff0c;集合对象包含的所有元素都被保存在整数集合里面。 另一方面&#xff0c;hashtable编码的集合对象使用字典作为底层实现&#xff0c;字典的每个键都是一个…

REDHAWK——连接(续)

文章目录 前言一、突发 IO1、数据传输①、输入②、输出 2、突发信号相关信息 (SRI)3、多输出端口4、使用复数数据①、在 C 中转换复数数据 5、时间戳6、端口统计①、C 二、消息传递1、消息生产者①、创建一个消息生产者②、发送消息 2、消息消费者①、创建消息消费者②、注册接…

力扣106---从中序和后序序列构造二叉树

题目描述&#xff1a; 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20…

项目性能优化—使用JMeter压测SpringBoot项目

我们的压力测试架构图如下&#xff1a; 配置JMeter 在JMeter的bin目录&#xff0c;双击jmeter.bat 新建一个测试计划&#xff0c;并右键添加线程组&#xff1a; 进行配置 一共会发生4万次请求。 ctrl s保存&#xff1b; 添加http请求&#xff1a; 配置http请求&#xff1a;…

工控机的无限可能2--智慧城市

一、智能柜 随着网络技术的发展&#xff0c;网购因方便快捷、价格优惠、不受时空限制等优势已成为用户重要的消费方式。快递员因满柜&#xff0c;或柜型单一不能投递&#xff0c;只能将快件堆放在车上或公共过道处苦等&#xff0c;快递、资产管理也随之出现。 如下&#xff0…

使用Windows远程访问Kali Linux桌面

安装xrdp、xfce4 apt-get install -y xrdp xfce4修改 xrdp 配置文件启用 xfce 桌面 vim /etc/xrdp/startwm.sh修改后文件如下&#xff1a; #!/bin/sh # xrdp X session start script (c) 2015, 2017, 2021 mirabilos # published under The MirOS Licence# Rely on /etc/pam…

Unity InputField实现框自适应内容简便方法

要实现InputField框自适应输入内容&#xff0c;除了通过代码进行处理&#xff0c;还可以是使用以下简便的方法。 1、创建InputField组件&#xff1a;右键->UI->Input Field -TextMeshPro。 2、把Input Field Settings中的Line Type设置为Multi Line Newline模式&#x…

第五篇:数字视频广告格式概述 - IAB视频广告标准《数字视频和有线电视广告格式指南》

第五篇&#xff1a;第五篇&#xff1a;数字视频广告格式概述 - IAB视频广告标准《数字视频和有线电视广告格式指南 --- 我为什么要翻译介绍美国人工智能科技公司IAB系列技术标准&#xff08;2&#xff09; ​​​​​​​翻译计划 第一篇序言第二篇简介和目录第三篇概述- IA…

ubuntu下在vscode中配置matplotlibcpp

ubuntu下在vscode中配置matplotlibcpp 系统&#xff1a;ubuntu IDE&#xff1a;vscode 库&#xff1a;matplotlib-cpp matplotlibcpp.h文件可以此网址下载&#xff1a;https://github.com/lava/matplotlib-cpp 下载的压缩包中有该头文件&#xff0c;以及若干实例程序。 参考…

钡铼R40工业路由器在果园智能化生产管理系统中的重要角色

在现代果园智能化生产管理系统中&#xff0c;钡铼R40工业路由器扮演着至关重要的角色。它作为物联网技术的核心组件&#xff0c;将果园的智能化管理推向了一个全新的高度&#xff0c;实现了对果园环境、果树生长状况以及各类生产设备的实时监控与精准调控。 首先&#xff0c;钡…

Apache Dolphinscheduler - 无需重启 Master-Server 停止疯狂刷日志解决方案

记录的是一个 3.0 比较难搞的问题&#xff0c;相信不少使用过 3.0 的用户都遇到过 Master 服务中存在一些工作流或者任务流一直不停的死循环的问题&#xff0c;导致疯狂刷日志。不过本人到现在也没找到最关键的触发原因&#xff0c;只是看到一些连锁反应带来的结果…… 影响因素…

内网穿透的应用-如何使用Docker安装DockerUI可视化管理工具无公网IP远程访问

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

glib交叉编译

Glib交叉编译 逸一时&#xff0c;误一世。 —— 田所浩二「夏夜银梦」 交叉编译 GLib 涉及到在一个平台上生成能够在另一个平台上运行的目标文件。在这种情况下&#xff0c;我们将会在一台主机&#xff08;通常是开发机器&#xff09;上使用交叉编译工具链来构建 GLib 库&#…