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

Flutter横屏切换时如何限制Widget树重建并解决页面异常渲染问题

问题:横屏切换后Flutter页面异常渲染(Screen1覆盖Screen4)

我有Screen1、Screen2、Screen3、Screen4四个页面,从Screen3跳转进入Screen4后设置横屏播放YouTube视频,但一段时间后Screen1会在Screen4上渲染,且并未调用Screen1的相关代码,推测是横屏切换导致Widget树重建引发的问题。

以下是Screen4的原代码:

class _FullScreenVideoScreen extends State<FullScreenVideoScreen> {
  final Key myKey = UniqueKey();
  late BuildContext _parentContext;

  @override
  void initState() {
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.landscapeRight,
    ]);

    super.initState();
  }

  @override
  void dispose() {
    SystemChrome.setPreferredOrientations(DeviceOrientation.values);
    super.dispose();
  }

  // @override
  // void didChangeDependencies() {
  //   super.didChangeDependencies();
  //   print("dididididididiidididiididid");
  //   // Trigger a rebuild when the orientation changes
  //   WidgetsBinding.instance?.addPostFrameCallback((_) {
  //     SystemChrome.setPreferredOrientations([
  //       DeviceOrientation.landscapeLeft,
  //       DeviceOrientation.landscapeRight,
  //     ]);
  //   });
  // }


  @override
  Widget build(BuildContext context) {
    _parentContext = context;

          return Scaffold(
            body: Center(
              child: YoutubePlayer(
                  controller: YoutubePlayerController(
                    initialVideoId: widget.videoId,
                    flags: YoutubePlayerFlags(
                      mute: false,
                      autoPlay: true,
                      disableDragSeek: false,
                      loop: false,
                      isLive: false,
                      forceHD: false,
                      enableCaption: true,
                      showLiveFullscreenButton : false,
                    ),
                  ),
                  showVideoProgressIndicator: true,
                  progressIndicatorColor: Colors.blueAccent,
                ),
            ),
          );
  }
}

解决方案

1. 稳定页面Key,避免不必要重建

原代码用UniqueKey(),每次Widget重建都会生成新Key,导致页面状态被重置。换成GlobalKey确保页面重建时状态能保留。

2. 把YoutubePlayerController移到initState初始化

在build方法里直接创建控制器会导致每次build都重新初始化播放器,浪费资源还会引发状态异常。应该在initState里初始化,dispose时销毁。

3. 优化横屏锁定逻辑

确保横屏设置在页面渲染完成后生效,避免系统自动切换方向导致的Widget树异常重建。

修改后的完整代码

class _FullScreenVideoScreen extends State<FullScreenVideoScreen> {
  // 使用GlobalKey保持页面状态稳定
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  late YoutubePlayerController _youtubeController;

  @override
  void initState() {
    super.initState();
    // 初始化YouTube控制器
    _youtubeController = YoutubePlayerController(
      initialVideoId: widget.videoId,
      flags: const YoutubePlayerFlags(
        mute: false,
        autoPlay: true,
        disableDragSeek: false,
        loop: false,
        isLive: false,
        forceHD: false,
        enableCaption: true,
        showLiveFullscreenButton: false,
      ),
    );
    // 延迟设置横屏,确保页面已初始化完成
    WidgetsBinding.instance.addPostFrameCallback((_) {
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.landscapeRight,
      ]);
    });
  }

  @override
  void dispose() {
    // 销毁控制器,释放资源
    _youtubeController.dispose();
    // 恢复默认屏幕方向
    SystemChrome.setPreferredOrientations(DeviceOrientation.values);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: Center(
        child: YoutubePlayer(
          controller: _youtubeController,
          showVideoProgressIndicator: true,
          progressIndicatorColor: Colors.blueAccent,
        ),
      ),
    );
  }
}

额外注意事项

  • 跳转Screen4时确保使用Navigator.push标准方式,避免页面栈混乱引发的渲染问题。
  • 检查全局状态管理(如Provider、GetX等)是否存在状态泄漏,确保各页面状态相互独立。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:53:10