2022年1月8日 星期六

Flutter 骨架 (Skeleton) 專案範例

Flutter  提供骨架(Skeleton)專案範例,主要提供下列功能說明:

  1.  專案中新增/設定本地化( Localizations)檔案
  2.  程式中動態切換主題(Theme)的方法
  3.  導航與路由 (Navigate & Routing)的方法


1.        建立新的Flutter專案

1-1.        開啟命令介面

 

1-2.        選擇建立骨架 (Skeleton) 專案類型

1-3.        輸入專案名稱 





2.        Flutter 預設骨架專案的檔案架構

在選擇建立新的骨架專案後會自動產生相關的檔案及目錄,主要的檔案如下:

2-1.  build目錄 

    儲存各平台建置完成後產生的執行檔案

     (1)  app/outputs/apk -  

       選擇建置andoird平台後所產生的apk檔
















(2)  windows/runner/ -

       選擇建置 windows平台後所產生的exe及dll檔案。















(3)  web

       選擇建置web平台後所產生相關的html及js檔案。





(4)  linux/x64/release/bundle

                     選擇建置linux平台後所產生的執行檔及.so檔案。















2-2.  lib目錄

        主要存放開發程式碼的目錄,main.dart 中的 main 函式為啟動程式的入口函式,而此範例程式使用非同步的方法載入主題(Thmem)的資料,因此在main 函式後加入 async 關鍵字。

若要直接引用存放於此目錄下的檔案的格式如下:

  •      引用同層目錄的檔案:import "檔案名稱";
  •   引用子目錄的檔案: import "子目錄名稱/檔案名稱";
  •   引用上層目錄的檔案: import "../目錄名稱/檔案名稱";

import 'package:flutter/material.dart';
import 'src/app.dart';
import 'src/settings/settings_controller.dart';
import 'src/settings/settings_service.dart';

void main() async {
  final settingsController = SettingsController(SettingsService());

  await settingsController.loadSettings();

  runApp(MyApp(settingsController: settingsController));
}

2-3.  test目錄

         主要存放使用Flutter中WidgetTester的測試程序對指定Widget物件進行互動驗證程式與 test 測試函數進行自訂函數的驗證而 group 函數為可組合多次連續測試程序,此範例專案提供兩個測試範例:

1.  unit_test.dart  

        測試自訂的1+1是否等於二的函數正確性,若正確則會回傳test函數中定義的字串,若不是則會在執行時產生例外。

import 'package:flutter_test/flutter_test.dart';

void main() {
  group('Plus Operator', () {
    test('should add two numbers together', () {
      expect(1 + 1, 2);
    });
  });
}









2.  widget_test.dart
測試自訂MaterialApp在建立時是否會包含多於一個Text物件,若正確則會回傳execpt函數中定義的字串,若不是則會在執行時產生例外。
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  group('MyWidget', (){
     estWidgets('should display a string of text', (WidgetTester tester) async {  
    // Define a Widget
    const myWidget = MaterialApp(
      home: Scaffold(
        body: Text('Hello'),
      ),
    );
    // Build myWidget and trigger a frame.
    await tester.pumpWidget(myWidget);

    // Verify myWidget shows some text
    expect(find.byType(Text), findsOneWidget);
   });
 });
} 




2-4.  pubspec.yaml檔案

         flutter 專案中的檔案配置檔,除了設定基本專案資訊並可設定專案中使用到的相依類別庫或外部資源。

name: flutter_skeleton
description: A new Flutter project.

# Prevent accidental publishing to pub.dev.
publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: ">=2.15.1 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
    version: ^0.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^1.0.0

flutter:
  uses-material-design: true

  # Enable generation of localized Strings from arb files.
  generate: true

  assets:
  # Add assets from the images directory to the application.
  - assets/images/

2-5.  .packages檔案

flutter 專案中設定相依類別庫檔案路徑的組態檔,建立專案的預設檔案路徑為 flutter_skeleton:lib/ 而此檔案是在執行"flutter pub get"指令後根據 pubspec.yaml中的內容產生出來,設定引用類別庫格式為【路徑別名:實際路徑】。

async:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.8.2/lib/
boolean_selector:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/boolean_selector-2.1.0/lib/
characters:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/characters-1.2.0/lib/
charcode:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/charcode-1.3.1/lib/
clock:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/clock-1.1.0/lib/
collection:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/collection-1.15.0/lib/
fake_async:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/fake_async-1.2.0/lib/
flutter:file:///D:/flutter_windows_2.8.1-stable/flutter/packages/flutter/lib/
flutter_lints:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_lints-1.0.4/lib/
flutter_localizations:file:///D:/flutter_windows_2.8.1-stable/flutter/packages/flutter_localizations/lib/
flutter_test:file:///D:/flutter_windows_2.8.1-stable/flutter/packages/flutter_test/lib/
intl:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/intl-0.17.0/lib/
lints:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/lints-1.0.1/lib/
matcher:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.11/lib/
meta:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.7.0/lib/
path:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/path-1.8.0/lib/
sky_engine:file:///D:/flutter_windows_2.8.1-stable/flutter/bin/cache/pkg/sky_engine/lib/
source_span:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/source_span-1.8.1/lib/
stack_trace:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.10.0/lib/
stream_channel:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/stream_channel-2.1.0/lib/
string_scanner:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/string_scanner-1.1.0/lib/
term_glyph:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/term_glyph-1.2.0/lib/
test_api:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/test_api-0.4.3/lib/
typed_data:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/typed_data-1.3.0/lib/
vector_math:file:///D:/flutter_windows_2.8.1-stable/flutter/.pub-cache/hosted/pub.dartlang.org/vector_math-2.1.1/lib/
flutter_skeleton:lib/

2-6.  I10n.yaml

flutter 專案中的本地化(localization)配置檔,主要用來設定放置不同本地化(Localization)檔案路徑、預設本地化檔案及產生出載入本地化檔案的程式檔名稱。

arb-dir: lib/src/localization
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

此範例專案只有建立基本的本地化(localication)  arb 檔案 

{
	"appTitle": "flutter_skeleton",
	"@appTitle": {
		"description": "The title of the application"
	}
}

         若專案中有出現無法載入本地化(localization)檔案,則可在Terminal 視窗中執行 「flutter pub add "gen_l10n/app_localizations.dart"」於.dart_tool目錄下產生相應的目錄及檔案。








 

3.  Flutter 預設骨架專案的基本架構 

        一個最基本的 MaterialApp  的骨架 (Skeleton) 程式,至個 MaterialApp 與 AnimatedBuilder 兩個類別並搭配以混入 (mixins) ChangeNotifier 類別的方式自訂 SettingsController  類別作為主題 (Theme) 切換時產生通知事件的參數。

        因此在建立 Skeleton 專案時會自動產生其基本的運用方法,後續可以依照需求針對 AnimatedBuilder 及 MaterialApp 兩個類別所提供的參數進行程式外觀及操作介面的調整。

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

import 'sample_feature/sample_item_details_view.dart';
import 'sample_feature/sample_item_list_view.dart';
import 'settings/settings_controller.dart';
import 'settings/settings_view.dart';

/// The Widget that configures your application.
class MyApp extends StatelessWidget {
  const MyApp({ Key? key, required this.settingsController,})
               : super(key: key);

  final SettingsController settingsController;

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: settingsController,
      builder: (BuildContext context, Widget? child) {
        return MaterialApp(
         restorationScopeId: 'app',
         localizationsDelegates: const [
           AppLocalizations.delegate,
           GlobalMaterialLocalizations.delegate,
           GlobalWidgetsLocalizations.delegate,
           GlobalCupertinoLocalizations.delegate,
         ],
         supportedLocales: const [
           Locale('en', ''), // English, no country code
         ],          
         onGenerateTitle: (BuildContext context) => 
                  AppLocalizations.of(context)!.appTitle,
         
         theme: ThemeData(),
         darkTheme: ThemeData.dark(),
         themeMode: settingsController.themeMode,
 
         onGenerateRoute: (RouteSettings routeSettings) {
           return MaterialPageRoute<void>(
             settings: routeSettings,
             builder: (BuildContext context) {
               switch (routeSettings.name) {
                 case SettingsView.routeName:
                   return SettingsView(controller: settingsController);
                 case SampleItemDetailsView.routeName:
                   return const SampleItemDetailsView();
                 case SampleItemListView.routeName:
                 default:
                   return const SampleItemListView();
             }},
         );}
      );},
   );}
}

 

4.        執行各平台Flutter 偵錯

        點選右下角No Devices項目後切換至要執行偵錯的平台並執行 Run -> Start Debugging (F5) 進行偵錯

4-1.        Windows Desktop

















































4-2.        Chrome Web








































































4-3.        Linux APP (Ubuntu)



























































































4-4.        Android APP

在執行Android APP時,若無實體裝置需要先開啟Android Studio並使用AVD Manage建立模擬Android裝置








































 執行時選擇所要執行的Android裝置