flutter之敲木鱼练习跟练--续2

接着上篇文章,动画部分的完成--我们来组装一下已经写好的几个模块

首先,需要建一个新页面 muyu_home.dart 有状态组件

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

// 主页面
class Muyu_Home extends StatefulWidget {
  const Muyu_Home({super.key});

  @override
  State<Muyu_Home> createState() => _Muyu_HomeState();
}

class _Muyu_HomeState extends State<Muyu_Home> {
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

作为主页面,我们使用Scaffold widget包裹内容,关于Scaffold Widget 实际化起来我们可以看做一个基本骨架 有头、身体、胳膊、脚,这些构成页面的基本。

那么来看一下scaffold 的基础语法,flutter 的语法是样式和函数是组合在一起的,不同于前端中vue的样式和函数拆分开来,一开始会感觉这种糅合在一起的有点不太舒服,但写的多了就会有所适应, 它们各有千秋!

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

// 主页面
class Muyu_Home extends StatefulWidget {
  const Muyu_Home({super.key});

  @override
  State<Muyu_Home> createState() => _Muyu_HomeState();
}

class _Muyu_HomeState extends State<Muyu_Home> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 导航栏--头部
      appBar: AppBar(
          // 頁面標題
          title: Text('One More'),
          // 背景颜色
          backgroundColor: Colors.white,
          // 文字样式
          titleTextStyle: const TextStyle(
              color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold),
          //图标主题
          iconTheme: const IconThemeData(color: Colors.black),
          //导航栏右侧菜单
          actions: [
            IconButton(onPressed: () {}, icon: const Icon(Icons.history))
          ]),

      //底部导航栏
      bottomNavigationBar: BottomNavigationBar(
        // 底部导航
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(
              icon: Icon(Icons.business), label: 'Business'),
          BottomNavigationBarItem(icon: Icon(Icons.school), label: 'School'),
        ],
      ),

      // 页面内容--此处为一个center组件,内容会居中
      body: const Center(
        child: Text('Muyu'),
      ),
    );
  }
}

那么回到小案例,组装写好的各个模块,代码如下

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

// 主页面
class Muyu_Home extends StatefulWidget {
  const Muyu_Home({super.key});

  @override
  State<Muyu_Home> createState() => _Muyu_HomeState();
}

class _Muyu_HomeState extends State<Muyu_Home> {
  @override
  Widget build(BuildContext context) {
    var activeImage;
    var _cruRecord;
    var _counter;
    return Scaffold(
      appBar: AppBar(
          elevation: 0,
          backgroundColor: Colors.white,
          titleTextStyle: const TextStyle(
              color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold),
          iconTheme: const IconThemeData(color: Colors.black),
          title: const Text('电子木鱼'),
          actions: [
            IconButton(onPressed: () {}, icon: const Icon(Icons.history))
          ]),
      body: Column(
        children: [
          Expanded(
              //功德数+右侧切木鱼样式和音乐按钮组件,传递三个参数给组件  1.功德数总值 切换音乐 切换图片
              child: CountPanel(
                  count: _counter,
                  onTapSwitchAudio: () {},
                  onTapSwitchImage: () {})),
          //下半部分组件--木鱼图片
          Expanded(
              child: Stack(
            alignment: Alignment.topCenter,
            children: [
              MuyuAssetsImage(image: activeImage, onTap: () {}),
              if (_cruRecord != null)
                AnimateText(
                  record: _cruRecord!,
                )
            ],
          ))
        ],
      ),
    );
  }
}

此时运行一下程序,会看到主页面只有功德数和右侧按钮,木鱼图片可以先放一个本地图片。 组装完成主界面如下:

再次回顾整体功能点:

  • 1.敲击木鱼,加功德数,并伴有文字动画由深变浅、由大到小的动画文字效果;
  • 2.界面功德数实时变化,随着敲击的次数增加;
  • 3.点击右侧音乐按钮,底部弹出音效列表面板,可切换敲木鱼音效;
  • 4.点击右侧图片按钮,底部弹出木鱼面板,可切换,不同木鱼所代表功德数值不同;
  • 5.点击导航栏右侧历史icon,弹出抽屉层,记录功德数历史列表,列表信息有id、敲击时间、增加的功德数,当前木鱼的图片

样式好了,那么该写方法了,让我们敲起木鱼来! 在木鱼图片组件中封装了一个onKnock方法,敲击实现很简单,定义两个变量,一个为实时增加的值,一个为总数,敲一次总数进行累加,传值给功德数组件,实时增加数传值给动画组件;

点击时将当前木鱼信息存起来,针对需求点,需要存取id,木鱼图片样式、当前音效、当前时间、功德增加数;历史列表的信息会频繁使用,后续木鱼图片、木鱼音效也存进此类中。

js 复制代码
// 木鱼记录信息 封装成一个类 一个数据模型
class MeritRecord {
  final String id;
  final int timestamp;
  final int value;
  final String image;
  final String audio;

//  这个类指向它的实例
  MeritRecord(this.id, this.audio, this.image, this.timestamp, this.value);

  Map<String, dynamic> toJson() => {
        "id": id, //记录的唯一标识
        "timestamp": timestamp, //记录的时间戳
        "image": image, //图片资源
        "audio": audio, //音效名称
        "value": value, //功德数
      };
}

// 敲木鱼音效和样式的选择
class AudioOption {
  final String name;
  final String src;

  const AudioOption(this.name, this.src);
}

// 维护不同样式敲木鱼的数据
class ImageOption {
  final String name;
  final String src;

  ///资源路径
  final int min; //每次点击功德最小值
  final int max; //每次点击积功德最大值

  const ImageOption(this.max, this.min, this.name, this.src);
}

关于这里的id,我们使用flutter 的一个uuid 插件,它可以生成不同的id, 链接:pub.dev 使用方法:

js 复制代码
//即可生成一個id
  String id = uuid.v4();

当前时间获取:

js 复制代码
 DateTime.now().millisecondsSinceEpoch,

木鱼图片面板组合木鱼音效面板也需要进行封装成单独模块

1.木鱼图片面板模块

界面分析:上下布局,内容左右布局-column+row+expand

这里主要分析一下实现切换图片的一个思路:

在主界面定义图片数据源--初始化时默认使用第一张图片,图片的index值作为切换图片的关键参数,

点击右侧图片按钮,从底部弹出面板->这里用到一个弹框类似以vue里面的showModal------flutter中的 showCupertinoModalPopup,

基本语法如下:

js 复制代码
 showCupertinoModalPopup(
      context: context,
      builder: (BuildContext context) {
      //此处ImageOptionPanel 是封装好的木鱼选择面板组件
        return ImageOptionPanel(
          imageOptions: imageOptions,
          activeIndex: _activeIndex,
          onSelect: _onSelectImage,
        );
      },
    );

在这个弹框里面定义一个select切换方法,当前图片的index、及图片列表数据。此时index值已传入子组件中,将index赋值给当前组件中激活的index,得到一个当前被选中的木鱼--在点击关闭或者切换时,做一个监听回调,将当前的index值回调给父组件-由父组件来判断回调之后的index是否与原来一致,不一致则用新的index传入木鱼图片组件之中,一致则返回。

切换木鱼音效的思路也是大致的,木鱼音效这里使用一个插件:flame_audio 本案例中的语法

js 复制代码
  void _tempPlay(String src) async {
    AudioPool pool = await FlameAudio.createPool(src, maxPlayers: 1);
    pool.start();
  }

历史列表实现思路: 点击时将存储列表传递进去,这里要对列表进行一个倒序处理,将数字转化为List才可以哦!

由于代码有点多,就不再一一分析了,需要源码可以滴滴我,自行分析。嗯对于初学者来说还是一个很有意义的项目,里面设计到了组件的封装思想、界面布局的widget、定义数据类等等。

相关推荐
jhonjson17 小时前
Flutter开发之flutter_local_notifications
flutter·macos·cocoa
iFlyCai18 小时前
23种设计模式的Flutter实现第一篇创建型模式(一)
flutter·设计模式·dart
恋猫de小郭19 小时前
Flutter 小技巧之 OverlayPortal 实现自限性和可共享的页面图层
flutter
A_cot1 天前
Vue.js:构建现代 Web 应用的强大框架
前端·javascript·vue.js·flutter·html·web·js
B.-1 天前
在 Flutter 应用中调用后端接口的方法
android·flutter·http·ios·https
️ 邪神1 天前
【Android、IOS、Flutter、鸿蒙、ReactNative 】约束布局
android·flutter·ios·鸿蒙·reactnative
pinkrecall20121 天前
flutter调试
flutter
jhonjson1 天前
在Flutter中,禁止侧滑的方法
前端·javascript·flutter
️ 邪神2 天前
【Android、IOS、Flutter、鸿蒙、ReactNative 】文本点击事件
flutter·ios·鸿蒙·reactnative·anroid
️ 邪神2 天前
【Android、IOS、Flutter、鸿蒙、ReactNative 】文本Text显示
flutter·ios·鸿蒙·reactnative·anroid