You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在运行时根据应用主题切换启动屏?

iOS端实现跟随应用内主题切换启动屏(Flutter适配)

因为启动屏是iOS系统在Flutter引擎加载前就渲染的,所以无法直接通过Flutter控制,必须借助iOS原生代码实现,核心思路是用临时视图模拟启动屏,根据应用内预存的主题设置动态加载对应样式,待Flutter加载完成后再切换到Flutter页面。

具体实现步骤

1. 准备两套启动屏资源

在Xcode中创建两个Launch Screen Storyboard:

  • LaunchScreenLight.storyboard:配置浅色主题的启动屏(白色背景等)
  • LaunchScreenDark.storyboard:配置深色主题的启动屏(黑色背景等)
    确保两个storyboard的布局结构完全一致,仅颜色等主题相关元素不同。

2. 同步Flutter主题设置到iOS原生存储

当用户在Flutter内切换主题时,通过MethodChannel将主题值同步到iOS的UserDefaults中:

Flutter端代码

import 'package:flutter/services.dart';

class ThemeSync {
  static const _channel = MethodChannel('app/theme_sync');

  /// 保存当前选中的主题到原生存储
  static Future<void> saveSelectedTheme(String theme) async {
    await _channel.invokeMethod('saveTheme', {'theme': theme});
  }
}

iOS端代码(AppDelegate.swift)

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    // 初始化MethodChannel处理主题同步
    let themeChannel = FlutterMethodChannel(name: "app/theme_sync", binaryMessenger: window?.rootViewController as! FlutterViewController)
    themeChannel.setMethodCallHandler { (call, result) in
      guard call.method == "saveTheme", 
            let args = call.arguments as? [String: String],
            let theme = args["theme"] else {
        result(FlutterError(code: "INVALID_ARGS", message: "参数无效", details: nil))
        return
      }
      UserDefaults.standard.set(theme, forKey: "selected_app_theme")
      result(nil)
    }
    
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

3. 动态加载对应主题的启动屏

修改AppDelegate.swift,在Flutter引擎启动前先加载对应主题的临时启动屏,待Flutter就绪后再切换:

override func application(
  _ application: UIApplication,
  didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
  // 读取预存的主题,默认浅色
  let savedTheme = UserDefaults.standard.string(forKey: "selected_app_theme") ?? "light"
  let launchStoryboardName = savedTheme == "dark" ? "LaunchScreenDark" : "LaunchScreenLight"
  
  // 加载对应主题的启动屏视图控制器
  let launchStoryboard = UIStoryboard(name: launchStoryboardName, bundle: nil)
  let launchVC = launchStoryboard.instantiateInitialViewController()!
  
  // 设置临时启动屏为当前根控制器
  window?.rootViewController = launchVC
  window?.makeKeyAndVisible()
  
  // 初始化Flutter引擎
  let flutterEngine = FlutterEngine(name: "AppFlutterEngine")
  flutterEngine.run()
  GeneratedPluginRegistrant.register(with: flutterEngine)
  
  // 延迟切换到Flutter页面(确保启动屏显示足够时间,避免闪屏)
  DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
    let flutterVC = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
    self?.window?.rootViewController = flutterVC
  }
  
  // 主题同步的MethodChannel逻辑(保留之前的代码)
  let themeChannel = FlutterMethodChannel(name: "app/theme_sync", binaryMessenger: flutterEngine.binaryMessenger)
  themeChannel.setMethodCallHandler { (call, result) in
    guard call.method == "saveTheme", 
          let args = call.arguments as? [String: String],
          let theme = args["theme"] else {
      result(FlutterError(code: "INVALID_ARGS", message: "参数无效", details: nil))
      return
    }
    UserDefaults.standard.set(theme, forKey: "selected_app_theme")
    result(nil)
  }
  
  return true
}

注意事项

  • 两套启动屏的布局必须完全一致,否则切换到Flutter页面时会出现视觉跳变。
  • 首次启动时UserDefaults无主题记录,默认使用浅色主题,可根据需求修改默认值。
  • 延迟切换的时间可根据实际情况调整,确保Flutter引擎完全加载,避免闪屏。

内容的提问来源于stack exchange,提问作者iSuu273

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:06:37