Category: Tech

IT Technology, 3C, AI

  • 如何設定 Flutter App 程式的 Icon 圖示

    如何設定 Flutter App 程式的 Icon 圖示

    透過 flutter_launcher_icons 套件,可以方便的自定義 App 各平台的 icon。以下是使用方式:

    1. 針對各平台準備對應所需要的 icon.png 圖檔,解析度方面,除了 Windows 平台有上限 256*256外,其他的平台建議用 1024*1024 即可

    2. 參閱下圖,專案根目錄下建立資料夾路徑 “asset\icon\”,並把各平台對應的 icon 圖檔放在這裡
    (路徑和檔案名稱可以依需要命名)

    3. 在 pubspec.yaml 的 dependencies 加入相依套件 flutter_launcher_icons

    4. 建立對應的 config 設定,這可以直接新增在 pubspec.yaml 也可以為了管理方便於根目錄建立獨立檔案 flutter_launcher_icons.yaml

    5. 參考下面的範例編輯 config 設定內容即可

    flutter_launcher_icons:
    android: "launcher_icon"
    ios: true
    image_path: "assets/icon/icon.png"
    min_sdk_android: 21 # android min sdk min:16, default 21
    web:
    generate: true
    image_path: "assets/icon/icon_web.png"
    background_color: "#000000"
    theme_color: "#000000"
    windows:
    generate: true
    image_path: "assets/icon/icon_windows.png"
    icon_size: 48 # min:48, max:256, default: 48
    macos:
    generate: true
    image_path: "assets/icon/icon_macos.png"

    6. 演示範例

    1. Flutter StreamBuilder & Ping 套件 Example

      Flutter StreamBuilder & Ping 套件 Example

      相較於一次性的非同步執行緒 FutureBuilder,StreamBuilder 能持續運作並可搭配 StreamController 達到更新畫面資料時,不需要整個重新 build 而只更動使用 StreamBuilder 的區塊。

      以下StreamBuilder 範例為使用 dart_ping 套件,建立一個簡易的網址偵測 App。

      程式規劃和引用的套件(pubspec.yaml)

      main.dart

      import 'package:flutter/material.dart';

      import 'package:network_toolkit/screens/ping_screen.dart';

      void main() {
      runApp(
      const AppEntryPoint()
      );
      }

      class AppEntryPoint extends StatelessWidget {
      const AppEntryPoint({super.key});

      @override
      Widget build(BuildContext context) {
      return MaterialApp(
      title: 'Network Toolkit',
      theme: ThemeData(
      useMaterial3: true,
      primarySwatch: Colors.green,
      ),
      routes: {
      "/ping":(BuildContext context) => const PingScreen(),
      },
      initialRoute: "/ping",
      );
      }
      }

      screens/ping_screen.dart

      import 'package:flutter/material.dart';
      import 'dart:async';
      import 'package:dart_ping/dart_ping.dart';

      import 'package:network_toolkit/components/ping_result_component.dart';

      class PingScreen extends StatefulWidget {
      const PingScreen({super.key});

      @override
      State createState() {
      return _PingScreen();
      }
      }

      class _PingScreen extends State<PingScreen> {
      bool _userInputTextFieldEnabled = true;
      String _urlOrIP = "";
      late StreamController _controller;
      final ScrollController _scrollController = ScrollController();
      List<String> _pingResultList = [];

      @override
      void initState() {
      super.initState();
      _controller = StreamController.broadcast(); // Initial
      }

      @override
      Widget build(BuildContext context) {
      var textEditController = TextEditingController( text: _urlOrIP );

      Widget userInputTextField = SizedBox(
      width: 500,
      child: TextField(
      decoration: const InputDecoration(
      border: OutlineInputBorder(),
      hintText: 'Input URL or IP',
      ),
      controller: textEditController,
      enabled: _userInputTextFieldEnabled,
      onSubmitted: (inputvalue){
      _urlOrIP = inputvalue;
      _pingResultList = [];

      setState(() {
      _userInputTextFieldEnabled = false;
      });

      // Begin ping process and listen for output
      final ping = Ping(_urlOrIP, count: 5);
      ping.stream.listen(
      (event) {
      _pingResultList.add("${ping.command} : ${event.toString()}");

      _controller.sink.add(_pingResultList);
      },
      onDone: () {
      setState(() {
      _userInputTextFieldEnabled = true;
      });
      },
      );
      },
      ),
      );

      return Scaffold(
      appBar: AppBar(
      title: const Text("Ping"),
      ),
      body: Column(
      children: [
      userInputTextField,
      StreamBuilder(
      initialData: _pingResultList,
      stream: _controller.stream,
      builder: (context, n) {
      List<String> results = n.data as List<String>;
      return Expanded(
      child: ListView(
      controller: _scrollController,
      children: [
      ...results.map((pingResult) => PingResultComponent(pingResult)).toList()
      ]
      )
      );
      }
      ),
      ]
      ),
      );
      }

      @override
      void dispose() {
      super.dispose();
      _controller.close();
      }
      }

      components/ping_result_component.dart

      import 'package:flutter/material.dart';

      // ignore: must_be_immutable
      class PingResultComponent extends StatefulWidget {
      String pingResult;

      PingResultComponent(this.pingResult, {super.key});

      @override
      State createState() {
      return _PingResultComponent();
      }
      }

      class _PingResultComponent extends State<PingResultComponent> {
      @override
      Widget build(BuildContext context) {
      Widget pingResultValueText =
      Flexible(
      child: Text(
      widget.pingResult,
      )
      );

      return Card(
      child: ListTile(
      title: Row(
      children: [
      pingResultValueText,
      ]
      ),
      ),
      );
      }
      }
    2. 另類的 三仙歸洞 魔術

      由最近很紅的 魔術師 大仙 在機車行用機車零件變的三仙歸洞魔術👍

      https://www.facebook.com/share/v/zGy4NduNjDQWWRDj/?mibextid=WC7FNe

    3. 台灣2024立法院召委名單 Taiwan 2024 Legislative Yuan Convener Committee List

      台灣2024立法院召委名單 Taiwan 2024 Legislative Yuan Convener Committee List

      • 內政委員會召委︰吳琪銘(民進黨)、高金素梅(無黨籍)
      • 外交國防委員會召委:王定宇(民進黨)、馬文君(國民黨)
      • 經濟委員會召委:邱議瑩(民進黨)、楊瓊瓔(國民黨)
      • 財政委員會召委:郭國文(民進黨)、羅明才(國民黨)
      • 教育文化委員會召委:林宜瑾(民進黨)、柯志恩(國民黨)
      • 交通委員會召委:李昆澤(民進黨)、陳雪生(國民黨)
      • 司法法制委員會召委:鍾佳濱(民進黨)、吳宗憲(國民黨)
      • 社福衛環委員會召委:黃秀芳(民進黨)、王育敏(國民黨)

      召委,全稱為召集委員,召委的權力主要在於可以決定各委員會的議程。立法院的待審議案數量龐大,哪些議案能夠優先審查,掌握排審議程主導權的召委便成為重要角色。

      Democratic Progressive Party (DPP) and Kuomintang (KMT) dominated the votes to elect the heads of the eight standing committees. They’re each gained an equal number of committee chairs.

      • The two convener seats on the Transportation Committee were won by the KMT’s Chen Hsueh-shen and the DPP’s Lee Kun-tse
      • The Social Welfare and Environmental Hygiene Committee conveners elected were the KMT’s Alicia Wang and the DPP’s Huang Hsiou-fang
      • The Judiciary and Organic Laws and Statutes Committee conveners are the KMT’s Wu Tsung-hsien and the DPP’s Chung Chia-pin
      • The Foreign and National Defense Committee elected the KMT’s Ma Wen-chun and the DPP’s Wang Ting-yu
      • On the Internal Administration Committee, independent Legislator May Chin and the DPP’s Wu Chi-ming were elected
      • The Finance Committee’s cochairs are KMT Legislator Lo Ming-tsai and DPP Legislator Kuo Kuo-wen
      • The Economics Committee is headed by the KMT’s Yang Chiung-ying and the DPP’s Chiu Yi-ying
    4. Flutter Foreground Task 常駐程式套件

      Flutter Foreground Task 常駐程式套件

      在 Flutter 官方經營的 https://pub.dev 上有相當多好用的程式套件,其中,Flutter Foreground Task 是許多人推薦能在 Android 和 iOS 實現[常駐程式]機制的套件。

      pub.dev 上幾乎所有套件都會提供 Example 範例程式,以展示其使用方式及效果。Flutter Foreground Task 的範例程式的展示效果如下圖所示。

      左邊的為程式主畫面,按下[start]按鈕後便會執行常駐程式,並手機最上方的區域顯示程式的 icon (時間右邊數來第二個);右邊的為手機滑下上方區域的畫面,flutter_oreground_task_example 為程式名稱、MyTaskHandler 為固定顯示的內容、eventCount 為動態更新的內容、 按下Send 和 Test 按鈕可觸發程式做動作(似乎是 Android限定)、整個區塊按下去可跳回程式。

      由於該範例程式極具參考價值,這裡做一張對應的程式流程圖以方便理解參考。

      另外,關於前景服務的概念,也可以參考 Domen Lanisnik 的文章(Android):https://medium.com/@domen.lanisnik/guide-to-foreground-services-on-android-9d0127dc8f9a

    5. 關於磁碟陣列和資料備份

      關於磁碟陣列和資料備份

      在個人或家用的電腦或筆電使用情境上,一般人會將重要資料放系統磁碟區以外的地方如D槽、其他磁區甚至獨立的硬碟等,更有甚者會將資料再上傳一份到雲端以避免資料遺失。

      以下就資料遺失風險的高至低來說明:

      1. 與系統在同一顆硬碟上:系統碟是使用頻度最高的地方,因此耗損和失效風險也是最高的。一般的筆電或是品牌主機基本都是這樣的配置。
      2. 獨立的硬碟:相較於系統碟,只有在需要資料時才會用到,因此耗損和失效風險也相對較低。
      3. 主機板內建的軟體磁碟陣列RAID1:幾乎絕大部分主機板所用的晶片組都有內建磁碟陣列的功能,需搭配Windows作業系統的驅動程式來運作,且磁碟之內的移轉上需使用相同廠牌的晶片組,如Intel所建立的磁碟陣列只能移轉到Intel主機板上,AMD晶片組所建立的磁碟陣列亦同。
      4. Windows作業系統的軟體磁碟陣列(動態磁碟映射模式):通常資料存取速度較主機板內建的軟體磁碟陣列來得差一寫,但好處是只要是Windows都可以使用和移轉。家用主機非常推薦此做法。
      5. 使用具獨立晶片和控制系統的磁碟陣列卡建立的硬體磁碟陣列RAID5: 企業級的做法在性能和風險上取得平衡,建置成本高且移轉時一樣會受限於使用晶片的廠家。
      6. 資料備份在外接式硬碟:優點是資料單位成本比雲端便宜,但有忘記做和備份資料不即時的問題。
      7. 透過自動化的方式備份到雲端:優點是備份的資料,大部分的雲端空間都有提供包含手機、Windows和Mac等多平台的備份方案。且相較於本地備份的方案,異地備份具有更低的風險。推薦使用。
    6. Flutter 常用指令

      Flutter 常用指令

      以下為命令提示字元或VS Code的終端機介面下,常用的指令:

      • flutter {command} -h:查閱各command指令的用法和參數說明
      • flutter –version:檢視 flutter 版本
      • flutter doctor:檢查 flutter 開發環境相關軟體的安裝狀態
      • flutter upgrade:更新 flutter SDK 到最新版本 (也可以直接到 Flutter 官網下載)
      • flutter pub get:取得 package 並下載到 .pub-cache 隱藏目錄
      • flutter pub upgrade:更新 package 到最新版本
      • flutter clean:清除 .pub-cache 隱藏目錄。
      • flutter devices:顯示可用裝置資訊
      • flutter emulators:顯示可用模擬器資訊
      • flutter config –android-studio-dir=”{path}”:手動指定 Android Studio 的安裝路徑
      • flutter config –android-sdk=”{path}”:手動指定 Android SDK 的安裝路徑
      • flutter build apk:建立 release 版本 apk
      • flutter build apk –debug:建立 debug版本 apk

      如果Flutter專案目錄有異動,在編譯程式時可能會出現cache路徑錯誤之類的異常。這時候可以先清除 cache:flutter clean
      然後再重新取得 package 來排除問題:flutter pub get

    7. Dart 程式語言命名原則

      Dart 程式語言命名原則

      • 資料夾和檔案名稱
        使用小寫英數字加底線,例如:models\customer_model.dart
      • Class 類別名稱
        使用 Upper Camel Case 大駝峰式命名,例如:class CustomerModel
      • 分辨 public 和 private
        類別的屬性和方法名稱若有底線,則代表 private,反之則為 public,例如:class _CustomerModel
        (Dart 沒有 public 和 private 關鍵字)
      • 變數和函數名稱
        使用 Lower Camel Case 小駝峰式命名,例如:int customerId = -1;
      • 建立新物件時可省略 new 這關鍵字
        例如:return new CustomerModel(); 可以寫成 return CustomerModel();
    8. Flutter Structure Chart 架構圖

      下圖為 Flutter SDK 的架構。