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. 调度 / 帧相关

  • endOfFrameFuture<void>:当前帧结束后完成的 Future,常用于帧后执行代码Flutter。
// 等待当前帧结束
await WidgetsBinding.instance.endOfFrame;
print('当前帧已结束');
  • currentFrameTimeStampDuration:当前帧时间戳Flutter。
final 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;
  • schedulerPhaseSchedulerPhase:当前调度阶段(idle、transientCallbacks、midFrameMicrotasks、persistentCallbacks、postFrameCallbacks)Flutter。

一帧完整执行流程

idle → transientCallbacks → midFrameMicrotasks → persistentCallbacks → postFrameCallbacks → idle  

Flutter SchedulerPhase 5 个阶段完整对照表(清晰版)

表格

阶段名称 英文原值 执行顺序 核心作用 对应开发者操作 注意事项
空闲 idle 0 无帧任务,等待下一次 VSync 信号 正常待机状态
动画回调 transientCallbacks 1 执行动画、Ticker 回调,更新动画值 AnimationController 驱动 不要在这里做耗时操作
帧中微任务 midFrameMicrotasks 2 清空上一阶段产生的微任务(microtask) 开发者一般无感 系统内部清理
构建布局绘制 persistentCallbacks 3 build → layout → paint 真正渲染 UI setState 触发更新 最核心阶段,禁止阻塞
帧后回调 postFrameCallbacks 4 执行帧结束后的回调 addPostFrameCallback 适合获取尺寸、执行收尾
import 'package:flutter/scheduler.dart';  
final phase = WidgetsBinding.instance.schedulerPhase;
print('当前调度阶段: $phase');

// 可判断阶段
if (phase == SchedulerPhase.idle) {
  print('空闲');
}
  • hasScheduledFramebool:是否已调度下一帧Flutter。
final scheduled = WidgetsBinding.instance.hasScheduledFrame;
print('是否已调度下一帧: $scheduled');
  • framesEnabledbool:是否允许调度帧。  
final enabled = WidgetsBinding.instance.framesEnabled;
print('帧是否启用: $enabled');

2. 应用生命周期

  • lifecycleStateAppLifecycleState?:应用生命周期(resumed、inactive、paused、detached、hidden)Flutter。  

Flutter 所有 5 种生命周期说明

表格

状态 含义
resumed 应用在前台,可交互
inactive 应用在前台,但不活跃(来电、弹窗、切换应用过渡)
paused 应用在后台,不可见
hidden 应用完全隐藏
detached 应用正在销毁 / 退出
final state = WidgetsBinding.instance.lifecycleState;
print('当前应用状态: $state');

if (state == AppLifecycleState.resumed) {
  print('应用在前台');
}
import '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. 渲染 / 视图

  • renderViewRenderView:根渲染对象。整个应用的「根渲染画布」
  • pipelineOwnerPipelineOwner:渲染管线管理者。渲染流程的「总调度员」
  • buildOwnerBuildOwner:Widget 构建管理者。Widget 树的「构建总指挥」
final 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. 手势 / 输入

  • gestureArenaGestureArenaManager:手势竞技场,处理手势(点击、滑动、长按)冲突,决定谁赢。
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: 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,
        ),
      ),
    );
  }
}
  • mouseTrackerMouseTracker:鼠标指针追踪。
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: 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}");
            },
          ),
        ),
      ),
    );
  }
}
// 获取当前有哪些组件正在监听鼠标
mouseTracker.debugListTypedConnections<MouseTrackerAnnotation>();  
// 强制刷新鼠标状态  
mouseTracker.updateDeviceCursor(0);  
// 调试鼠标事件丢失、不触发 
print(mouseTracker.debugDescription);
  • keyboardHardwareKeyboard:硬件键盘状态查询。  
final keyboard = WidgetsBinding.instance.keyboard;
print('键盘是否按下 Shift: ${keyboard.isShiftPressed}');
  • focusManagerFocusManager:焦点树管理。
final focus = WidgetsBinding.instance.focusManager;
print('当前焦点节点: ${focus.primaryFocus}');
// 拿走当前焦点 → 键盘自动消失
WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();

5. 其他全局

  • platformDispatcherPlatformDispatcher:平台调度器(替代旧版 window)Flutter。
  • platformBrightness:返回 Brightness.light/Brightness.dark,用于适配深色模式
  • locales:获取系统当前的语言区域设置,用于多语言适配、监听屏幕尺寸变化、字体缩放、平台消息分发  
final dispatcher = WidgetsBinding.instance.platformDispatcher;
print('屏幕亮度: ${dispatcher.platformBrightness}'); // 获取系统亮/暗模式
print('语言: ${dispatcher.locales}'); // 获取系统语言列表
import '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)),
            ],
          ),
        ),
      ),
    );
  }
}
  • firstFrameRasterizedbool:首帧是否已渲染完成。
final firstFrameDone = WidgetsBinding.instance.firstFrameRasterized;
print('首帧是否渲染完成: $firstFrameDone');
  • isRootWidgetAttachedbool:根 Widget 是否已挂载。  
final attached = WidgetsBinding.instance.isRootWidgetAttached;
print('根 Widget 是否已挂载: $attached');

1.4 条件导入  

import 'hash_routes_stub.dart'

if (dart.library.html) 'hash_routes_web.dart'

as impl;
  • 默认导入 hash_routes_stub.dart(stub = 占位/空实现)
  • 如果当前环境有 dart.library.html(即 Web 环境),就改为导入 hash_routes_web.dart
  • 并把导入结果起别名 impl,后面可以统一写 impl.xxx() 调用,不关心具体平台实现

1.6  初始化列表

初始化列表就是 Dart 构造函数里(只有构造函数才有),函数体执行前先做的一段“初始化步骤”。

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

  @override
  State<AppShell> createState() => _AppShellState();
}
const AppShell({super.key});

等价于  

const AppShell({Key? key}) : super(key: key);

1.7 禁止外部实例化  

class AppRouteNames {
  AppRouteNames._(); // 不让创建实例
}

1.8 状态管理

1.8.1 ValueNotifier  

类似于vue里面的ref,可跨Widget共享  

1. 定义 ValueNotifier 变量  

final ValueNotifier<int> _counter = ValueNotifier<int>(0);

2. 监听并刷新 UI(ValueListenableBuilder)  

ValueListenableBuilder(
  valueListenable: 你的ValueNotifier,
  builder: (context, 最新值, child) {
    // 返回需要刷新的 UI
    return Text("当前值:$最新值");
  },
)

监听值变化用  

// 监听 _counter 变化
  _counter.addListener(() {
    print("数值变了!新值:${_counter.value}");
    
    // 你可以在这里写任何逻辑
    if (_counter.value >= 10) {
      print("达到10次啦!");
    }
  });

取消监听  

 _counter.removeListener(() => {});

3. 修改值(触发刷新)  

_counter.value++;

4. 销毁(防止内存泄漏)

@override
void dispose() {
  _counter.dispose(); // 必须销毁!
  super.dispose();
}
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: Scaffold(
        appBar: AppBar(title: const Text("ValueNotifier 基础用法")),
        body: const ValueNotifierDemo(),
      ),
    );
  }
}

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

  @override
  State<ValueNotifierDemo> createState() => _ValueNotifierDemoState();
}

class _ValueNotifierDemoState extends State<ValueNotifierDemo> {
  // 1. 定义 ValueNotifier(初始值 0)
  final ValueNotifier<int> _counter = ValueNotifier<int>(0);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          // 2. 用 ValueListenableBuilder 监听变化,自动刷新 UI
          ValueListenableBuilder<int>(
            valueListenable: _counter, // 绑定监听对象
            builder: (context, value, child) {
              // value = _counter.value(最新值)
              return Text(
                "点击次数:$value",
                style: const TextStyle(fontSize: 24),
              );
            },
          ),
          const SizedBox(height: 20),
          // 3. 点击按钮修改值,触发 UI 刷新
          ElevatedButton(
            onPressed: () {
              _counter.value++; // 直接修改 value 即可
            },
            child: const Text("点击加 1"),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    // 4. 页面销毁时释放资源
    _counter.dispose();
    super.dispose();
  }
}

传给其它组件  

1.8.2  state  

late int _currentIndex;  
setState(() {
   _currentIndex = i;
});

2、第三方库  

2.1 easy_localization

pubspec.yaml  

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  flutter_web_plugins:
    sdk: flutter
  easy_localization: ^3.0.0

assets/i18n下编写json文件  

main.dart  

  1. WidgetsFlutterBinding.ensureInitialized()
  2. await EasyLocalization.ensureInitialized()
  3. runApp(EasyLocalization(...))

EasyLocalization 参数你项目是这样设计的:

  • supportedLocales: 支持 7 种语言
  • path: 'assets/i18n'
  • fallbackLocale: Locale(LangConfig.defaultLang)
  • startLocale: Locale(LangConfig.defaultLang)
  • useFallbackTranslations: true
import '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();

4、页面生命周期  

表格

生命周期方法 执行时机 核心用途 执行次数 关键注意事项
createState() Widget 插入渲染树时,第一个执行 创建对应 State 实例,绑定 Widget 1 次(仅创建时执行 1 次) 必须重写,返回 State 对象,无业务逻辑
initState() State 实例创建后,build() 之前执行 初始化数据、订阅事件、发起网络请求、创建控制器 1 次(页面创建仅执行 1 次) 可通过 context 访问,但不能做同步依赖 context 的操作(如 Navigator);必须调用 super.initState()
didChangeDependencies() 1. initState() 后立即执行2. 依赖的 InheritedWidget 变化时触发 处理依赖数据变化(如主题、全局状态更新) 多次(首次 + 依赖变化时) 一般业务场景很少主动使用,多用于全局状态监听
build() 1. didChangeDependencies() 后首次执行2. 调用 setState() 时3. 页面从后台切回时4. 父 Widget 重建时 构建 UI 界面,渲染 Widget 树 多次(页面存活期内多次触发) 绝对禁止写耗时操作 / 网络请求,仅做 UI 渲染
didUpdateWidget() 父 Widget 重建,当前 Widget 配置更新时触发 响应旧 Widget 到新 Widget 的配置变化 多次(配置变化时) 必须调用 super.didUpdateWidget(oldWidget),用于同步 Widget 状态
deactivate() 页面被移出渲染树时(如 push 新页面、切后台) 临时保存页面状态,准备销毁 / 恢复 多次(页面暂停 / 恢复时) dispose() 的前置步骤,页面恢复会走 activate()
activate() 页面重新插入渲染树时(如从新页面返回、切回前台) 恢复页面状态、刷新数据 多次(页面恢复时) 页面从后台切回不会重新走 initState(),仅触发 activate() + build()
dispose() 页面彻底销毁、从渲染树永久移除时 释放资源:销毁控制器、取消订阅、关闭流、移除监听 1 次(页面销毁仅执行 1 次) 必须调用 super.dispose()最后执行,避免内存泄漏

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐