您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關(guān)如何利用Flutter制作一個摸魚桌面版App,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
Win10商店上架了一款名為《摸魚》的App,在下載打開之后,這個App會讓你的電腦進入一個假更新的畫面,讓別人以為你的電腦正在升級,這時候你就可以休息一下,優(yōu)雅地喝一杯咖啡。 頓時這個念頭劃過了我的腦海:好東西,但是我用的是 MacBook,不能用這個應(yīng)用。但是貌似我可以自己寫一個?
年輕最需要的就是行動力,想到就干,盡管我此刻正在理順 DevFest 的講稿,但絲毫不妨礙我用 10 分鐘寫一個 App。于是我打出了一套組合拳:
flutter config --enable-macos-desktop flutter create --platforms=macos touch_fish_on_macos
一個支持 macOS 的 Flutter 項目就創(chuàng)建好了。(此時大約過去了 1 分鐘)
我們首先需要一張高清無碼的 圖片,這里你可以在網(wǎng)上進行搜尋,有一點需要注意的是,使用 LOGO 要注意使用場景帶來的版權(quán)問題。找到圖片后,丟到 assets/apple-logo.png,并在 pubspec.yaml 中加上資源引用:
flutter: use-material-design: true + assets: + - assets/apple-logo.png
我們來觀察一下 macOS 的啟動畫面,有幾個要點:
LOGO 在屏幕中間,固定大小約為 100dp;
LOGO 與進度條間隔約 100 dp;
進度條高度約 5dp,寬度約 200dp,圓角幾乎完全覆蓋高度,值部分為白色,背景部分為填充色+淺灰色邊框。
(別問我為什么這些東西能觀察出來,問就是天天教 UI 改 UI。)
確認了大概的布局模式,接下來我們開始搭布局。(此時大約過去了 2 分鐘)
首先將 LOGO 居中、著色、設(shè)定寬度為 100,上下間隔 100:
return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Spacer(), Padding( padding: const EdgeInsets.symmetric(vertical: 100), child: Image.asset( 'assets/apple-logo.png', color: CupertinoColors.white, // 使用 Cupertino 系列的白色著色 width: 100, ), ), const Spacer(), ], ), );
然后在下方放一個相對靠上的進度條:
return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Spacer(), Padding( padding: const EdgeInsets.symmetric(vertical: 100), child: Image.asset( 'assets/apple-logo.png', color: CupertinoColors.white, // 使用 Cupertino 系列的白色 width: 100, ), ), Expanded( child: Container( width: 200, alignment: Alignment.topCenter, // 相對靠上中部對齊 child: DecoratedBox( border: Border.all(color: CupertinoColors.systemGrey), // 設(shè)置邊框 borderRadius: BorderRadius.circular(10), // 這里的值比高大就行 ), child: ClipRRect( borderRadius: BorderRadius.circular(10), // 需要進行圓角裁剪 child: LinearProgressIndicator( value: 0.3, // 當(dāng)前的進度值 backgroundColor: CupertinoColors.lightBackgroundGray.withOpacity(.3), color: CupertinoColors.white, minHeight: 5, // 設(shè)置進度條的高度 ), ), ), ), ], ), );
到這里你可以直接 run,一個靜態(tài)的界面已經(jīng)做好了。(此時大約過去了 4 分鐘)
打開 App,你已經(jīng)可以放在一旁掛機了,老板走到你的身邊,可能會跟你閑聊更新的內(nèi)容。但是,更新界面不會動,能稱之為更新界面? 當(dāng)老板一而再再而三地從你身邊經(jīng)過,發(fā)現(xiàn)還是這個進度的時候,也許就已經(jīng)把你的工資劃掉了,或者第二天你因為進辦公室在椅子上坐下而被辭退。
那么下一步我們就要思考如何讓它動起來。
來看看啟動動畫大概是怎么樣的:
開始是沒有進度條的;
進度條會逐級移動、速度不一定相等。
基于以上兩個條件,我設(shè)計了一種動畫處理方式:
構(gòu)造分段的時長 (Duration),可以自由組合由多個時長;
動畫通過時長的數(shù)量決定每個時長最終的進度;
每段時長控制起始值到結(jié)束值的間隔。
只有三個條件,簡單到起飛,開動?。ù藭r大約過去了 5 分鐘)
開局一個 AnimationController:
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin { /// 巧用 late 初始化,節(jié)省代碼量 late final AnimationController _controller = AnimationController(vsync: this); /// 啟動后等待的時長 Duration get _waitingDuration => const Duration(seconds: 5); /// 分段的動畫時長 List<Duration> get _periodDurations { return <Duration>[ const Duration(seconds: 5), const Duration(seconds: 10), const Duration(seconds: 4), ]; } /// 當(dāng)前進行到哪一個分段 final ValueNotifier<int> _currentPeriod = ValueNotifier<int>(1);
接下來實現(xiàn)動畫方法,采用了遞歸調(diào)用的方式,減少調(diào)用鏈的控制:
@override void initState() { super.initState(); // 等待對應(yīng)秒數(shù)后,開始進度條動畫 Future.delayed(_waitingDuration).then((_) => _callAnimation()); } Future<void> _callAnimation() async { // 取當(dāng)前分段 final Duration _currentDuration = _periodDurations[currentPeriod]; // 準備下一分段 currentPeriod++; // 如果到了最后一個分段,取空 final Duration? _nextDuration = currentPeriod < _periodDurations.length ? _periodDurations.last : null; // 計算當(dāng)前分段動畫的結(jié)束值 final double target = currentPeriod / _periodDurations.length; // 執(zhí)行動畫 await _controller.animateTo(target, duration: _currentDuration); // 如果下一分段為空,即執(zhí)行到了最后一個分段,重設(shè)當(dāng)前分段,動畫結(jié)束 if (_nextDuration == null) { currentPeriod = 0; return; } // 否則調(diào)用下一分段的動畫 await _callAnimation(); }
以上短短幾行代碼,就完美的實現(xiàn)了進度條的動畫操作。(此時大約過去了 8 分鐘)
最后一步,將動畫、分段二者與進度條綁定,在沒進入分段前不展示進度條,在動畫開始后展示對應(yīng)的進度:
ValueListenableBuilder<int>( valueListenable: _currentPeriod, builder: (_, int period, __) { // 分段為0時,不展示 if (period == 0) { return const SizedBox.shrink(); } return DecoratedBox( decoration: BoxDecoration( border: Border.all(color: CupertinoColors.systemGrey), borderRadius: BorderRadius.circular(10), ), child: ClipRRect( borderRadius: BorderRadius.circular(10), child: AnimatedBuilder( // 使用 AnimatedBuilder,在動畫進行時觸發(fā)更新 animation: _controller, builder: (_, __) => LinearProgressIndicator( value: _controller.value, // 將 controller 的值綁定給進度 backgroundColor: CupertinoColors.lightBackgroundGray.withOpacity(.3), color: CupertinoColors.white, minHeight: 5, ), ), ), ); }, )
大功告成,總共用時 10 分鐘,讓我們跑起來看看效果。(下圖 22.1 M)
打包發(fā)布
發(fā)布正式版的 macOS 應(yīng)用較為復(fù)雜,但我們可以打包給自己使用,只需要一行命令即可:flutter build macos。
成功后,產(chǎn)物將會輸出在 build/macos/Build/Products/Release/touch_fish_on_macos.app,雙擊即可使用
關(guān)于如何利用Flutter制作一個摸魚桌面版App就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。