1、语法
1.1 空值赋值运算符
_fToast ??= FToast(); if (_fToast == null) { _fToast = FToast(); }
1.2 定时器
依赖import 'dart:async';
import 'dart:async'; import 'package:flutter/material.dart'; class TestPage extends StatefulWidget { @override _TestPageState createState() => _TestPageState(); } class _TestPageState extends State<TestPage> { late Timer timer; @override void initState() { super.initState(); // 1. 延迟执行(setTimeout) Future.delayed(Duration(seconds: 2), () { print("2秒后执行"); }); // 2. 循环执行(setInterval) timer = Timer.periodic(Duration(seconds: 1), (timer) { print("每秒执行一次"); }); } @override void dispose() { timer.cancel(); // 页面销毁时必须停止!防内存泄漏 super.dispose(); } @override Widget build(BuildContext context) { return Scaffold(body: Center(child: Text("定时器测试"))); } }延时器还可以如下写
// 1. 如果定时器正在运行,先取消(防止重复触发) _logoutDebounceTimer?.cancel(); // 2. 创建一个【3秒后只执行1次】的定时器 _logoutDebounceTimer = Timer(const Duration(seconds: 3), () { _isLoggingOut = false; // 3秒后执行这句 });
1.3 WidgetsBinding.instance
核心方法
// 1. 帧后执行(如获取尺寸、状态同步) WidgetsBinding.instance.addPostFrameCallback((_) { // 代码在当前帧绘制完成后执行 }); // 2. 监听应用生命周期 class MyObserver with WidgetsBindingObserver { @override void didChangeAppLifecycleState(AppLifecycleState state) { print('生命周期: $state'); } } WidgetsBinding.instance.addObserver(MyObserver()); // 3. 等待首帧完成 await WidgetsBinding.instance.endOfFrame;1. 帧调度 / 回调
addPostFrameCallback(FrameCallback callback) →void:添加帧后回调(当前帧结束执行)。addPersistentFrameCallback(FrameCallback callback) →void:添加持久帧回调(每帧执行)Flutter。scheduleFrame() →void:主动调度一帧。scheduleForcedFrame() →void:强制调度帧(无视 Vsync)Flutter。cancelFrameCallbackWithId(int id) →void:取消指定 ID 的帧回调。2. 生命周期与监听
addObserver(WidgetsBindingObserver observer) →void:添加生命周期 / 路由监听。removeObserver(WidgetsBindingObserver observer) →void:移除监听。3. 任务调度
scheduleTask(VoidCallback task,Priority priority) →void:调度高 / 中 / 低优先级任务。4. 根 Widget 管理
scheduleAttachRootWidget(Widget rootWidget) →void:调度挂载根 WidgetFlutter。attachRootWidget(Widget rootWidget) →void:直接挂载根 Widget。5. 服务与扩展
registerBoolServiceExtension(...) →void:注册布尔型服务扩展(调试用)。setSemanticsEnabled(bool enabled) →void:开启 / 关闭语义化(无障碍)。6. 常用工具
ensureVisualUpdate() →void:确保视图更新(触发重绘)。handleAppLifecycleStateChanged(AppLifecycleState state) →void:手动触发生命周期变更。核心属性
1. 调度 / 帧相关
endOfFrame→Future<void>:当前帧结束后完成的 Future,常用于帧后执行代码Flutter。
Dart// 等待当前帧结束 await WidgetsBinding.instance.endOfFrame; print('当前帧已结束');
currentFrameTimeStamp→Duration:当前帧时间戳Flutter。
Dartfinal timeStamp = WidgetsBinding.instance.currentFrameTimeStamp; print('当前帧时间戳(微秒): $timeStamp'); // 0:00:00.123456 0 小时 0 分 0 秒 123456 微秒 // 1. 总微秒数(最精确,Flutter 内部用这个) int microseconds = timeStamp.inMicroseconds; // 2. 总毫秒数 int ms = timeStamp.inMilliseconds; // 3. 总秒数 int seconds = timeStamp.inSeconds;
schedulerPhase→SchedulerPhase:当前调度阶段(idle、transientCallbacks、midFrameMicrotasks、persistentCallbacks、postFrameCallbacks)Flutter。一帧完整执行流程
idle → transientCallbacks → midFrameMicrotasks → persistentCallbacks → postFrameCallbacks → idle
Flutter SchedulerPhase 5 个阶段完整对照表(清晰版)
表格
阶段名称 英文原值 执行顺序 核心作用 对应开发者操作 注意事项 空闲 idle0 无帧任务,等待下一次 VSync 信号 无 正常待机状态 动画回调 transientCallbacks1 执行动画、Ticker 回调,更新动画值 AnimationController驱动不要在这里做耗时操作 帧中微任务 midFrameMicrotasks2 清空上一阶段产生的微任务(microtask) 开发者一般无感 系统内部清理 构建布局绘制 persistentCallbacks3 build → layout → paint 真正渲染 UI setState触发更新最核心阶段,禁止阻塞 帧后回调 postFrameCallbacks4 执行帧结束后的回调 addPostFrameCallback适合获取尺寸、执行收尾
Dartimport 'package:flutter/scheduler.dart'; final phase = WidgetsBinding.instance.schedulerPhase; print('当前调度阶段: $phase'); // 可判断阶段 if (phase == SchedulerPhase.idle) { print('空闲'); }
hasScheduledFrame→bool:是否已调度下一帧Flutter。
Dartfinal scheduled = WidgetsBinding.instance.hasScheduledFrame; print('是否已调度下一帧: $scheduled');
framesEnabled→bool:是否允许调度帧。
Dartfinal enabled = WidgetsBinding.instance.framesEnabled; print('帧是否启用: $enabled');2. 应用生命周期
lifecycleState→AppLifecycleState?:应用生命周期(resumed、inactive、paused、detached、hidden)Flutter。Flutter 所有 5 种生命周期说明
表格
状态 含义 resumed应用在前台,可交互 inactive应用在前台,但不活跃(来电、弹窗、切换应用过渡) paused应用在后台,不可见 hidden应用完全隐藏 detached应用正在销毁 / 退出
Dartfinal state = WidgetsBinding.instance.lifecycleState; print('当前应用状态: $state'); if (state == AppLifecycleState.resumed) { print('应用在前台'); }
Dartimport 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: const LifecyclePage(), ); } } class LifecyclePage extends StatefulWidget { const LifecyclePage({super.key}); @override State<LifecyclePage> createState() => _LifecyclePageState(); } class _LifecyclePageState extends State<LifecyclePage> with WidgetsBindingObserver { @override void initState() { super.initState(); // 注册生命周期监听 WidgetsBinding.instance.addObserver(this); // 你要的:立即获取当前状态 _getCurrentAppState(); } // 获取当前应用状态 void _getCurrentAppState() { final state = WidgetsBinding.instance.lifecycleState; print('当前应用状态: $state'); if (state == AppLifecycleState.resumed) { print('应用在前台(活跃)'); } else if (state == AppLifecycleState.inactive) { print('应用在前台(不活跃,如来电、弹窗)'); } else if (state == AppLifecycleState.paused) { print('应用在后台(不可见)'); } else if (state == AppLifecycleState.detached) { print('应用正在销毁'); } else if (state == AppLifecycleState.hidden) { print('应用完全隐藏'); } } // 监听生命周期变化(所有状态都会触发) @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); print('\n===== 应用状态变化 ====='); print('新状态: $state'); switch (state) { case AppLifecycleState.resumed: print('✅ 应用在前台(活跃、可交互)'); break; case AppLifecycleState.inactive: print('⚠️ 应用在前台(不活跃,如弹窗、来电)'); break; case AppLifecycleState.paused: print('⏸️ 应用在后台(不可见)'); break; case AppLifecycleState.hidden: print('👁️ 应用完全隐藏'); break; case AppLifecycleState.detached: print('❌ 应用正在销毁(退出)'); break; default: print('❓ 未知状态'); } } @override void dispose() { // 移除监听 WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Flutter 完整生命周期')), body: const Center(child: Text('查看控制台输出生命周期')), ); } }3. 渲染 / 视图
renderView→RenderView:根渲染对象。整个应用的「根渲染画布」pipelineOwner→PipelineOwner:渲染管线管理者。渲染流程的「总调度员」buildOwner→BuildOwner:Widget 构建管理者。Widget 树的「构建总指挥」
Dartfinal renderView = WidgetsBinding.instance.renderView; print('根渲染对象 size: ${renderView.size}'); final pipeline = WidgetsBinding.instance.pipelineOwner; print('渲染管线 owner: $pipeline'); final buildOwner = WidgetsBinding.instance.buildOwner; print('构建 owner: $buildOwner');
对象 核心职责 对应层级 小白能感知到的作用 renderView根渲染对象,承载所有 UI 渲染树(RenderObject 树) 屏幕尺寸、根布局 pipelineOwner驱动布局、绘制、合成 渲染管线 UI 刷新、动画流畅度 buildOwner驱动 Widget 树构建、更新 Widget 树 setState刷新 UI用户操作 → setState ↓ buildOwner(构建 Widget 结构) ↓ pipelineOwner(渲染到屏幕)
4. 手势 / 输入
gestureArena→GestureArenaManager:手势竞技场,处理手势(点击、滑动、长按)冲突,决定谁赢。
Dartimport 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('手势互斥:二选一')), body: const Center(child: GestureArenaDemo()), ), ); } } class GestureArenaDemo extends StatelessWidget { const GestureArenaDemo({super.key}); @override Widget build(BuildContext context) { return GestureDetector( // 点击 onTap: () { print("✅ 【点击获胜】滑动已被系统取消"); // 查看竞技场 final arena = WidgetsBinding.instance.gestureArena; arena.debugDescribe(); }, // 滑动 onPanStart: (_) { print("✅ 【滑动获胜】点击已被系统取消"); // 查看竞技场 final arena = WidgetsBinding.instance.gestureArena; arena.debugDescribe(); }, child: Container( width: 300, height: 300, color: Colors.blueAccent, alignment: Alignment.center, child: const Text( '点我:只打印点击\n滑我:只打印滑动\n\n永远二选一!', style: TextStyle(color: Colors.white, fontSize: 24), textAlign: TextAlign.center, ), ), ); } }
mouseTracker→MouseTracker:鼠标指针追踪。
Dartimport 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: MouseRegion( child: Container( width: 300, height: 300, color: Colors.blue, alignment: Alignment.center, child: const Text("鼠标放我上面", style: TextStyle(color: Colors.white, fontSize: 24)), ), // 鼠标进入 onEnter: (event) { print("✅ 鼠标进入"); // 你要的 mouseTracker final mouseTracker = WidgetsBinding.instance.mouseTracker; print("鼠标追踪器状态:${mouseTracker.debugDescription}"); }, // 鼠标移动 onHover: (event) { // 实时鼠标位置 print("鼠标位置:${event.position}"); }, ), ), ), ); } }
Dart// 获取当前有哪些组件正在监听鼠标 mouseTracker.debugListTypedConnections<MouseTrackerAnnotation>(); // 强制刷新鼠标状态 mouseTracker.updateDeviceCursor(0); // 调试鼠标事件丢失、不触发 print(mouseTracker.debugDescription);
keyboard→HardwareKeyboard:硬件键盘状态查询。
Dartfinal keyboard = WidgetsBinding.instance.keyboard; print('键盘是否按下 Shift: ${keyboard.isShiftPressed}');
focusManager→FocusManager:焦点树管理。
Dartfinal focus = WidgetsBinding.instance.focusManager; print('当前焦点节点: ${focus.primaryFocus}'); // 拿走当前焦点 → 键盘自动消失 WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();5. 其他全局
platformDispatcher→PlatformDispatcher:平台调度器(替代旧版window)Flutter。
platformBrightness:返回Brightness.light/Brightness.dark,用于适配深色模式locales:获取系统当前的语言区域设置,用于多语言适配、监听屏幕尺寸变化、字体缩放、平台消息分发
Dartfinal dispatcher = WidgetsBinding.instance.platformDispatcher; print('屏幕亮度: ${dispatcher.platformBrightness}'); // 获取系统亮/暗模式 print('语言: ${dispatcher.locales}'); // 获取系统语言列表
Dartimport 'package:flutter/material.dart'; import 'dart:ui' as ui; void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { // 屏幕信息 double? width; double? height; double? textScale; // 平台分发消息(真正用 platformDispatcher 接收) String platformMessage = "等待平台消息..."; @override void initState() { super.initState(); // ================================ // 🔥 1. 监听屏幕尺寸 + 字体缩放(官方正确用法) // ================================ final dispatcher = WidgetsBinding.instance.platformDispatcher; // 先取初始值 updateInfo(); // 监听变化:屏幕旋转、尺寸变化、字体缩放、像素密度变化 dispatcher.onMetricsChanged = () { setState(() { updateInfo(); }); }; // ================================ // 🔥 2. 真正用 platformDispatcher 接收平台消息 // 这是引擎底层消息,不是 channel! // ================================ dispatcher.onPlatformMessage = ( String name, Uint8List? data, ui.PlatformMessageResponseCallback? callback, ) { setState(() { platformMessage = "收到平台消息:$name"; }); // 必须回复,否则引擎会报错 callback?.call(null); }; } // 更新屏幕 + 字体信息 void updateInfo() { final view = WidgetsBinding.instance.platformDispatcher.views.first; final size = view.physicalSize / view.devicePixelRatio; width = size.width; height = size.height; textScale = WidgetsBinding.instance.platformDispatcher.textScaleFactor; } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text("platformDispatcher 纯官方演示")), body: Padding( padding: const EdgeInsets.all(20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("📱 屏幕宽度:${width?.toStringAsFixed(1)}", style: const TextStyle(fontSize: 16)), Text("📱 屏幕高度:${height?.toStringAsFixed(1)}", style: const TextStyle(fontSize: 16)), const SizedBox(height: 20), Text("🔤 系统字体缩放:${textScale?.toStringAsFixed(2)}", style: const TextStyle(fontSize: 16)), const SizedBox(height: 20), Text("📩 $platformMessage", style: const TextStyle(fontSize: 16, color: Colors.blue)), ], ), ), ), ); } }
firstFrameRasterized→bool:首帧是否已渲染完成。
Dartfinal firstFrameDone = WidgetsBinding.instance.firstFrameRasterized; print('首帧是否渲染完成: $firstFrameDone');
isRootWidgetAttached→bool:根 Widget 是否已挂载。
Dartfinal attached = WidgetsBinding.instance.isRootWidgetAttached; print('根 Widget 是否已挂载: $attached');
2、第三方库
2.1 easy_localization
pubspec.yaml
dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter flutter_web_plugins: sdk: flutter easy_localization: ^3.0.0assets/i18n下编写json文件
main.dart
WidgetsFlutterBinding.ensureInitialized()await EasyLocalization.ensureInitialized()runApp(EasyLocalization(...))
EasyLocalization参数你项目是这样设计的:
supportedLocales: 支持 7 种语言
path: 'assets/i18n'
fallbackLocale: Locale(LangConfig.defaultLang)
startLocale: Locale(LangConfig.defaultLang)
useFallbackTranslations: trueimport 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:get/get.dart' hide Trans;
import 'package:get_storage/get_storage.dart';
import 'config/lang_config.dart';
import 'controllers/app_controller.dart';
import 'controllers/user_controller.dart';
import 'services/api_service.dart';
import 'app.dart';
// 默认导入 url_strategy_stub.dart
// 如果当前编译目标支持 dart:html(也就是 Web),改为导入 url_strategy_web.dart
// 最后统一起别名 url_strategy
import 'url_strategy_stub.dart'
if (dart.library.html) 'url_strategy_web.dart'
as url_strategy;Future<void> main() async {
// Flutter 框架没初始化则立刻初始化,若已经初始化则返回现有对象
// binding: WidgetsBinding是flutter与引擎交互的总路口
final binding = WidgetsFlutterBinding.ensureInitialized();
// Web 使用哈希路由(localhost:63497/#/profile),与 Vue SPA 一致
url_strategy.setupHashUrlStrategy();
// 保留启动页 FlutterNativeSplash.preserve(widgetsBinding: binding); await EasyLocalization.ensureInitialized(); await GetStorage.init(); // 初始化 API 服务 ApiService().init(); // 全局锁定竖屏,全屏视频页单独允许横屏 SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); Get.put(AppController()); Get.put(UserController()); // 同步当前语言到 UserController final currentLocale = WidgetsBinding.instance.platformDispatcher.locale; final langCode = currentLocale.languageCode; final countryCode = currentLocale.countryCode; String localeCode = langCode; if (langCode == 'zh' && countryCode == 'TW') { localeCode = 'zh_TW'; } UserController.to.setLocale(localeCode); runApp( EasyLocalization( supportedLocales: const [ Locale('en'), Locale('zh'), Locale('ko'), Locale('ja'), Locale('th'), Locale('zh', 'TW'), Locale('vi'), ], path: 'assets/i18n', fallbackLocale: Locale(LangConfig.defaultLang), startLocale: Locale(LangConfig.defaultLang), useFallbackTranslations: true, child: const SdramaApp(), ), ); // 等到 Flutter 首帧完成后再移除启动页,避免首帧布局未完成时收到点击导致 hitTest 断言。 WidgetsBinding.instance.addPostFrameCallback((_) { FlutterNativeSplash.remove(); });}
app.dart
把
easy_localization的上下文能力"桥接"到MaterialApp
import 'package:easy_localization/easy_localization.dart'; class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { context.locale; // 初始化 ToastHelper ToastHelper.init(context); return Obx( () => MaterialApp( title: 'app.title'.tr(namedArgs: app_brand.AppConfig.brandNamedArgs), debugShowCheckedModeBanner: false, locale: context.locale, supportedLocales: context.supportedLocales, localizationsDelegates: context.localizationDelegates, ), ); } }其它页面使用翻译和上面类似
切换语言
import 'package:easy_localization/easy_localization.dart'; await context.setLocale(Locale('zh', 'TW');
3、内置包
3.1 services
import 'package:flutter/services.dart';作用:专门负责和原生系统交互的核心服务包。
- 调用键盘、输入法
- 监听、控制屏幕旋转
- 调用原生通道(MethodChannel)
- 复制、粘贴、剪切板
- 控制状态栏、亮度、震动
- 读取平台信息(iOS/Android)
- 处理原生事件
3.1.1 键盘控制
隐藏键盘
SystemChannels.textInput.invokeMethod('TextInput.hide');或者
import 'package:flutter/material.dart'; // 包含它 // 或 import 'package:flutter/widgets.dart'; FocusScope.of(context).unfocus();打开键盘
// 先获取焦点节点 FocusNode focusNode = FocusNode(); // 让输入框获得焦点 → 键盘自动弹出 FocusScope.of(context).requestFocus(focusNode);完整案例(实际textField聚焦后会自动打开键盘)
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: const AutoKeyboardPage(), ); } } class AutoKeyboardPage extends StatefulWidget { const AutoKeyboardPage({super.key}); @override State<AutoKeyboardPage> createState() => _AutoKeyboardPageState(); } class _AutoKeyboardPageState extends State<AutoKeyboardPage> { // 1. 创建焦点节点 late FocusNode _focusNode; @override void initState() { super.initState(); _focusNode = FocusNode(); // 2. 页面初始化后自动获取焦点 → 自动弹键盘 WidgetsBinding.instance.addPostFrameCallback((_) { _focusNode.requestFocus(); }); } @override void dispose() { // 记得释放 _focusNode.dispose(); super.dispose(); } // 关闭键盘 void _hideKeyboard() { FocusScope.of(context).unfocus(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("自动打开键盘")), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ TextField( focusNode: _focusNode, // 绑定焦点 decoration: const InputDecoration( labelText: "输入框", border: OutlineInputBorder(), ), ), const SizedBox(height: 20), ElevatedButton( onPressed: _hideKeyboard, child: const Text("关闭键盘"), ), ], ), ), ); } }
3.1.2 屏幕方向
// 强制竖屏 SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { // 强制竖屏:必须在 runApp 之前调用 WidgetsFlutterBinding.ensureInitialized(); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, // 仅允许正竖屏 // DeviceOrientation.landscapeLeft, // 左横屏 // DeviceOrientation.landscapeRight, // 右横屏 ]); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '强制竖屏 Demo', theme: ThemeData(primarySwatch: Colors.blue), home: const HomePage(), ); } } class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("强制竖屏")), body: const Center( child: Text( "整个 App 已强制竖屏\n无论怎么旋转都不会横屏", textAlign: TextAlign.center, style: TextStyle(fontSize: 20), ), ), ); } }android原生
android/app/src/main/AndroidManifest.xml
android:screenOrientation="portrait" android:screenOrientation="landscape"ios原生
ios/Runner/Info.plist
<key>UISupportedInterfaceOrientations</key> <array> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array> <key>UISupportedInterfaceOrientations</key> <array> <string>UIInterfaceOrientationPortrait</string> </array>3.1.3 状态栏(顶部电池、时间栏)
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); // 隐藏状态栏和导航栏,沉浸式模式 SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '隐藏状态栏 Demo', debugShowCheckedModeBanner: false, home: Scaffold( body: Center( child: Text( '状态栏已隐藏\n(滑动屏幕边缘可呼出)', style: TextStyle(fontSize: 22), textAlign: TextAlign.center, ), ), ), ); } }只隐藏状态栏,保留底部导航栏
SystemChrome.setEnabledSystemUIMode( SystemUiMode.manual, overlays: [SystemUiOverlay.bottom], // 只显示底部导航栏 ); // 1. 只隐藏顶部状态栏(最常用) overlays: [SystemUiOverlay.bottom] // 2. 只隐藏底部导航栏 overlays: [SystemUiOverlay.top] // 3. 全部显示(恢复正常) overlays: SystemUiOverlay.values底部导航栏 (已被"手势导航"替代)
Android:屏幕底部有 系统导航栏(返回键、主页键、多任务键) iOS:底部只有一条小横条,不算系统导航栏,也不能用 Flutter 隐藏
SystemUiMode一共有 4 个常用枚举值
枚举值 意思(大白话) 效果 immersive 普通沉浸式 滑动呼出,不自动隐藏 immersiveSticky 粘性沉浸式 滑动呼出,几秒后自动隐藏(最常用) edgeToEdge 边到边正常模式 显示状态栏 + 导航栏(默认) manual 手动自定义 自己决定显示 / 隐藏哪个
3.1.4 剪切板
复制内容
// 复制文字 await Clipboard.setData(ClipboardData(text: '复制内容')); import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // 必须导入 void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text("复制文字示例")), body: const Center( child: CopyWidget(), // 复制功能组件 ), ), ); } } // 复制功能组件 class CopyWidget extends StatelessWidget { const CopyWidget({super.key}); // 复制方法 Future<void> copyText() async { // 复制内容 await Clipboard.setData(ClipboardData(text: '我是被复制的内容')); // 复制成功后提示 // 这里用 Flutter 自带提示,也可以用 Toast print("复制成功"); } @override Widget build(BuildContext context) { return ElevatedButton( onPressed: copyText, child: const Text("点击复制文字"), ); } }
3.1.5 原生通道
原生通道 MethodChannel(Flutter ↔ 原生通信)
const channel = MethodChannel('my_channel');
调用系统相机、相册
获取设备唯一标识
调用第三方 SDK(微信、支付宝、推送)
读写本地文件、蓝牙、传感器
启动原生页面
import 'package:flutter/services.dart';
// 1. 创建通道(名字必须唯一)
const MethodChannel _channel = MethodChannel('my_channel');// 2. 调用原生方法
Future<void> callNativeMethod() async {
try {
// 给原生发送消息,可接收返回值
final String result = await _channel.invokeMethod(
'getDeviceInfo', // 方法名
{'extra': '123'}, // 传递参数
);
print('原生返回:result'); } on PlatformException catch (e) { print('错误:{e.message}');
}
}安卓端写了一个方法
override fun onMethodCall(call: MethodCall, result: Result) { if (call.method == "getDeviceInfo") { // 这里必须一模一样! // 安卓原生逻辑 } }
3.1.6 震动
Flutter 自带的 触觉反馈 / 震动 功能 点击反馈、提示震动
安卓:短震动
iOS:轻触反馈(不吵人、很柔和)
import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; // 必须导入void main() {
runApp(const MyApp());
}class MyApp extends StatelessWidget {
const MyApp({super.key});
@override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text("震动示例")), body: Center( child: ElevatedButton( onPressed: () { // ✅ 触发震动 HapticFeedback.vibrate(); }, child: const Text("点我震动"), ), ), ), ); }}
// 轻震动(最常用)
HapticFeedback.lightImpact();// 中等震动
HapticFeedback.mediumImpact();// 强震动
HapticFeedback.heavyImpact();// 选择器震动(很轻)
HapticFeedback.selectionClick();
