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、定义数据类等等。

相关推荐
明似水23 分钟前
解决 Flutter 在 iOS 真机上构建失败的问题
flutter·ios
仙魁XAN20 小时前
Flutter 学习之旅 之 Flutter 和 Android 原生 实现数据交互的MethodChanel和EventChannel方式的简单整理
android·flutter·flutter module·aar·混合开发·flutter交互
leluckys2 天前
flutter 专题 六十一 支持上拉加载更多的自定义横向滑动表格
flutter
UzumakiHan2 天前
flutter开发音乐APP(简单的音乐播放demo)
flutter
leluckys2 天前
flutter 专题 六十四 在原生项目中集成Flutter
flutter
leluckys2 天前
flutter 专题 一百零四 Flutter环境搭建
flutter
唯鹿2 天前
AI生成Flutter UI代码实践(一)
人工智能·flutter·ui
仙魁XAN2 天前
Flutter 学习之旅 之 flutter 有时候部分手机【TextField】无法唤起【输入法软键盘】的一些简单整理
flutter·unity·华为手机·textfield·键盘唤不起
leluckys2 天前
flutter 专题 五十八 关于Flutter提示Your Xcode project requires migration的错误
flutter
只可远观3 天前
Flutter Dart中的函数参数 默函数的定义 可选参数 箭头函数 匿名函认参数 命名参类数 闭包等
windows·flutter