flutter之敲木鱼练习--基础案例

前言:

实践是检验真理的唯一标准,前期语法学的如何,一个小小demo试试手。 要想学的好,练习不可少;

一、本期敲木鱼demo主要功能介绍:

复制代码
主界面木鱼可以敲击,加功德
功德历史列表
木鱼样式功能切换
木鱼音效功能切换

实现效果图如下:

功德数增加动画效果:

功德历史列表:

木鱼样式选择面板:

音效选择列表:

以上为实现效果图

二、敲木鱼案例功能拆分

2.1 主页面的部分划分

页面布局角度: 主页面:上下布局--各封装一个模块,上布局 :Stack+Center+Positioned 下布局 :Center, 整体布局为:Column+Expanded

布局样式我们进行上下划分,功德数、音效按钮、图片按钮为上半部分,木鱼图片为下半部分

上半部分为图片、音效功德数这些模块设计到后续功能,我们做一个单独的模块封装。

新建一个页面,countpanel.dart【上半部分模块】,使用st快捷输入,这里使用的是无状态Widget【StatelessWidget】

js 复制代码
import 'package:flutter/material.dart';

class CountPanel extends StatelessWidget {
  final int count;//定义功德总数
  final VoidCallback onTapSwitchAudio;//定义切换音效方法
  final VoidCallback onTapSwitchImage;//定义切换木鱼图片方法


  const CountPanel({
    super.key,
    required this.count,
    required this.onTapSwitchAudio,
    required this.onTapSwitchImage,
  });

  @override
  Widget build(BuildContext context) {
  //自定义按钮内容样式
  final ButtonStyle style = ElevatedButton.styleFrom(
      minimumSize: const Size(50, 50),
      padding: EdgeInsets.zero,
      backgroundColor: Colors.green,
      elevation: 0,
    );
  //stack 组件 层叠布局和 Web 中的绝对定位、Android 中的 Frame 布局是相似的,子组件可以根据距父容器四个角的位置来确定自身的位置。
    return Stack(
      children: [
       //center 组件顾名思义,居中内容的组件
        Center(
          child: Text(
            '功德数: $count',
            style: const TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
        //右侧音效、图片切换按钮--使用定位来实现 Positioned
         Positioned(
            right: 10,
            top: 10,
            //# Wrap 流失布局,当一行超出屏幕流失布局会自动拆分,进行换行
            child: Wrap(
              spacing: 8,
              direction: Axis.vertical,
              children: [
              //`ElevatedButton` 即"漂浮"按钮,自带点击事件:onPressed
                ElevatedButton(
                  style: style,
                  onPressed: onTapSwitchAudio,
                  child: const Icon(
                    Icons.music_note_outlined,
                    color: Colors.white,
                  ),
                ),
                ElevatedButton(
                  style: style,
                  onPressed: onTapSwitchImage,
                  child: const Icon(
                    Icons.image,
                    color: Colors.white,
                  ),
                )
              ],
            )),
      ],
    );
  }
}

下半部分图片看似只有一个,但是其实背后是包含着木鱼图片和文字动画效果,这里也封装为一个单独的模块 切换图片时,便于接收不同的imgUrl.

图片组件模块如下:

// 存放木鱼在首页点击图片

js 复制代码
class MuyuAssetsImage extends StatelessWidget {
  final String image;
  final VoidCallback onTap; //接收一个回调方法
  const MuyuAssetsImage({super.key, required this.image, required this.onTap});

  @override
  Widget build(BuildContext context) {
    return Center(
        // gestureDetector  组件监听手势回调
        child: GestureDetector(
      onTap: onTap,
      child: Image.asset(
        image,//接收父组件传递的url值
        height: 200,
      ),
    ));
  }
}

那么图片模块有了,我们来看一下文字动画效果如何实现

动画效果:是点击向上飘,放大又缩小 、文字由深色逐渐变淡

ScaleTransition 弹性动画,scale:放大数 SlideTransition ,根据位置变化的Widget
FadeTransition 淡出的动画效果, AnimationController 动画控制器

因此动画文字模块代码如下:

js 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_app_seven/muyu/fishenity.dart';

// 敲木鱼动画文字组件 --之前有bug 点击切换图片样式时会触发动画
class AnimateText extends StatefulWidget {
  final MeritRecord record;
  const AnimateText({super.key, required this.record});

  @override
  State<AnimateText> createState() => _AnimateTextState();
}

// 加入这个用于加入动画控制器
class _AnimateTextState extends State<AnimateText>
    with SingleTickerProviderStateMixin {
  late AnimationController controller;
  late Animation<double> opacity;
  late Animation<Offset> position;
  late Animation<double> scale;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 500));
    // 动画器属性配置,从开始
    opacity = Tween(begin: 1.0, end: 0.0).animate(controller);//透明度
    scale = Tween(begin: 1.0, end: 0.9).animate(controller);//放大到缩小值
    //位置变化
    position = Tween<Offset>(
      begin: const Offset(0, 5),
      end: Offset.zero,
    ).animate(controller);
    controller.forward();
  }

  @override
  // 在父widget中调用setState
  void didUpdateWidget(covariant AnimateText oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 避免功德未变化的情况下,启动动画场景
    if (oldWidget.record.id != widget.record.id) {
      controller.forward(from: 0);
    }
  }
  
  
  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    //过渡消失组件 还缺少缩放动画
    // 旋转
    return ScaleTransition(
      scale: scale,
      // 移动
      child: SlideTransition(
          position: position,
          child: FadeTransition(
            opacity: opacity,
            child: Text('功德数+${widget.record.value}'),
          )),
    );
  }
}

下期在续...

相关推荐
西西学代码1 小时前
flutter_blue_plus
flutter
tangweiguo030519872 小时前
Flutter MVVM 完整实战:网络请求、状态管理、分页加载一网打尽
flutter
孤影过客3 小时前
Flutter优雅构建:从零打造开发级工作流
arm开发·数据库·flutter
p1gd0g4 小时前
flutter web 如何确保用户收到更新
flutter
GoCoding5 小时前
Flutter ngspice 插件
flutter
恋猫de小郭5 小时前
Android Studio Panda 2 ,支持 AI 用 Vibe Coding 创建项目
android·前端·flutter
Gorit7 小时前
如何使用 Flutter 开发 HarmonyOS 应用
flutter·华为·harmonyos
孤影过客7 小时前
Flutter高性能任务管理APP开发实战代码解析
jvm·flutter·oracle
键盘鼓手苏苏19 小时前
Flutter 三方库 p2plib 的鸿蒙化适配指南 - 实现高性能的端到端(P2P)加密通讯、支持分布式节点发现与去中心化数据流传输实战
flutter·harmonyos·鸿蒙·openharmony
加农炮手Jinx19 小时前
Flutter for OpenHarmony:postgrest 直接访问 PostgreSQL 数据库的 RESTful 客户端(Supabase 核心驱动) 深度解析与鸿蒙适配指南
数据库·flutter·华为·postgresql·restful·harmonyos·鸿蒙