學習 Flutter (一)

學習 Flutter (一)

1. 引言

  • 什么是 Flutter?

    Flutter 是 Google 開發的一套開源 UI 框架,主要用于構建高性能、高保真、跨平臺的應用程序。使用一套 Dart 編寫的代碼,開發者可以同時構建適用于:

    • Android

    • iOS

    • Web

    • Windows、macOS、Linux 桌面端

    • 嵌入式平臺(如車載、IoT 設備)

    Flutter 的核心特性包括:

    • 熱重載(Hot Reload):可以快速預覽修改結果,提高開發效率。

    • 自繪式渲染引擎(Skia):繞過原生控件,確保 UI 在各平臺一致。

    • 豐富的組件庫(Widgets):一切皆組件,易于構建復雜界面。

    • 靈活的布局系統:支持響應式和復雜嵌套的布局設計。

  • 為什么選擇 Flutter?

    選擇 Flutter 的理由主要包括以下幾點:

    • 跨平臺統一開發

      用一套 Dart 代碼即可構建多端應用,極大節省開發和維護成本。

    • 高性能
      Flutter 擁有自己的渲染引擎,不依賴原生控件,性能接近原生,尤其適合需要高幀率渲染的場景。

    • 快速開發體驗
      熱重載和熱重啟機制,加快了開發調試的迭代周期,提升開發效率。

    • 豐富的生態
      Flutter 擁有大量開源插件(如 camera、http、firebase 等),支持多數主流功能的快速集成。

    • 社區支持良好
      Google 官方持續更新,社區活躍度高,文檔齊全,資源豐富。

  • 本文檔的目標和讀者定位

    文檔目標

    本系列文檔旨在從零開始,系統性講解 Flutter 框架的核心概念與開發實戰內容。通過理論與實操結合,幫助讀者完成從入門到進階的技能成長路徑。

    具體目標包括:

    • 理解 Flutter 的核心組件與布局體系

    • 能夠獨立開發一個簡單完整的 Flutter 應用

    • 掌握跨平臺適配、狀態管理等實用技能

2. 環境準備

2.1 安裝 Android Studio

  • 下載地址與版本選擇

    官網地址:(最好開VPN)訪問 developer.android.com/studio 或者 Android Studio 下載文件歸檔 | Android Developers

  • Android Studio 簡單介紹

    Android Studio 是 Google 官方推出的 Android 應用開發集成環境(IDE),基于 JetBrains 的 IntelliJ IDEA 平臺構建。它是開發 Android 原生應用和 Flutter 應用的推薦工具,提供了豐富的功能來幫助開發者高效編寫、調試和測試應用程序, Android Studio 是一個功能齊全、插件豐富的現代化開發環境,不僅適用于傳統 Android 開發,也是目前 Flutter 開發的首選 IDE。無論是新手學習,還是企業級項目開發,Android Studio 都提供了良好的開發支持與工具生態

2.2 安裝 Flutter SDK

  • Flutter SDK 下載與安裝步驟(Windows)

    官方地址:Archive | Flutter

  • 設置環境變量

    • 在系統環境變量中新建變量

      變量名:PUB_HOSTED_URL
      變量值:https://pub.flutter-io.cn
      
      變量名:FLUTTER_STORAGE_BASE_URL
      變量值:https://storage.flutter-io.cn
      
    • 在系統變量 PATH 中添加 Flutter bin目錄

      D:\flutter_windows_3.24.1-stable\flutter\bin
      
    • Android Studio 下載 SDK 工具和 Android SDK Comman-line Tools 并下載 Flutter 和 Dart 插件

    • 執行命令

      flutter doctor -v
      

      首次執行 Flutter 命令會從網絡中拉取 Dart SDK、flutter工具等,這個過程會比較漫長

      可能一直卡在
      C:\Users\zengjh1>D:\flutter_windows_3.22.1-stable\flutter\bin\flutter.bat doctor
      Checking Dart SDK version…
      Downloading Dart SDK from Flutter engine …

      只能耐心等待,或者關閉重來,下載完后會顯示 flutter 結果

      [] Flutter (Channel stable, 3.24.1, on Microsoft Windows [版本 10.0.19044.5737], locale zh-CN)? Flutter version 3.24.1 on channel stable at D:\flutter_windows_3.24.1-stable\flutter? Upstream repository https://github.com/flutter/flutter.git? Framework revision 5874a72aa4 (11 months ago), 2024-08-20 16:46:00 -0500? Engine revision c9b9d5780d? Dart version 3.5.1? DevTools version 2.37.2? Pub download mirror https://pub.flutter-io.cn? Flutter download mirror https://storage.flutter-io.cn[] Windows Version (Installed version of Windows is version 10 or higher)[!] Android toolchain - develop for Android devices (Android SDK version 35.0.0)? Android SDK at D:\SDK? Platform android-35, build-tools 35.0.0? ANDROID_SDK_ROOT = D:\SDK? Java binary at: C:\Program Files\Java\jdk-17\bin\java? Java version Java(TM) SE Runtime Environment (build 17+35-LTS-2724)X Android license status unknown.Run `flutter doctor --android-licenses` to accept the SDK licenses.See https://flutter.dev/to/windows-android-setup for more details.[] Chrome - develop for the web? Chrome at C:\Users\zengjh1\AppData\Local\Google\Chrome\Application\chrome.exe[X] Visual Studio - develop Windows appsX Visual Studio not installed; this is necessary to develop Windows apps.Download at https://visualstudio.microsoft.com/downloads/.Please install the "Desktop development with C++" workload, including all of its default components[] Android Studio (version 2024.3)? Android Studio at F:\Program Files\Android\Android Studio? Flutter plugin can be installed from:https://plugins.jetbrains.com/plugin/9212-flutter? Dart plugin can be installed from:https://plugins.jetbrains.com/plugin/6351-dart? Java version OpenJDK Runtime Environment (build 21.0.6+-13355223-b631.42)[] Connected device (3 available)? Windows (desktop) ? windows ? windows-x64    ? Microsoft Windows [版本 10.0.19044.5737]? Chrome (web)      ? chrome  ? web-javascript ? Google Chrome 117.0.5938.63? Edge (web)        ? edge    ? web-javascript ? Microsoft Edge 138.0.3351.65[] Network resources? All expected network resources are available.! Doctor found issues in 2 categories.
      

      會提示我們那些工具缺少了什么,我們用的是 AndroidStudio,所以只要保證 AndroidStudio 這一欄沒問題就行

2.3 安裝 Dart 插件和 Flutter 插件

  • 在 Android Studio 中安裝插件的方法

    在 File -> Setting -> Plugins -> Marketplace 下搜索 Dart 和 Flutter 插件下載安裝即可。

2.4 連接真實設備

  • 設備開啟開發者 USB 調試模式
  • 設備連接與調試授權

3. 創建第一個 Flutter 項目

3.1 通過 Android Studio 創建 Flutter 項目

  • 選擇 Flutter 項目
    在這里插入圖片描述

  • 配置 Flutter SDK path

    在這里插入圖片描述

  • 項目配置
    在這里插入圖片描述

3.2 項目結構介紹

  • lib/ 文件夾及主要 Dart 文件

    • lib/ 是 Dart 代碼的主目錄

    • main.dart 是應用的啟動文件,負責引導整個 UI 構建。

    • 項目結構建議按模塊劃分(如 pages/widgets/ 等),便于組織和維護。

  • pubspec.yaml 文件含義

    pubspec.yaml 是 Flutter 和 Dart 項目的配置文件,用于聲明項目的依賴、資源、版本信息、打包配置等內容。

    它類似于其他語言生態的配置文件,例如:

    • Node.js 的 package.json

    • Java 的 pom.xml

    • Python 的 requirements.txt

    項目功能描述
    name, version定義項目元信息
    dependencies項目運行所需依賴
    dev_dependencies測試/開發所需依賴
    flutter/assets聲明項目使用的圖片、JSON、音頻等資源
    flutter/fonts配置自定義字體
    uses-material-design是否使用 Material 風格設計

4. 編寫第一個 Flutter 界面

4.1 了解 Widget 體系

  • StatelessWidget 和 StatefulWidget 區別

    • StatelessWidget(無狀態組件)

      StatelessWidget不可變的 ,其構建內容在生命周期中不會發生變化。

      適用場景:

      • 內容不需要更新,比如固定文本、圖標、樣式按鈕等。

      • UI 僅依賴構造時傳入的數據。

      class HelloText extends StatelessWidget {final String name;const HelloText({super.key, required this.name});Widget build(BuildContext context) {return Text('Hello, $name');}
      }
      
    • StatefulWidget(有狀態組件)

      StatefulWidget可變的 ,擁有自己的狀態對象 State ,當狀態改變時會觸發 UI 重新構建 (setState())。

      適用場景:

      • UI 需要根據用戶交互或數據更新而改變

      • 比如按鈕點擊計數、輸入框內容、動畫等。

      class CounterWidget extends StatefulWidget {const CounterWidget({super.key});State<CounterWidget> createState() => _CounterWidgetState();
      }class _CounterWidgetState extends State<CounterWidget> {int _count = 0;void _increment() {setState(() {_count++;});}Widget build(BuildContext context) {return Column(children: [Text('Count: $_count'),ElevatedButton(onPressed: _increment, child: const Text('Increment')),],);}
      }
      

    區別總結

    特性StatelessWidgetStatefulWidget
    狀態是否可變否(不可變)是(可變)
    是否持有狀態對象是(通過 State 類)
    UI 是否可動態更新是(調用 setState()
    重建方式構造函數參數變化時重建setState() 調用后重建
    常見應用場景靜態文本、圖標、按鈕等表單輸入、計數器、動畫等
  • Widget 樹的概念

    在 Flutter 中,一切都是 Widget,頁面 UI 是由各種 Widget 通過嵌套組合而成的,這種嵌套結構被稱為 Widget 樹

    • 什么是 Widget 樹

      Widget 樹是指:一個頁面上的所有元素(按鈕、文字、圖片、容器等)以”樹“的結構從上到下排列組合而成。

      每一個 Widget 都可能包含子 Widget,它們像”樹枝”一樣組成整個頁面的布局和邏輯

      MaterialApp
      └── Scaffold├── AppBar└── Body└── Column├── Text└── ElevatedButton
      
    • Widget 樹的層級關系

      • 父 Widget:包含其他 Widget(容器、布局等)

      • 子 Widget:被包含在某個父 Widget 中

      • Flutter 會從上往下遞歸構建、渲染、更新整課 Widget 樹

    • 為什么理解 Widget 樹很重要?

      • 調試和布局排查:Widget 樹幫助你理解某個組件在頁面中的層級與位置;

      • 性能優化:可以判斷哪些 Widget 頻繁重建,是否可以抽離為 Stateless;

      • 構建思想轉變:傳統 UI 框架強調“修改視圖”,Flutter 強調“重建 Widget 樹”。

    • Widget 樹的可視化工具

      Flutter 提供了調試工具:

      • Flutter Inspector(在 Android Studio、VSCode 中可用)

      • 可以查看實際 Widget 樹結構,幫助開發者理解頁面構造

  • 總結

    概念說明
    StatelessWidget不可變組件,適合靜態展示,構建后不會改變
    StatefulWidget可變組件,內部狀態變化時可使用 setState() 觸發重建
    Widget 樹所有 Widget 按嵌套結構組成的一棵樹,構成 UI 的骨架

4.2 修改默認代碼為“Hello World”

  • 替換原先 main.dart 內容為

    import 'package:flutter/material.dart';void main() => runApp(const MyApp());class MyApp extends StatelessWidget {const MyApp();Widget build(BuildContext context) {return const MaterialApp(home: HelloWorldPage(),);}
    }class HelloWorldPage extends StatelessWidget {const HelloWorldPage();Widget build(BuildContext context) {return const Scaffold(body: Center(child: Text('Hello World',style: TextStyle(fontSize: 24),),),);}
    }
    

5. Flutter 組件詳解

5.1 基礎組件

  • Text(文本顯示)

    用于在界面中顯示一段文本

    Text('Hello Flutter')
    

    常用屬性:

    屬性名類型說明
    styleTextStyle設置字體大小、顏色、粗細、行高等
    textAlignTextAlign文本對齊方式(如 centerleft
    maxLinesint顯示的最大行數
    overflowTextOverflow文本超出時的處理(如 ellipsis

    示例

    Text('歡迎學習 Flutter!',style: TextStyle(fontSize: 20,color: Colors.blue,fontWeight: FontWeight.bold),textAlign: TextAlign.center,maxLines: 1,overflow: TextOverflow.ellipsis,)
    
  • Image(圖片)

    用于顯示本地或網絡圖片

    常用構造函數:

    函數名說明
    Image.asset()加載項目中的本地圖片
    Image.network()加載網絡圖片
    Image.file()加載本地文件系統中的圖片
    Image.memory()加載內存中的圖片

    示例

    import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {MyApp();Widget build(BuildContext context) {return  MaterialApp(home: HelloWorldPage(),);}
    }class HelloWorldPage extends StatelessWidget {HelloWorldPage();Widget build(BuildContext context) {return  Scaffold(body: Center(child: Image.network('https://img.shetu66.com/zt/1661475606815_a10229ff.jpg',width: 200,height: 80,),),);}
    }
    
  • Icon(圖標)

    用于顯示 Material Design 風格的圖標

    基本用法

    Icon(Icons.home)
    

    常用屬性

    屬性名說明
    Icons.xxx圖標名,Flutter 內置許多圖標
    size圖標大小
    color圖標顏色

    示例

    import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {MyApp();Widget build(BuildContext context) {return MaterialApp(home: HelloWorldPage(),);}
    }class HelloWorldPage extends StatelessWidget {HelloWorldPage();Widget build(BuildContext context) {return Scaffold(body: Center(child: Icon(Icons.favorite,color: Colors.red,size: 32,),),);}
    }
    

對比

組件用途典型構造方法常用屬性
Text顯示文字Text('xxx')style, textAlign
Image顯示圖片Image.asset(), Image.network()width, height, fit
Icon顯示圖標Icon(Icons.xxx)size, color

5.2 布局組件

  • Container(容器)

    Container 是一個組合型的組件(組合了尺寸、邊距、填充、對齊、顏色、裝飾、變換等功能)。

    它本身不渲染任何內容,但可以承載一個子 Widget,并通過屬性來控制它的展示方式,它相當于

    HTML 中的 <div> + CSS 中的 margin/padding/background/transform 組合體。

    常用屬性

    屬性類型說明
    childWidget子組件
    width / heightdouble設置容器的寬度和高度
    marginEdgeInsets外邊距
    paddingEdgeInsets內邊距(對子組件生效)
    colorColor背景顏色(不能與 decoration.color 同時使用)
    alignmentAlignment控制子組件在容器內的位置
    decorationBoxDecoration背景裝飾(如圓角、邊框、背景圖等)
    transformMatrix4容器的幾何變換(如旋轉、縮放、平移)

    示例

    • 設置寬高 + 背景色 + 子組件居中

      import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {MyApp();Widget build(BuildContext context) {return MaterialApp(home: HelloWorldPage(),);}
      }class HelloWorldPage extends StatelessWidget {HelloWorldPage();Widget build(BuildContext context) {return Container(width: 200,height: 100,color: Colors.blue,alignment: Alignment.center,child:const Text('Hello Container', style: TextStyle(color: Colors.white)),);}
      }
      
    • 設置內邊距和外邊距

      import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {MyApp();Widget build(BuildContext context) {return MaterialApp(home: HelloWorldPage(),);}
      }class HelloWorldPage extends StatelessWidget {HelloWorldPage();Widget build(BuildContext context) {return Container(margin: const EdgeInsets.all(16),padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),color: Colors.green,child: const Text('帶邊距的文本'),);}
      }
      
  • 使用裝飾 decoration

    import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {MyApp();Widget build(BuildContext context) {return MaterialApp(home: HelloWorldPage(),);}
    }class HelloWorldPage extends StatelessWidget {HelloWorldPage();Widget build(BuildContext context) {return Container(width: 150,height: 150,decoration: BoxDecoration(color: Colors.orange,borderRadius: BorderRadius.circular(16),border: Border.all(color: Colors.black, width: 2),),child: const Center(child: Text('裝飾效果')),);}
    }
    
  • 添加變換(旋轉)

    import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {MyApp();Widget build(BuildContext context) {return MaterialApp(home: HelloWorldPage(),);}
    }class HelloWorldPage extends StatelessWidget {HelloWorldPage();Widget build(BuildContext context) {return Container(width: 100,height: 100,color: Colors.purple,transform: Matrix4.rotationZ(0.2),alignment: Alignment.center,child: const Text('旋轉'),);}
    }
    
  • Padding(內邊距)

    Padding 是 Flutter 中用于給子組件添加 內邊距(padding) 的布局組件。
    它的作用是:在子組件的外部(但在邊框內部)增加空白區域

    語法結構

    Padding(padding: EdgeInsets.all(8.0), // 設置內邊距child: Text('Hello Padding'),
    )
    

    示例

  • 四邊統一內邊距

    Padding(padding: EdgeInsets.all(16),child: Text('我有 16 的內邊距'),
    )
    
  • 水平、垂直內邊距不同

    Padding(padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),child: Text('左右 24,上下 12'),
    )
    
  • 僅指定某個方向

    Padding(padding: EdgeInsets.only(top: 20, left: 10),child: Text('僅上邊距 20,左邊距 10'),
    )
    

    PaddingContainer 的區別

    特性PaddingContainer
    設置內邊距專門用于設置內邊距(但只是組合屬性的一部分)
    設置顏色、大小不支持可以設置寬高、顏色、裝飾等
    推薦場景專注間距控制通用容器,做樣式和布局控制更全面
  • Align(對齊)

    Align 是 Flutter 中用于 對子組件進行位置控制 的組件。它會在自身范圍內,將 child 放置到指定的位置(例如居中、左上、右下等)

    基本語法

    Align(alignment: Alignment.center, // 默認值child: Text('居中顯示')
    )
    

    alignment 屬性詳解

    常量對應位置
    Alignment.topLeft左上角
    Alignment.topCenter上中
    Alignment.topRight右上角
    Alignment.centerLeft左中
    Alignment.center中間(默認)
    Alignment.centerRight右中
    Alignment.bottomLeft左下角
    Alignment.bottomCenter下中
    Alignment.bottomRight右下角

    本質上,alignment 是一個二維坐標系:

    • (-1, -1) 表示左上角,(1,1) 表示右下角,(0, 0) 表示正中間。“

    示例

    • 文字顯示在右下角

      Align(alignment: Alignment.bottomRight,child: Text('右下角文字'),
      )
      
    • 放一張圖片到左上角

      Align(alignment: Alignment.topLeft,child: Image.asset('assets/images/avatar.png', width: 60),
      )
      
    • 附加屬性 widthFactorheightFactor

      這些屬性可以影響 Align 本身的大小

      • widthFactor :子組件寬度 × 倍數,作為 Align 的寬度;

      • heightFactor :子組件高度 × 倍數,作為 Align 的高度;

      Align(alignment: Alignment.center,widthFactor: 2,heightFactor: 2,child: Text('我是 2 倍大'),)
      
    • 和其他對齊組件的區別

      組件功能描述
      Align精確控制子組件在父組件中的位置
      Center相當于 Align(alignment: Alignment.center)
      Padding設置內邊距,但不能控制子組件的具體位置
      Positioned用于 Stack 中,絕對定位
  • Center(居中)

    Center 是一個非常簡單的布局組件,它的作用是:將子組件放在父容器的中心位置

    基本語法

    Center(child: Text('居中顯示'),
    )
    

    它會自動讓 Text 或其他子組件在父容器中 水平居中 + 垂直居中

    示例

    • 居中顯示文本

      Center(child: Text('Hello Center',style: TextStyle(fontSize: 24),),
      )
      
    • 居中顯示圖片

      Center(child: Image.asset('assets/images/logo.png', width: 100),
      )
      
    • 結合 Container 使用

      Container(width: 300,height: 300,color: Colors.blue.shade100,child: Center(child: Text('我是居中的文字'),),
      )
      
    • Center 和其他布局組件的區別

      組件用途特點
      Center子組件居中最簡單,等價于 Align.center
      Align子組件任意對齊更靈活,需要手動指定 alignment
      Padding增加空白區域,但不控制對齊方式
      PositionedStack 中做絕對定位需要配合 Stack 使用
  • Row(水平排列)

    Row 是一個橫向布局組件,用于 將多個組件水平排列在一行內

    基本語法

    Row(children: [Text('A'),Text('B'),Text('C'),],
    )
    

    這段代碼會將 A B C 橫向排在一行里。

    • 常用屬性詳情

      屬性名類型說明
      childrenList<Widget>子組件列表
      mainAxisAlignmentMainAxisAlignment主軸(水平方向)對齊方式
      crossAxisAlignmentCrossAxisAlignment交叉軸(垂直方向)對齊方式
      mainAxisSizeMainAxisSize主軸尺寸:最大/最小(是否占滿可用空間)
      textDirectionTextDirection布局方向:從左到右(默認)還是從右到左
    • mainAxisAlignment 對齊選項(水平)

      屬性效果
      MainAxisAlignment.start左對齊(默認)
      MainAxisAlignment.center水平居中
      MainAxisAlignment.end右對齊
      MainAxisAlignment.spaceBetween兩端對齊,子項平均分布
      MainAxisAlignment.spaceAround子項周圍空白相等
      MainAxisAlignment.spaceEvenly子項之間空白完全相等

      示例

      Row(mainAxisAlignment: MainAxisAlignment.center,children: const [Icon(Icons.star, color: Colors.red),Icon(Icons.star_border, color: Colors.red),Icon(Icons.star_half, color: Colors.red),],)
      
    • crossAxisAlignment 對齊選項(垂直)

      屬性效果
      CrossAxisAlignment.start頂部對齊
      CrossAxisAlignment.center垂直居中(默認)
      CrossAxisAlignment.end底部對齊
      CrossAxisAlignment.stretch拉伸子項填滿垂直空間
      baseline(需設置 textBaseline)按文本基線對齊
  • Column(垂直排列)

    Column 是一個 豎直方向布局組件 ,可以讓多個子組件 從上到下一次排列

    基本語法

    Column(children: [Text('第一行'),Text('第二行'),Text('第三行'),],
    )
    
    • 常用屬性解釋

      屬性名類型說明
      childrenList<Widget>子組件列表
      mainAxisAlignmentMainAxisAlignment主軸(豎直方向)對齊方式
      crossAxisAlignmentCrossAxisAlignment交叉軸(水平方向)對齊方式
      mainAxisSizeMainAxisSize主軸大小控制(是否占滿可用垂直空間)
    • 主軸對齊(mainAxisAlignment)

      控制子組件在豎直方向上的排列方式

      屬性值效果
      MainAxisAlignment.start從頂部開始(默認)
      MainAxisAlignment.center垂直居中
      MainAxisAlignment.end底部對齊
      MainAxisAlignment.spaceBetween上下貼邊,中間平均分布
      MainAxisAlignment.spaceAround每個子組件周圍間距相等
      MainAxisAlignment.spaceEvenly所有子組件間距完全相等
    • 交叉軸對齊(crossAxisAlignment)

      控制子組件在水平方向上的對齊方式

      屬性值效果
      CrossAxisAlignment.start左對齊(默認)
      CrossAxisAlignment.center水平居中
      CrossAxisAlignment.end右對齊
      CrossAxisAlignment.stretch拉伸子組件到最大寬度

    示例

    • 簡單垂直排布

      Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: const [Text('標題'),SizedBox(height: 10),Text('副標題'),SizedBox(height: 10),Icon(Icons.star, size: 32),],)
      
    • 加背景 + 居中演示(配合 Container)

      Container(width: double.infinity,height: 300,color: Colors.blue.shade50,child: Column(mainAxisAlignment: MainAxisAlignment.spaceEvenly,crossAxisAlignment: CrossAxisAlignment.center,children: const [Text('上'),Text('中'),Text('下'),],),)
      
  • Stack(層疊布局)

    Stack 是一個 堆疊布局組件 允許多個子組件 按照 z 軸 (前后)方向疊加在一起

    基本語法

    Stack(children: [Container(width: 200, height: 200, color: Colors.blue),Positioned(top: 20,left: 20,child: Icon(Icons.star, size: 50, color: Colors.white),),],
    )
    
    • 常用屬性解釋

      屬性名類型說明
      childrenList<Widget>所有子組件,越靠后越在上層
      alignmentAlignment控制非 Positioned 子組件的位置
      fitStackFit控制子組件尺寸如何適應 Stack
      clipBehaviorClip是否裁剪超出部分(默認 Clip.hardEdge
    • Stack vs Positioned

      • Stack 用來定義多個疊加的層

      • Positioned 用來對某個子組件進行絕定位

      和基本語法示例對比

      Stack(children: [Container(color: Colors.yellow, width: 200, height: 200),Positioned(bottom: 10,right: 10,child: Text('右下角'),),],
      )
      
    • alignment:對非 Positioned 的子組件對齊

      Stack(alignment: Alignment.center,children: [Container(width: 100, height: 100, color: Colors.red),Text('居中'), // 自動居中],)
      

5.3 按鈕和交互組neiElevatedButton / TextButton / OutlinedButton(各種按鈕)

  • ElevatedButton / TextButton / OutlinedButton(各種按鈕)

    按鈕類型外觀描述適用場景
    ElevatedButton有陰影、背景填充、立體感強用于強調操作,如“提交”
    TextButton無邊框、無背景,僅文本用于輔助操作、二級選項
    OutlinedButton有邊框但無背景用于不那么主要的操作按鈕
    • ElevatedButton 立體按鈕

      Container(child: Column(children: [ElevatedButton(onPressed: () {print('點擊了 ElevatedButton');},child: Text('確定'),)],),color: Colors.white,)
      

      常用于強調主要操作,例如 “登錄”、“提交”。

    • TextButton(純文本按鈕)

      TextButton(onPressed: () {print('點擊了 TextButton');},child: Text('取消'),)
      

      用于不那么顯眼的按鈕,比如“忘記密碼”、“查看更多”。

    • OutlinedButton(帶邊框按鈕)

      OutlinedButton(onPressed: () {print('點擊了 OutlinedButton');},child: Text('邊框按鈕'),
      )
      

      用于中性操作,比如“跳過”、“稍后再說”。

    • 自定義按鈕樣式

      三種按鈕都支持使用 style 參數來自定義外觀,使用 ButtonStyle

      ElevatedButton(onPressed: () {},style: ElevatedButton.styleFrom(primary: Colors.blue, // 背景色onPrimary: Colors.white, // 文字顏色padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12),),),child: Text('自定義樣式'),
      )
      
    • 使用場景建議

      場景推薦按鈕類型
      提交、主操作ElevatedButton
      取消、跳過、輕操作TextButton
      次要但需強調(邊界操作)OutlinedButton
      圖標 + 文本按鈕*.icon() 系列
  • GestureDetector(手勢識別)

    GestureDetector 是一個 手勢識別器 可以監聽用戶在屏幕上的各種操作(手勢)如

    • 點擊(Tap)

    • 雙機(Double Tap)

    • 長按(Long Press)

    • 拖動(Drag)

    • 縮放(Scale)

    基本語法

    GestureDetector(onTap: () {print('點擊了組件');},child: Container(color: Colors.blue,padding: EdgeInsets.all(20),child: Text('點我'),),
    )
    
    • 常用事件一覽

      屬性名類型說明
      onTapvoid Function()單擊
      onDoubleTapvoid Function()雙擊
      onLongPressvoid Function()長按
      onPanUpdateFunction(DragUpdateDetails)拖動時觸發(全向)
      onPanStart / onPanEnd-拖動開始 / 結束
      onScaleUpdateFunction(ScaleUpdateDetails)雙指縮放

    示例

    • 點擊、長按、雙擊事件

      GestureDetector(onTap: () => print('點擊'),onDoubleTap: () => print('雙擊'),onLongPress: () => print('長按'),child: Container(padding: EdgeInsets.all(20),color: Colors.lightGreen,child: Text('點我試試'),),
      )
      
    • 拖動(onPanUpdate)

      GestureDetector(onPanUpdate: (details) {print('dx: ${details.delta.dx}, dy: ${details.delta.dy}');},child: Container(width: 200,height: 200,color: Colors.orange,child: Center(child: Text('拖動我')),),
      )
      
    • 縮放(onScaleUpdate)

      GestureDetector(onScaleUpdate: (details) {print('縮放比例:${details.scale}');},child: Image.asset('assets/images/logo.png'),
      )
      

    總結

功能是否支持示例屬性
點擊支持onTap
雙擊支持onDoubleTap
長按支持onLongPress
拖動支持onPanUpdate
縮放支持onScaleUpdate
支持嵌套其他組件支持child
無視覺效果(非按鈕)支持需要自定義樣式
  • InkWell(水波紋效果點擊)

    InkWell 是一個 帶水波紋(漣漪)點擊效果的手勢識別組件。 相比 GestureDetector 它有更好的 Material 設計風格的視覺效果

    它屬于 Material 組件體系的一部分,使用時需要有 Material 組件作為“水波紋的繪制容器”

    基本用法

    InkWell(onTap: () {print('點擊了 InkWell');},child: Padding(padding: EdgeInsets.all(16),child: Text('點我'),),
    )
    

    點擊時會看到水波紋從點擊點擴散開來

    • 常用屬性

      屬性名類型說明
      onTapvoid Function()?點擊事件
      onDoubleTapvoid Function()?雙擊事件
      onLongPressvoid Function()?長按事件
      borderRadiusBorderRadius設置水波紋圓角
      splashColorColor設置水波紋顏色
      highlightColorColor按下時的背景色
      childWidget顯示內容
    • 配合 Material 使用 (必須)

      Material(color: Colors.blue[50],borderRadius: BorderRadius.circular(12),child: InkWell(onTap: () {print('點到了卡片');},borderRadius: BorderRadius.circular(12),splashColor: Colors.redAccent.withOpacity(0.2),child: Padding(padding: EdgeInsets.all(20),child: Text('有點擊水波紋的卡片'),),),)
      
    • GestureDetectro 區別對比

      對比點GestureDetectorInkWell
      是否有視覺反饋無水波紋有水波紋
      是否依賴 Material不依賴必須依賴 Material 父組件
      支持的手勢種類拖動、縮放、滑動等更豐富主要用于點擊相關
      使用場景自定義復雜交互通常用于按鈕、卡片、列表點擊反饋等

5.4 輸入框和表單

  • TextField(文本輸入)

    TextField 是最常用的文本輸入組件,用于實現表單的輸入、搜索框、聊天框等各種輸入功能

    基本用法

    TextField(decoration: InputDecoration(labelText: '用戶名',hintText: '請輸入用戶名',border: OutlineInputBorder(),),
    )
    

    效果:一個帶標簽、提示文字、邊框的輸入框

    • 常用屬性詳情

      屬性名類型說明
      controllerTextEditingController控制和監聽輸入框內容
      decorationInputDecoration裝飾輸入框(如提示、圖標、邊框等)
      obscureTextbool是否隱藏輸入內容(用于密碼)
      keyboardTypeTextInputType輸入類型(文本、數字、郵箱等)
      maxLinesint輸入框最大行數
      onChangedFunction(String)文本改變時回調
      onSubmittedFunction(String)用戶按下“完成/提交”時的回調
      enabledbool是否可編輯
      readOnlybool是否只讀

    示例

    • 帶控制器示例(獲取輸入內容)

      
      class TextFieldExample extends StatelessWidget {final TextEditingController _controller = TextEditingController();Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('TextField 示例')),body: Padding(padding: const EdgeInsets.all(16.0),child: Column(children: [TextField(controller: _controller,decoration: InputDecoration(labelText: '輸入內容'),),SizedBox(height: 20),ElevatedButton(onPressed: () {print("你輸入了: ${_controller.text}");},child: Text('提交'))],),),);}
      }
      
    • 密碼框(隱藏輸入)

      TextField(obscureText: true,decoration: InputDecoration(labelText: '密碼',border: OutlineInputBorder(),),)
      

      不同輸入類型

      輸入類型示例設置
      文本(默認)keyboardType: TextInputType.text
      數字keyboardType: TextInputType.number
      電話keyboardType: TextInputType.phone
      郵箱keyboardType: TextInputType.emailAddress
    • 多行輸入

      TextField(maxLines: 5,decoration: InputDecoration(labelText: '多行備注'),
      )
    • 自定義裝飾 InputDecoration 示例

      TextField(decoration: InputDecoration(prefixIcon: Icon(Icons.person),suffixIcon: Icon(Icons.clear),labelText: '用戶名',hintText: '請輸入用戶名',border: OutlineInputBorder(),),
      )
  • Checkbox(多選框)

    Checkbox 是一個可以勾選/取消的組件,只有兩個狀態(true / false ) 可以搭配文字或圖標一起使用。

    基本用法

    bool _isChecked = false;Checkbox(value: _isChecked,onChanged: (bool? value) {setState(() {_isChecked = value!;});},
    )

    必須在 StatefulWidget 中使用,因為復選框的值需要動態更新。

    示例

    class CheckBoxDemo extends StatefulWidget {_CheckBoxDemoState createState() => _CheckBoxDemoState();
    }class _CheckBoxDemoState extends State<CheckBoxDemo> {bool _isSelected = false;Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Checkbox 示例")),body: Center(child: Row(mainAxisSize: MainAxisSize.min,children: [Checkbox(value: _isSelected,onChanged: (bool? value) {setState(() {_isSelected = value!;});},),Text(_isSelected ? "已選中" : "未選中"),],),),);}
    }

    常用屬性

    屬性名類型說明
    valuebool當前是否勾選
    onChanged(bool?) → void勾選狀態變化時的回調函數
    activeColorColor選中時的顏色
    checkColorColor號顏色
    tristatebool是否支持三種狀態(true/false/null)

    搭配 CheckboxListTitle (復選框 + 標題 + 子標題)

    CheckboxListTile(title: Text("我同意協議"),subtitle: Text("點擊確認后繼續"),value: _isChecked,onChanged: (value) {setState(() {_isChecked = value!;});},secondary: Icon(Icons.policy),controlAffinity: ListTileControlAffinity.leading,)
    

    總結

    你想實現的功能使用方式或屬性
    基本復選框Checkbox
    復選框 + 文字Row + TextCheckboxListTile
    支持不確定(null)狀態tristate: true
    更好看的樣式和布局CheckboxListTile
  • Radio(單選框)

    Radio<T> 是 Flutter 提供的泛型組件,用于在多個選項中選擇一個,必須搭配 groupValue 一起使用。

    最基本的用法示例

    Radio<int>(value: 1,groupValue: _selectedValue,onChanged: (int? value) {setState(() {_selectedValue = value!;});},
    )
    • value:表示當前這個單選按鈕的值

    • groupValue:表示當前“選中的值”

    • onChanged:當點擊時調用,傳入的就是 value

    選擇性別示例:

    class RadioDemo extends StatefulWidget {_RadioDemoState createState() => _RadioDemoState();
    }class _RadioDemoState extends State<RadioDemo> {String _gender = "男";Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Radio 示例")),body: Column(children: [ListTile(title: Text("男"),leading: Radio<String>(value: "男",groupValue: _gender,onChanged: (value) {setState(() {_gender = value!;});},),),ListTile(title: Text("女"),leading: Radio<String>(value: "女",groupValue: _gender,onChanged: (value) {setState(() {_gender = value!;});},),),SizedBox(height: 20),Text("你選擇的是:$_gender"),],),);}
    }
    

    常用屬性一覽

    屬性名類型說明
    valueT當前這個選項的值
    groupValueT當前組中被選中的值
    onChangedFunction(T?)點擊時回調
    activeColorColor選中狀態顏色
    toggleablebool是否支持再次點擊取消(Flutter 3.7+)
  • Switch(開關)

    Switch 是 Flutter 提供的滑動切換組件,只有兩個狀態:true (開啟)和 false (關閉)

    最基本的用法

    bool _isOn = false;Switch(value: _isOn,onChanged: (bool value) {setState(() {_isOn = value;});},
    )

    必須在 StatefulWidget 中使用,因為開關狀態需要實時更新。

    示例:

    • 控制某功能開關

      class SwitchDemo extends StatefulWidget {_SwitchDemoState createState() => _SwitchDemoState();
      }class _SwitchDemoState extends State<SwitchDemo> {bool _isDarkMode = false;Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Switch 示例")),body: Column(mainAxisAlignment: MainAxisAlignment.center,children: [Switch(value: _isDarkMode,onChanged: (bool value) {setState(() {_isDarkMode = value;});},),Text(_isDarkMode ? '暗黑模式已開啟' : '暗黑模式已關閉'),],),);}
      }

    常用屬性

    屬性名類型說明
    valuebool當前開關狀態
    onChanged(bool) → void狀態變化回調函數
    activeColorColor開啟時的主色(圓點顏色)
    activeTrackColorColor開啟時軌道顏色
    inactiveThumbColorColor關閉時圓點顏色
    inactiveTrackColorColor關閉時軌道顏色
    materialTapTargetSizeMaterialTapTargetSize調整點擊區域大小
  • Form 與 FormField(表單管理)

    在 Flutter 中,FormFormField 是用于統一管理多個輸入組件的表單系統,可以方便地進行表單驗證、提交等操作,常用于登錄、注冊、反饋等界面。

    • 什么是 FormFormField

      組件作用說明
      Form表單容器,用于管理一組輸入項(字段)
      FormField表單字段的基類(如 TextFormField)

      TextFormField 是最常用的 FormField 實現,是帶表單驗證功能的輸入框

    • Form 的基本結構

      final _formKey = GlobalKey<FormState>();Form(key: _formKey,child: Column(children: [TextFormField(decoration: InputDecoration(labelText: '用戶名'),validator: (value) {if (value == null || value.isEmpty) {return '請輸入用戶名';}return null;},),ElevatedButton(onPressed: () {if (_formKey.currentState!.validate()) {// 所有字段驗證通過print('驗證成功,提交數據');}},child: Text('提交'),),],),
      )
    • 關鍵知識點說明

      項目說明
      FormState表單狀態對象,管理字段驗證、保存等操作
      GlobalKey<FormState>唯一標識表單,獲取 FormState 對象
      validate()執行所有字段的 validator 方法,返回是否通過驗證
      save()觸發每個字段的 onSaved 回調(如果設置)
      reset()重置所有字段內容和狀態
    • 完整示例

      class FormExample extends StatefulWidget {_FormExampleState createState() => _FormExampleState();
      }class _FormExampleState extends State<FormExample> {final _formKey = GlobalKey<FormState>();String _username = '';String _password = '';Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Form 表單示例')),body: Padding(padding: EdgeInsets.all(16),child: Form(key: _formKey,child: Column(children: [TextFormField(decoration: InputDecoration(labelText: '用戶名'),validator: (value) {if (value == null || value.isEmpty) {return '請輸入用戶名';}return null;},onSaved: (value) {_username = value!;},),TextFormField(decoration: InputDecoration(labelText: '密碼'),obscureText: true,validator: (value) {if (value == null || value.length < 6) {return '密碼不能少于6位';}return null;},onSaved: (value) {_password = value!;},),SizedBox(height: 20),ElevatedButton(onPressed: () {if (_formKey.currentState!.validate()) {_formKey.currentState!.save();print('用戶名: $_username');print('密碼: $_password');}},child: Text('提交'),),],),),),);}
      }
    • TextField VS TextFormField

      區別項TextFieldTextFormField
      表單驗證支持無驗證方法支持 validator/onSaved 等
      與 Form 配合使用需要單獨管理狀態可統一使用 Form 管理
      推薦使用場景簡單輸入框表單場景(如登錄、注冊等)
    • 一些常用方法(FormState)

      方法名說明
      validate()所有字段驗證,返回布爾值
      save()調用每個字段的 onSaved()
      reset()重置整個表單

5.5 滾動視圖

  • ListView(列表)

    ListView 是一個 可滾動的線性列表視圖組件 可以直接或水平顯示一系列子組件

    • 最基本的用法

      ListView(children: [ListTile(title: Text('第1項')),ListTile(title: Text('第2項')),ListTile(title: Text('第3項')),],
      )

      默認是垂直方向的,超出屏幕會自動滾動。

    • 常見構造方式

      • ListView + children: 靜態少量內容

      • ListView.builder: 動態列表(推薦)

      • ListView.separated: 帶分隔線

      • ListView.custom: 高級自定義構造(極少用)

    • 常用屬性

      屬性名類型說明
      itemCountint列表項數量(用于 builder)
      itemBuilderIndexedWidgetBuilder構建每項內容的方法
      scrollDirectionAxis滾動方向(Axis.vertical / horizontal
      reversebool是否反轉列表顯示順序
      shrinkWrapbool是否根據內容自動收縮高度
      physicsScrollPhysics滾動行為(如禁止、彈性等)
      paddingEdgeInsets設置內邊距
    • 示例

      class ListViewDemo extends StatelessWidget {final List<String> items = List.generate(20, (index) => '項目 $index');Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('ListView 示例')),body: ListView.builder(itemCount: items.length,itemBuilder: (context, index) {return ListTile(leading: Icon(Icons.start),title: Text(items[index]),onTap: () {print('你點擊了: ${items[index]}');},);}));}
      }
  • GridView(網格)

    GridView(網格布局),它是用來顯示多列(多行多列)的組件,常用于圖片展示、商品列表、圖標宮格菜單等場景。GridView 是一個支持滾動的二維網格布局組件,和 ListView 類似,但可以在橫向上自動分布多個元素。

    • 常用構造方法

      • GridView.count(常規固定列數網格)

        GridView.count(crossAxisCount: 3,children: List.generate(9, index {return Container(alignment: Alignment.center,color: Colors.blue[100 * ((index % 8) + 1)],child: Text('項 $index'));});
        );
        
      • GridView.builder(推薦用于大數據列表)

        GridView.builder(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2,         // 每行 2 個crossAxisSpacing: 10,      // 橫向間距mainAxisSpacing: 10,       // 縱向間距childAspectRatio: 1.5,     // 寬高比(默認是 1)),itemCount: 20,itemBuilder: (context, index) {return Container(color: Colors.teal[100 * ((index % 8) + 1)],alignment: Alignment.center,child: Text('Grid $index'),);},
        )
      • GridView.extent(指定最大寬度自動適配列數)

        GridView.extent(maxCrossAxisExtent: 100, // 每個項最大寬度,系統自動決定多少列children: List.generate(20, (index) {return Container(alignment: Alignment.center,color: Colors.orange[100 * ((index % 8) + 1)],child: Text('Item $index'),);}),
        )
    • 常用屬性說明

      屬性名類型說明
      crossAxisCountint每行顯示的列數
      mainAxisSpacingdouble每行之間的間距(垂直方向)
      crossAxisSpacingdouble每列之間的間距(水平方向)
      childAspectRatiodouble寬高比(寬/高)
      shrinkWrapbool是否根據內容高度自適應(適用于嵌套)
      physicsScrollPhysics滾動行為(常用于嵌套時禁用滾動)
    • 示例

      import 'package:flutter/material.dart';class GridViewExample extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('GridView 示例')),body: GridView.builder(padding: EdgeInsets.all(10),gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, // 3列crossAxisSpacing: 10,mainAxisSpacing: 10,childAspectRatio: 1.0, // 寬高比 1:1),itemCount: 12,itemBuilder: (context, index) {return Container(color: Colors.blue[100 * ((index % 8) + 1)],alignment: Alignment.center,child: Text('第 $index 項'),);},),);}
      }
  • SingleChildScrollView(單子節點滾動)

    SingleChildScrollView 允許一個子組件在主軸滾動(通常是垂直) 適用于控件數量不定時避免溢出(overflow)錯誤。

    • 基本用法

      SingleChildScrollView(child: Column(children: [Text('A'),Text('B'),Text('C'),// 很多內容...],),
      )

      SingleChildScrollViewchild 只能是 一個 Widget,通常搭配 Column 使用。

    • 典型使用場景

      • 登錄頁 / 注冊頁(鍵盤彈出時防止布局溢出)

      • 表單頁面(需要整體滾動)

      • 多控件組合的頁面(不是列表)

    • 重要屬性說明

      屬性名類型說明
      scrollDirectionAxis滾動方向,默認是 Axis.vertical
      paddingEdgeInsets內邊距
      reversebool是否反向滾動
      physicsScrollPhysics滾動行為(如彈性、不可滾動)
      controllerScrollController控制滾動、監聽滾動位置等
    • 示例

      import 'package:flutter/material.dart';class ScrollDemo extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('SingleChildScrollView 示例')),body: SingleChildScrollView(padding: EdgeInsets.all(16),child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: List.generate(20, (index) {return Padding(padding: EdgeInsets.symmetric(vertical: 8),child: Text('第 $index 行文本內容'));}),),),);}
      }
    • ListView 區別對比

      對比項SingleChildScrollViewListView
      用法場景多個固定控件、表單頁面長列表、動態項
      性能優化沒有懶加載,所有內容一次性渲染支持懶加載
      子組件結構一個 Widget(如 Column)包多個控件多個 Widget 構建
      嵌套使用更適合嵌套在頁面中或布局中嵌套需注意高度限制和滾動沖突

5.6 導航和路由

  • Navigator 介紹

    Navigator 是用于管理頁面(Route)跳轉和堆棧操作的組件,類似網頁的前進、后退、跳轉操作。

    • 什么是 Navigator ?

      Navigator 是一個頁面堆棧管理器,你可以:

      • push:打開新頁面(入棧)

      • pop:返回上一個頁面(出棧)

      • replace:替換當前頁面

      • 清空所有頁面再跳轉:跳轉并清空歷史

      Navigator 通常配合 MaterialPageRoutenamed route 使用。

    • 最基礎的頁面跳轉方式

      • 跳轉到新頁面(push)

        Navigator.push(context,MaterialPageRoute(builder: (context) => SecondPage()),
        );
      • 返回上一級頁面(pop)

        Navigator.pop(context);
    • 帶返回值的頁面跳轉

      A → B,B返回數據給A:

      在 A 頁面:

      void _goToSecondPage() async {final result = await Navigator.push(context,MaterialPageRoute(builder: (context) => SecondPage()),);print("從第二頁返回的數據: $result");
      }

      在 B 頁面:

      ElevatedButton(onPressed: () {Navigator.pop(context, "這是返回值");},child: Text("返回并攜帶數據"),
      )
    • 使用命名路由(推薦方式)

      • 定義路由表

        MaterialApp(initialRoute: '/',routes: {'/': (context) => HomePage(),'/second': (context) => SecondPage(),},
        )
      • 跳轉方式

        Navigator.pushNamed(context, '/second');
      • 返回方式

        Navigator.pop(context);
    • 常見跳轉方式對比

      跳轉方式用法適合場景
      push()直接傳入 Widget簡單項目
      pushNamed()使用路由名稱跳轉大型項目,統一管理路由
      pushReplacement()替換當前頁面(無返回)登錄成功替換登錄頁等
      pushAndRemoveUntil()清空歷史再跳轉登錄后清空所有導航棧
    • 小結

      功能推薦方式
      普通頁面跳轉Navigator.push()
      命名路由跳轉Navigator.pushNamed()
      頁面返回攜帶數據Navigator.pop(context, result)
      替換頁面,不保留返回Navigator.pushReplacement()
      清空頁面棧并跳轉Navigator.pushAndRemoveUntil()
  • push 和 pop

    pushpop 是 Flutter 中 Navigator 導航系統的兩個最核心方法,分別用于打開新頁面返回上一個頁面,就像“網頁的前進和后退”。

    • Navigator.push()

      作用:** 打開(壓棧)一個新頁面**

      Navigator.push(context,MaterialPageRoute(builder: (context) => SecondPage()),
      );
      
      • context:當前頁面的上下文

      • MaterialPageRoute:常用的頁面過渡動畫(安卓風格)

      • SecondPage():你要跳轉的新頁面 Widget

      示例

      ElevatedButton(onPressed: () {Navigator.push(context,MaterialPageRoute(builder: (context) => SecondPage()),);},child: Text("去第二頁"),
      )
      
    • Navigator.pop()

      作用:返回(出棧)上一個頁面

      Navigator.pop(context);
      

      可選地返回一個值:

      Navigator.pop(context, "返回的數據");
      
    • push + pop 結合使用(帶返回值)

      • 第一個頁面

        void _goToSecondPage() async {final result = await Navigator.push(context,MaterialPageRoute(builder: (context) => SecondPage()),);print("從第二頁返回的數據是:$result");
        }
      • 第二個頁面

        ElevatedButton(onPressed: () {Navigator.pop(context, "你好,這是返回值");},child: Text("返回并傳數據"),
        )
    • Navigator 的“堆棧”原理圖示

      初始:
      [ HomePage ]push(SecondPage)
      [ HomePage, SecondPage ]push(ThirdPage)
      [ HomePage, SecondPage, ThirdPage ]pop()
      [ HomePage, SecondPage ]
    • push / pop 常見變體

      方法名功能說明
      push()壓入新頁面
      pop()彈出當前頁面
      pushReplacement()替換當前頁面
      popUntil()返回到滿足條件的頁面
      pushAndRemoveUntil()清空頁面棧并跳轉
    • 總結

      功能方法
      打開新頁面Navigator.push()
      返回上一頁Navigator.pop()
      替換當前頁面Navigator.pushReplacement()
      返回并帶數據Navigator.pop(context, value)
      多頁面返回(條件)Navigator.popUntil()

5.7 其他常用組件

  • AppBar(應用欄)

    AppBar 是 Scaffold(腳手架頁面)的頂部欄,常用于顯示:頁面標題(title)、返回按鈕(自動生成)、操作按鈕(Icon)、搜索框、TabBar、菜單等

    它是 Flutter 應用中幾乎每個頁面都會使用的標準導航欄。

    • 基本語法

      Scaffold(appBar: AppBar(title: Text('我是標題'),),body: Center(child: Text('內容')),
      )
    • 常用屬性說明

      屬性名類型作用說明
      titleWidget應用欄的標題,通常是 Text
      leadingWidget左側圖標(默認是返回箭頭)
      actionsList<Widget>右側圖標按鈕列表
      backgroundColorColor背景顏色
      centerTitlebool是否居中標題(iOS 默認為 true)
      elevationdouble陰影高度(默認 4)
      bottomPreferredSizeWidget下方擴展區域,如 TabBar
    • 示例

      import 'package:flutter/material.dart';class AppBarExample extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('AppBar 示例'),leading: Icon(Icons.menu),actions: [IconButton(icon: Icon(Icons.search),onPressed: () {print('搜索按鈕點擊');},),IconButton(icon: Icon(Icons.more_vert),onPressed: () {print('更多菜單');},),],),body: Center(child: Text('頁面內容區域'),),);}
      }
  • Scaffold(腳手架,基礎頁面布局)

    Scaffold 是 Flutter 提供的 頁面結構容器,提供了一個基本布局框架,包含:AppBar(頂部應用欄)、Body(主要內容區)、Drawer(側邊欄)、BottomNavigationBar(底部導航)、FloatingActionButton(懸浮按鈕)

    、SnackBar(輕提示)等。它就像“頁面的骨架”,你把各種 UI 部件放進去就可以構成完整的頁面。

    • 基本使用方式

      Scaffold(appBar: AppBar(title: Text("首頁")),body: Center(child: Text("Hello World")),
      )
      
    • Scaffold 的常用屬性詳解

      屬性名類型作用說明
      appBarAppBar頁面頂部導航欄
      bodyWidget頁面主要內容區域
      floatingActionButtonFloatingActionButton頁面懸浮按鈕
      drawerDrawer左側滑出菜單
      bottomNavigationBarBottomNavigationBar頁面底部導航欄
      backgroundColorColor頁面背景色
      persistentFooterButtonsList<Widget>固定在底部的按鈕組
      bottomSheetWidget頁面底部懸浮層
    • 示例

      import 'package:flutter/material.dart';class ScaffoldExample extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Scaffold 示例')),body: Center(child: Text('我是頁面內容')),floatingActionButton: FloatingActionButton(onPressed: () {ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("你點擊了按鈕")),);},child: Icon(Icons.add),),drawer: Drawer(child: ListView(children: [DrawerHeader(decoration: BoxDecoration(color: Colors.blue),child: Text("菜單頭部", style: TextStyle(color: Colors.white))),ListTile(title: Text("選項1")),ListTile(title: Text("選項2"))],),),bottomNavigationBar: BottomAppBar(child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround,children: [IconButton(onPressed: (){}, icon: Icon(Icons.home)),IconButton(onPressed: (){}, icon: Icon(Icons.person))],),),);}
      }
    • 常見組合搭配

      頁面需求Scaffold 結構用法
      普通頁面(頂部+內容)appBar + body
      帶懸浮操作按鈕floatingActionButton
      左側菜單導航drawer
      底部固定菜單欄bottomNavigationBar or BottomAppBar
      顯示提示ScaffoldMessenger.of(context).showSnackBar(...)
  • Drawer(抽屜導航)

    Drawer 是 Scaffold 提供的一個側邊導航菜單,通常從左邊滑出,用于展示導航選項、用戶信息等。

    • 基本結構

      Drawer(child: ListView(padding: EdgeInsets.zero,children: [DrawerHeader(decoration: BoxDecoration(color: Colors.blue),child: Text('用戶信息'),),ListTile(leading: Icon(Icons.home),title: Text('首頁'),onTap: () {// 點擊事件},),ListTile(leading: Icon(Icons.settings),title: Text('設置'),onTap: () {// 點擊事件},),],),
      )
    • Drawer 常用組件說明

      組件作用
      DrawerHeader抽屜頂部區域,一般用于展示用戶頭像、昵稱
      ListTile列表項,一般用于菜單選項
      ListView內容可滾動
    • 打開與關閉 Drawer

      • 自動打開

        用戶手動左滑

        點左上角菜單按鈕(如果 AppBar 中設置了 automaticallyImplyLeading: true)

      • 手動打開

        Scaffold.of(context).openDrawer(); // 僅限于在子 Widget 中使用 Builder 包裹
        
      • 手動關閉

        Navigator.pop(context)
        
    • 示例

      class DrawerExample extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Drawer 示例')),drawer: Drawer(child: ListView(padding: EdgeInsets.zero,children: [const UserAccountsDrawerHeader(accountName: Text('張三'),accountEmail: Text("zhangsan@example.com"),currentAccountPicture: CircleAvatar(backgroundImage: AssetImage('assets/images/ic_launcher.png'),),),ListTile(leading: const Icon(Icons.home),title: const Text('首頁'),onTap: () {Navigator.pop(context);},),ListTile(leading: const Icon(Icons.settings),title: const Text('設置'),onTap: () {Navigator.pop(context);},),],),),body: const Center(child: Text('主頁面內容')));}
      }
    • 小結

      你要實現的功能推薦做法
      左側菜單導航使用 Scaffold.drawer
      右側快捷操作菜單使用 Scaffold.endDrawer
      展示用戶頭像信息使用 UserAccountsDrawerHeader
      菜單點擊關閉并跳轉Navigator.pop() 再導航頁面
  • BottomNavigationBar(底部導航欄)

    BottomNavigationBar 是 Flutter 提供的一個底部導航欄組件,配合 Scaffold 使用,支持多個標簽切換視圖頁面。

    它可以 : 顯示多個 tab 標簽(一般 3 ~ 5 個);高亮當前選中項;點擊切換頁面(配合 IndexedStack)

    • 基本用法

      Scaffold(bottomNavigationBar: BottomNavigationBar(currentIndex: 0, // 當前選中索引onTap: (index) {// 切換頁面邏輯},items: [BottomNavigationBarItem(icon: Icon(Icons.home),label: '首頁',),BottomNavigationBarItem(icon: Icon(Icons.person),label: '我的',),],),
      )
    • 示例

      import 'package:flutter/material.dart';class BottomNavExample extends StatefulWidget {_BottomNavExampleState createState() => _BottomNavExampleState();
      }class _BottomNavExampleState extends State<BottomNavExample> {int _currentIndex = 0;final List<Widget> _pages = [Center(child: Text('首頁內容')),Center(child: Text('分類內容')),Center(child: Text('我的內容'))];Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("底部導航示例")),body: IndexedStack (index: _currentIndex,children: _pages,),bottomNavigationBar: BottomNavigationBar (currentIndex: _currentIndex,onTap: (index) {setState(() {_currentIndex = index;});},items: [BottomNavigationBarItem(icon: Icon(Icons.home), label: "首頁"),BottomNavigationBarItem(icon: Icon(Icons.category), label: "分類"),BottomNavigationBarItem(icon: Icon(Icons.person), label: "我的"),],),);}
      }
    • 屬性說明

      屬性名類型說明
      itemsList菜單項(最少2項)
      currentIndexint當前選中項的索引
      onTapFunction(int)點擊導航項回調
      typeBottomNavigationBarType顯示樣式:fixed(默認)或 shifting(動效)
      selectedItemColorColor選中項顏色
      unselectedItemColorColor未選中項顏色
      backgroundColorColor背景色

6. 狀態管理基礎

6.1 什么是狀態?

簡單來說,狀態就是某個變量的值 當這個值發生變化時,對應的 UI會自動刷新 展示新的內容,

比如:

  1. 一個計數器的數字是狀態 (count = 3)

  2. 一個按鈕是否選中是狀態(isSelected = true

  3. 一個頁面當前是“加載中”還是“已完成”是狀態(loading = true / false

示例

int count = 0; // 這就是一個狀態ElevatedButton(onPressed: () {setState(() {count++;});},child: Text('點擊了 $count 次'),
)
  • Flutter 中狀態是怎么驅動 UI 的?

    Flutter 的 Widget 是聲明時UI,它不是手動改動控件,而是重新構建:

    // 當狀態改變時
    setState((){count++; // 修改狀態
    });
    // Flutter 自動重新調用 build() -> 根據新狀態更新 UI
    

    這就是 Flutter 的核心機制: 狀態驅動UI

  • 狀態在哪些 Widget 中存在?

    Widget 類型狀態管理方式
    StatelessWidget(無狀態)固定不變的 UI,只能顯示數據
    StatefulWidget(有狀態)可變 UI,狀態變化會自動刷新
  • 常見狀態的例子

    場景狀態變量
    計數器int counter
    登錄表單String username, password
    切換主題bool isDarkMode
    是否選中某項bool isChecked
    當前頁面索引int currentIndex

7. 資源管理

  • 圖片資源的使用

    在 Flutter 中使用圖片資源是構建 UI 的基本技能之一,分為以下幾類資源使用方式:

    • Flutter 中的圖片來源類型

      圖片來源示例使用方式
      本地 assets項目中的 assets/images/Image.asset(...)
      網絡圖片網絡鏈接Image.network(...)
      內存 / 字節流Uint8List 數據Image.memory(...)
      文件系統圖片本地文件路徑Image.file(...)
    • 使用本地圖片(assets)

      • 步驟一:創建 assets 目錄

        在項目根目錄下創建文件夾:

        /assets/images/
        

        放入圖片,例如:

        assets/images/logo.png
        
      • 步驟二:配置 pubspec.yaml

        打開 pubspec.yaml ,添加以下內容并取消注釋縮進對齊:

        flutter:uses-material-design: trueassets:- assets/images/logo.png# 或包含整個文件夾:# - assets/images/
        

        注意:

        1. 縮進要使用空格(不能用 Tab)

        2. 圖片路徑對大小寫敏感

      • 步驟三:使用 Image.asset 顯示圖片

        Image.asset('assets/images/logo.png',width: 200,height: 100,fit: BoxFit.cover, // 控制縮放裁剪方式
        )
        
    • 使用網絡圖片(Image.network)

      Image.network('https://flutter.dev/images/flutter-logo-sharing.png',width: 200,height: 100,fit: BoxFit.contain,loadingBuilder: (context, child, progress) {if (progress == null) return child;return CircularProgressIndicator();},errorBuilder: (context, error, stackTrace) {return Icon(Icons.error);},
      )
      

      建議總是配 loadingBuildererrorBuilder 處理網絡情況。

    • 圖片控件常用屬性

      屬性名類型說明
      widthdouble圖片寬度
      heightdouble圖片高度
      fitBoxFit圖片縮放裁剪方式,如 containcover
      colorColor給圖片加上顏色遮罩(配合 colorBlendMode
      repeatImageRepeat圖片重復方式(如 repeat-x)
      alignmentAlignment圖片對齊方式
    • 圖片裁剪、圓形、邊框示例

      • 圓形頭像

        ClipOval(child: Image.asset('assets/images/avatar.jpg',width: 100,height: 100,fit: BoxFit.cover,),
        )
        
      • 圓角圖片

        ClipRRect(borderRadius: BorderRadius.circular(12),child: Image.asset('assets/images/banner.jpg'),
        )
        
    • 示例

      class ImageExample extends StatelessWidget {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("圖片示例")),body: Column(children: [Text("本地圖片:"),Image.asset('assets/images/ic_launcher.png', width: 100),SizedBox(height: 20),Text("網絡圖片:"),Image.network("https://www.163987.com/d/file/p/2023/05-12/01f170d69eace10455c7116e98290099.png",width: 100)],));}
      }
    • 總結

      目標方法
      加載項目中的圖片Image.asset('路徑')
      加載網絡圖片Image.network('url')
      加載本地文件圖片Image.file(File('路徑'))
      加載內存字節圖片Image.memory(Uint8List)
  • 字體和圖標配置

    • 使用字體

      • 步驟一:添加字體文件

        在項目中創建字體目錄:

        assets/fonts/
        

        放入字體文件,例如:

        assets/fonts/Pacifico-Regular.ttf
        
      • 步驟二:配置 pubspec.yaml

        flutter: 區塊下添加字體配置(注意縮進!):

        flutter:uses-material-design: truefonts:- family: Pacificofonts:- asset: assets/fonts/Pacifico-Regular.ttf
      • 步驟三:使用字體

        Text('Hello 字體',style: TextStyle(fontFamily: 'Pacifico',fontSize: 32,),
        )
        
    • 使用內置圖標(Material Icons)

      Flutter 默認包含 Material Icons 圖標庫,只要:

      flutter:uses-material-design: true
      

      即可使用:

      Icon(Icons.favorite, color: Colors.red)
      
  • pubspec.yaml 中資源聲明

    Flutter 中的 assets 是項目中包含的靜態資源,例如:

    • 圖片(PNG、JPG、SVG)

    • 音頻(MP3、WAV)

    • 字體文件(TTF)

    • JSON / 文本 / 配置文件等

    這些資源 必須在 pubspec.yaml 中顯式聲明 才能在應用中使用。

    • 聲明單個文件

      flutter:assets:- assets/images/logo.png
      
    • 聲明整個文件夾

      flutter:assets:- assets/images/- assets/audio/
      
    • 注意事項

      說明
      縮進必須是 2 個空格,不能用 Tab!
      區分大小寫logo.PNGlogo.png
      文件路徑必須真實存在,拼寫要對
      不支持通配不能寫成 assets/images/*.png,只能手動列出或列目錄
      修改后需每次更改 assets 配置都應運行 flutter pub get 或重啟 IDE 使其生效

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/914507.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/914507.shtml
英文地址,請注明出處:http://en.pswp.cn/news/914507.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot 實現圖片防盜鏈:Referer 校驗與 Token 簽名校驗完整指南

Spring Boot 實現圖片防盜鏈教程&#xff08;Referer 校驗 Token 簽名校驗&#xff09;本文將詳細講解兩種防盜鏈實現方案&#xff0c;并提供完整代碼示例。方案一&#xff1a;Referer 校驗通過檢查 HTTP 請求頭中的 Referer 字段判斷來源是否合法。實現步驟創建 Referer 攔截…

從 JSON 到 Python 對象:一次通透的序列化與反序列化之旅

目錄 一、為什么要談 JSON 二、最快速上手&#xff1a;兩把鑰匙 dumps 與 loads 三、深入 dumps&#xff1a;參數是魔法棒 四、深入 loads&#xff1a;把風險擋在門外 五、文件級序列化&#xff1a;dump 與 load 六、處理中文與編碼陷阱 七、異常場景與調試技巧 八、實…

Leetcode 3315. 構造最小位運算數組 II

1.題目基本信息 1.1.題目描述 給你一個長度為 n 的質數數組 nums 。你的任務是返回一個長度為 n 的數組 ans &#xff0c;對于每個下標 i &#xff0c;以下 條件 均成立&#xff1a; ans[i] OR (ans[i] 1) nums[i] 除此以外&#xff0c;你需要 最小化 結果數組里每一個 a…

黑搜小知識 | DNS域名解析過程是什么樣的?

什么是DNS&#xff1f;DNS( Domain Name System)是“域名系統”的英文縮寫&#xff0c;是一種組織成域層次結構的計算機和網絡服務命名系統&#xff0c;它用于TCP/IP網絡&#xff0c;它所提供的服務是用來將主機名和域名轉換為IP地址的工作。舉例來說&#xff0c;如果你要訪問域…

MyBatis 使用教程及插件開發

作者&#xff1a;小凱 沉淀、分享、成長&#xff0c;讓自己和他人都能有所收獲&#xff01; 本文的宗旨在于通過簡單干凈實踐的方式教會讀者&#xff0c;使用 SpringBoot 配置 MyBatis 并完成對插入、批量插入、修改、查詢以及注解事務和編程事務的使用&#xff0c;通過擴展插件…

Maui勸退:用windows直接真機調試iOS,無須和Mac配對

初級代碼游戲的專欄介紹與文章目錄-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代碼都將會位于ctfc庫中。已經放入庫中我會指出在庫中的位置。 這些代碼大部分以Linux為目標但部分代碼是純C的&#xff0c;可以在任何平臺上使用。 源碼指引&#xff1a;github源…

【極客日常】后端任務動態注入執行策略的一種技術實現

近期做項目時遇到一個場景&#xff0c;是需要在后端任務執行時動態注入策略。具體而言&#xff0c;筆者負責的后端服務&#xff0c;可以理解是會在線上服務發布時&#xff0c;對服務風險做實時掃描&#xff0c;那么這個掃描就需要根據當前線上服務發布上下文&#xff0c;匹配對…

8. JVM類裝載的執行過程

1. JVM介紹和運行流程-CSDN博客 2. 什么是程序計數器-CSDN博客 3. java 堆和 JVM 內存結構-CSDN博客 4. 虛擬機棧-CSDN博客 5. JVM 的方法區-CSDN博客 6. JVM直接內存-CSDN博客 7. JVM類加載器與雙親委派模型-CSDN博客 8. JVM類裝載的執行過程-CSDN博客 9. JVM垃圾回收…

Linux操作系統之信號:信號的產生

前言&#xff1a;上篇文章我們大致講解了信號的有關概念&#xff0c;為大家引入了信號的知識點。但光知道那些是遠遠不夠的。本篇文章&#xff0c;我將會為大家自己的講解一下信號的產生的五種方式&#xff0c;希望對大家有所幫助。一、鍵盤&#xff08;硬件&#xff09;產生信…

pdf拆分

文章目錄 背景目標實現下載 背景 好不容易下載的1000頁行業報告&#xff0c;領導非要按章節拆分成20份&#xff01;學術論文合集需要按作者拆分投稿&#xff0c;手動分頁到懷疑人生…客戶發來加密合同&#xff0c;要求每5頁生成獨立文檔&#xff0c;格式還不能亂&#xff01; …

vue3使用mermaid生成圖表,并可編輯

效果圖實際代碼<template><div class"mermaid-container" style"z-index: 99999" ref"wrapperRef"><!-- 控制欄 --><div class"control-bar"><div class"control-bar-flex control-bar-tab-wrap"…

tcp/quic 的滑動窗口

一、滑動窗口 rwnd&#xff1a; 接收端窗口&#xff0c;接收方在每次發送ACK確認報文時&#xff0c;會包含一個 rwnd (Receive Window Size) 字段&#xff0c;指明自己當前剩余的接收緩沖區大小&#xff08;即可用窗口&#xff09;&#xff0c;這里是否是socket的接收緩沖區&am…

JVM監控及診斷工具-命令行篇

18.1. 概述 性能診斷是軟件工程師在日常工作中需要經常面對和解決的問題&#xff0c;在用戶體驗至上的今天&#xff0c;解決好應用的性能問題能帶來非常大的收益。 Java 作為最流行的編程語言之一&#xff0c;其應用性能診斷一直受到業界廣泛關注。可能造成 Java 應用出現性能…

Jenkins 版本升級與插件問題深度復盤:從 2.443 到 2.504.3 及功能恢復全解析

前言&#xff1a;問題溯源與升級必要性 在 Jenkins 持續集成體系中&#xff0c;插件生態是其強大功能的核心驅動力。然而&#xff0c;某次例行維護中&#xff0c;團隊對 Jenkins 2.443 環境的插件進行批量升級后&#xff0c;意外觸發連鎖反應 &#xff1a; SSH Server 插件功能…

Ribbon實戰

一、前置知識 1.1 負載均衡定義 負載均衡指的是將網絡請求通過不同的算法分配到不同的服務器上的技術&#xff0c;從而提升系統的性能。 1.2 負載均衡工具 負載均衡工具可以分分為客戶端負載均衡工具和服務端負載均衡工具&#xff0c;它們的區別如下。 表1-1 負載均衡工具…

cs285學習筆記(一):課程總覽

根據 Fall 2023 學期的官方課程日程&#xff0c;這里是 CS?285 全課程的 Lecture 大綱及內容摘要&#xff0c;詳細對應周次和主題&#xff0c;方便你快速定位每節課要點、相關作業與視頻資源 &#x1f3af; 官方課程地址 YouTobe 視頻地址 blibli視頻(帶中文字幕) &#x…

OkHttp SSE 完整總結(最終版)

1. SSE 基礎概念 什么是 SSE&#xff1f; SSE&#xff08;Server-Sent Events&#xff09;是一種 Web 標準&#xff0c;允許服務器向客戶端推送實時數據。 核心特點 單向通信&#xff1a;服務器 → 客戶端 基于 HTTP 協議&#xff1a;使用 GET 請求 長連接&#xff1a;連…

聚寬sql數據庫傳遞

自建數據庫從聚寬到Q-MT自動化交易實戰 從接觸聚寬以來一直都是手動跟單&#xff0c;在網上看到許多大佬的自動交易文章&#xff0c;心里也不禁十分癢癢。百說不如一練&#xff0c;千講不如實干。經過一番努力&#xff0c;終于成功實盤了&#xff0c;效果還可以&#xff0c;幾…

es里為什么node和shard不是一對一的關系

提問&#xff1a; 既然多個shard會被分配到同一個node上&#xff0c;那么為什么不把多個shard合并成一個然后存在當前node上呢&#xff0c;簡而言之也就是讓node和shard形成一對一的關系呢 &#xff1f;非常好的問題&#xff0c;這正是理解Elasticsearch分片&#xff08;shard…

淺談npm,cnpm,pnpm,npx,nvm,yarn之間的區別

首先做一個基本的分類 名稱描述npm,cnpm,yarn,pnpm都是Javascript包管理器nvm是Node.js版本控制器npx命令行工具 I.npm,cnpm,yarn,pnpm npm (Node Package Manager) npm是Node.js默認的包管理器&#xff0c;隨Node.js的安裝會一起安裝。使用npm可以安裝&#xff0c;發布&…