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

Flutter中通过原生代码判断设备自动旋转状态及弹窗闪烁问题解决

Flutter中判断Android自动旋转状态并解决弹窗闪烁问题

一、现有代码的问题

  • 频繁重建导致闪烁:你用OrientationBuilder监听MediaQuery的方向变化,当自动旋转开启且设备倾斜到临界角度时,MediaQuery的Orientation会在竖屏和横屏之间快速切换,导致OrientationBuilder频繁重建子widget,一会儿显示NativeDeviceOrientedWidget(弹窗),一会儿显示landscapeMode,造成弹窗闪烁。
  • useSensor逻辑冗余且不合理:useSensor的条件MediaQuery.of(context).orientation == Orientation.portrait && MediaQuery.of(context).orientation != Orientation.landscape完全冗余,等价于前者;更关键的是,这个条件会随MediaQuery方向变化动态切换,导致NativeDeviceOrientedWidget的传感器监听状态频繁改变,加剧重建问题。
  • 逻辑层级混乱:OrientationBuilder的判断和NativeDeviceOrientedWidget的传感器监听重叠,导致UI状态冲突。

二、解决方案:结合原生判断自动旋转状态

1. Android原生实现:判断自动旋转开关状态

在Android项目的MainActivity.kt中添加MethodChannel,提供获取自动旋转状态的方法:

import android.content.Context
import android.provider.Settings
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example/rotation_settings"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "isAutoRotationEnabled") {
                val isEnabled = isAutoRotationEnabled(this)
                result.success(isEnabled)
            } else {
                result.notImplemented()
            }
        }
    }

    private fun isAutoRotationEnabled(context: Context): Boolean {
        return try {
            Settings.System.getInt(context.contentResolver, Settings.System.ACCELEROMETER_ROTATION) == 1
        } catch (e: Settings.SettingNotFoundException) {
            false
        }
    }
}

2. Flutter端调用原生方法并修正UI逻辑

移除OrientationBuilder,直接通过原生获取的自动旋转状态控制UI:

import 'package:flutter/services.dart';
import 'package:native_device_orientation/native_device_orientation.dart';

class YourPage extends StatefulWidget {
  @override
  State<YourPage> createState() => _YourPageState();
}

class _YourPageState extends State<YourPage> {
  static const MethodChannel _channel = MethodChannel('com.example/rotation_settings');
  bool _isAutoRotationEnabled = true;

  @override
  void initState() {
    super.initState();
    _getAutoRotationState();
  }

  Future<void> _getAutoRotationState() async {
    try {
      final bool result = await _channel.invokeMethod('isAutoRotationEnabled');
      setState(() {
        _isAutoRotationEnabled = result;
      });
    } on PlatformException catch (e) {
      print("Failed to get rotation state: ${e.message}");
    }
  }

  @override
  Widget build(BuildContext context) {
    return NativeDeviceOrientedWidget(
      // 仅当自动旋转关闭时,用传感器检测物理方向
      useSensor: !_isAutoRotationEnabled,
      fallback: (context) => portraitMode(context),
      landscape: (context) => _isAutoRotationEnabled ? landscapeMode(context) : const RotationDialog(),
      landscapeLeft: (context) => _isAutoRotationEnabled ? landscapeMode(context) : const RotationDialog(),
      landscapeRight: (context) => _isAutoRotationEnabled ? landscapeMode(context) : const RotationDialog(),
      portrait: (context) => portraitMode(context),
      portraitUp: (context) => portraitMode(context),
      portraitDown: (context) => portraitMode(context),
    );
  }

  Widget portraitMode(BuildContext context) {
    // 你的竖屏UI实现
    return Scaffold(body: Center(child: Text("竖屏模式")));
  }

  Widget landscapeMode(BuildContext context) {
    // 你的横屏拍摄UI实现
    return Scaffold(body: Center(child: Text("横屏拍摄模式")));
  }
}

3. 关键逻辑说明

  • 原生判断逻辑:通过Settings.System.ACCELEROMETER_ROTATION值判断,1表示自动旋转开启,0表示关闭。
  • UI控制逻辑:
    • 自动旋转开启时:设备横屏会触发系统自动切换Flutter方向,直接显示横屏拍摄UI;
    • 自动旋转关闭时:通过传感器检测设备物理方向,若为横屏则显示弹窗提示开启自动旋转。

三、额外优化:实时监听自动旋转状态变化

如果需要实时感知用户切换自动旋转开关的操作,可以在Android原生中注册广播通知Flutter:

// 在MainActivity中添加广播监听
private val rotationChangeReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_CONFIGURATION_CHANGED) {
            val isEnabled = isAutoRotationEnabled(this@MainActivity)
            flutterEngine?.let {
                MethodChannel(it.dartExecutor.binaryMessenger, CHANNEL)
                    .invokeMethod("onRotationStateChanged", isEnabled)
            }
        }
    }
}

override fun onResume() {
    super.onResume()
    registerReceiver(rotationChangeReceiver, IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED))
}

override fun onPause() {
    super.onPause()
    unregisterReceiver(rotationChangeReceiver)
}

Flutter端接收状态变化:

@override
void initState() {
  super.initState();
  _getAutoRotationState();
  _channel.setMethodCallHandler((call) {
    if (call.method == "onRotationStateChanged") {
      setState(() {
        _isAutoRotationEnabled = call.arguments as bool;
      });
      return Future.value(null);
    }
    return Future.error("Method not implemented");
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 21:40:40