用Flutter寫一個(gè)畢設(shè)app的經(jīng)驗(yàn)(flutter 設(shè)計(jì)稿)
Flutter我也不是很了解,但自從我接觸了這門跨端技術(shù)開發(fā)之后,我是深深地喜歡上了它的UI、它的交互和動(dòng)畫。很多人會(huì)吐槽它的無限嵌套,這是它有所不足的地方。喜歡一項(xiàng)技術(shù),就像喜歡一個(gè)人一樣,看到Ta的優(yōu)點(diǎn)的同時(shí)也能包容它的缺點(diǎn)。
我認(rèn)識(shí)一位才女,她在今年的畢業(yè)設(shè)計(jì)中,設(shè)計(jì)了一款app的UI。我當(dāng)時(shí)有個(gè)想法,把她的畢設(shè)開發(fā)出一個(gè)app。后面聯(lián)系的機(jī)會(huì)也比較少,各自忙各自的去啦!直到2021.08.23號(hào),我跟她拿了設(shè)計(jì)稿,并通過新技術(shù)開始了一個(gè)周的開發(fā)經(jīng)歷。
看到設(shè)計(jì)稿,我第一感覺是:在設(shè)計(jì)和配色方面讓人聯(lián)想到文化和古風(fēng)
應(yīng)用介紹:運(yùn)用扁平風(fēng)插畫的形式來表現(xiàn)苗族特有的民族特征,文化和樂器,以最新潮的方式推廣給每一位用戶,讓《苗韻》成為一款趣味性的科普APP。


應(yīng)用開發(fā)后的交互視頻
經(jīng)驗(yàn)分享:
1.實(shí)現(xiàn)引導(dǎo)頁(yè)

引導(dǎo)頁(yè)面
兩種選擇,可以選擇pageview自行搭建自己的引導(dǎo)頁(yè);
stack(children:[  Positioned.fill(  // 根據(jù)需求構(gòu)建自己的應(yīng)到也            child: PageView.builder()	)  ]  // 指示器內(nèi)容  buildDot())
另外一種選擇是可以選擇使用插件:這個(gè)插件構(gòu)建出來的引導(dǎo)頁(yè)也不錯(cuò)
intro_views_flutter
2.實(shí)現(xiàn)組件突出效果

像這種卡片上移的效果,對(duì)于flutter來說不太好實(shí)現(xiàn),而且實(shí)現(xiàn)之后還需要注意層級(jí)會(huì)遮擋。
兩種實(shí)現(xiàn)方式:
使用stack布局,有一個(gè)缺點(diǎn),如果內(nèi)容是長(zhǎng)列表,那會(huì)導(dǎo)致里面的內(nèi)容無法正常的滑動(dòng),比較適合小卡片布局。比如上圖中向外突出的樂器。
stack(children:[  position(  top:-30, //關(guān)鍵代碼在這里  ),  ])
使用 配合transform: Matrix4.translationValues(0.0, -100.0, 0.0),配合ClipPath
ClipPath(                //定義裁切路徑    clipper: BackgroundClipper(),     child: Container(      ),   )
BackgroundClipper 用于裁剪上移后,容器下面部分的內(nèi)容。
4.實(shí)現(xiàn)全局加載動(dòng)畫和單個(gè)加載動(dòng)畫
插件推薦:
# loading動(dòng)畫  flutter_spinkit: ^5.0.0
全局加載模態(tài)
import 'package:flutter/material.dart';import 'package:flutter_miaoyun/utills/color_utils.dart';import 'package:flutter_spinkit/flutter_spinkit.dart';class Loading extends StatelessWidget {  static void show(BuildContext context) {    showDialog(      barrierDismissible: true,      context: context,      builder: (ctx) => Theme(        data: Theme.of(ctx).copyWith(dialogBackgroundColor: Colors.transparent),        child: Loading(),      ),    );  }  static void dismiss(context) {    Navigator.pop(context);  }  @override  Widget build(BuildContext context) {    return Container(      color: Colors.transparent,      child: Center(        child: Container(          decoration: BoxDecoration(            color: Colors.transparent,            borderRadius: BorderRadius.circular(5),          ),          width: 60,          height: 60,          alignment: Alignment.center,          child: Column(            mainAxisSize: MainAxisSize.min,            children: <Widget>[              SpinKitCubeGrid(                color: gColor("#C8AD6B"),                size: 46.0,              )            ],          ),        ),      ),    );  }}// 調(diào)用 Loading.show()  隱藏 Loading.dismiss()
單個(gè)加載動(dòng)畫,可參考插件的demo 自行選用
5.實(shí)現(xiàn)點(diǎn)擊菜單移動(dòng)到對(duì)應(yīng)的內(nèi)容區(qū)域
插件:
# 跳轉(zhuǎn)到對(duì)應(yīng)的頁(yè)面  scroll_to_index: ^2.0.0
6.音樂播放的實(shí)現(xiàn)

在使用這個(gè)插件的時(shí)候,我在編譯的時(shí)候遇到了kotlin版本不匹配問題,我的解決方案是看插件的example使用的是哪個(gè)版本,然后再Android Stadio 中更新kotlin到對(duì)應(yīng)的版本。之后就完美解決。
# 音頻播放  audioplayers: ^0.19.1
音頻播放的邏輯。大概的分享一下。我是將audio的實(shí)例對(duì)象初始化后存到controller中,這樣就可以在多個(gè)頁(yè)面對(duì)音樂進(jìn)行控制。
7.制作閃屏頁(yè)
插件推薦
flutter_native_splash配置dev_dependencies:  flutter_test:    sdk: flutter  flutter_native_splash: ^1.2.0flutter_native_splash:  # color: "#42a5f5"  #image: assets/splash/icon.png  background_image: assets/guides/splash.png  # color_dark: "#042a49"  #image_dark: assets/splash/icon.png  background_image_dark: assets/guides/splash.png  android: true  ios: true  web: true  fullscreen: true使用:三步走flutter clean flutter pub getflutter pub run flutter_native_splash:create
8.本地存儲(chǔ)
插件推薦
shared_preferences
封裝
import 'dart:convert';import 'package:shared_preferences/shared_preferences.dart';class SPUtils {  // 靜態(tài)實(shí)例  static SharedPreferences _sharedPreferences;  // 應(yīng)用啟動(dòng)時(shí)需要調(diào)用  // 初始化  static Future<bool> init() async {    _sharedPreferences = await SharedPreferences.getInstance();    return true;  }  // 清除數(shù)據(jù)  static void remove(String key) async {    if (_sharedPreferences.containsKey(key)) {      _sharedPreferences.remove(key);    }  }  // 異步保存數(shù)據(jù)類型  static Future save(String key, dynamic value) async {    if (value is String) {      _sharedPreferences.setString(key, value);    } else if (value is bool) {      _sharedPreferences.setBool(key, value);    } else if (value is double) {      _sharedPreferences.setDouble(key, value);    } else if (value is int) {      _sharedPreferences.setInt(key, value);    } else if (value is List<String>) {      _sharedPreferences.setStringList(key, value);    }  }  // 異步讀取數(shù)據(jù)  static Future<String> getString(String key) async {    return _sharedPreferences.getString(key);  }  static Future<int> getInt(String key) async {    return _sharedPreferences.getInt(key);  }  static Future<bool> getBool(String key) async {    return _sharedPreferences.getBool(key);  }  static Future<double> getDouble(String key) async {    return _sharedPreferences.getDouble(key);  }  // 保存自定義對(duì)象  static Future saveObject(String key, dynamic value) async {    // 通過json 將Object對(duì)象編譯成String類型保存    _sharedPreferences.setString(key, json.encode(value));  }  // 獲取自定義對(duì)象  static dynamic getObject(String key) {    String _data = _sharedPreferences.getString(key);    return (_data == null || _data.isEmpty) ? null : json.decode(_data);  }  // 保存類表數(shù)據(jù)  static Future<bool> putObjectList(String key, List<Object> list) {    List<String> _dataList = list?.map((value) {      return json.encode(value);    })?.toList();    return _sharedPreferences.setStringList(key, _dataList);  }  // 獲取對(duì)象集合數(shù)據(jù)  // 返回的是List  <Map<String ,dynamic>>類型  static List<Map> getObjectList(String key) {    if (_sharedPreferences == null) return null;    List<String> dataList = _sharedPreferences.getStringList(key);    return dataList?.map((value) {      Map _dataMap = json.decode(value);      return _dataMap;    })?.toList();  }}
以上是在開發(fā)過程中覺得不錯(cuò),可以分享給flutter愛好者的相關(guān)知識(shí)。也是我在開發(fā)過程中遇到的一些技術(shù)難點(diǎn)。淡然有很多。要開發(fā)一個(gè)app,遇到的問題絕不是上面的這一點(diǎn)點(diǎn)。大家有不懂得多多交流。
