Flutter 特定页面切换屏幕方向/iOS强制横屏/SystemChrome.setPreferredOrientations不起作用 看这里!

栏目: IOS · 发布时间: 5年前

内容简介:我此刻的Flutter版本:Flutter 1.2.0 • channel dev •Framework • revision 06b979c4d5 (3 weeks ago) • 2019-01-25 14:27:35 -0500

我此刻的Flutter版本:

Flutter 1.2.0 • channel dev • github.com/flutter/flu…

Framework • revision 06b979c4d5 (3 weeks ago) • 2019-01-25 14:27:35 -0500

Engine • revision 36acd02c94

Tools • Dart 2.1.1 (build 2.1.1-dev.3.2 f4afaee422)

特定页面旋转屏幕很简单:

SystemChrome.setPreferredOrientations([
  ...
]);
复制代码

数组中是您要支持的屏幕方向.

如果想在特定页面固定横屏, 您可以这样写:

@override
void initState() {
  super.initState();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.landscapeRight,
    DeviceOrientation.landscapeRight,
  ]);
}
复制代码

并且在 dispose 时更改回竖屏

@override
void dispose() {
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
  ]);
  super.dispose();
}
复制代码

但是!!! 不要走开 本文重点在下面

在Android设备上, 调用此方法可以强制改变屏幕方向. 但在iOS上却不是这样

对于iOS, 这个方法表示设置应用支持的屏幕方向, 只有在物理方向改变时才会改变屏幕方向

现在看起来, 这应该是一个Flutter的一个Bug. 有待官方解决

您可关注 issue #13238 追踪Flutter官方的最新更新

强制改变布局方向

既然 Flutter 提供的方法不能强制改变屏幕方向, 那么我们可以通过插件的形式, 桥接到iOS原生代码中, 通过原生方式改变屏幕方向.

设置应用支持的布局方向

通过Xcode打开Flutter项目中的iOS工程, 根据下图找到 Device Orientation 这一项 勾选需要支持的布局方向, 通过这一步, 默认你现在的应用已经会根据设备的方向转变布局了

Flutter 特定页面切换屏幕方向/iOS强制横屏/SystemChrome.setPreferredOrientations不起作用 看这里!

编写插件

展开 Runner / Runner 文件夹 右键->New File 添加两个新的OC文件 FlutterIOSDevicePlugin.mFlutterIOSDevicePlugin.h (叫什么都没关系) 创建方式看下图:

Flutter 特定页面切换屏幕方向/iOS强制横屏/SystemChrome.setPreferredOrientations不起作用 看这里!

FlutterIOSDevicePlugin.h 的内容:

#import <Flutter/Flutter.h>

@interface FlutterIOSDevicePlugin : NSObject<FlutterPlugin>
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar flutterViewController:(FlutterViewController*) controller;
- (instancetype)newInstance:(NSObject<FlutterPluginRegistrar>*)registrar flutterViewController:(FlutterViewController*) controller;
@end
复制代码

FlutterIOSDevicePlugin.m 的内容:

#import "FlutterIOSDevicePlugin.h"

@interface FlutterIOSDevicePlugin () {
    NSObject<FlutterPluginRegistrar> *_registrar;
    FlutterViewController *_controller;
}
@end

static NSString* const CHANNEL_NAME = @"flutter_ios_device";
static NSString* const METHOD_CHANGE_ORIENTATION = @"change_screen_orientation";
static NSString* const ORIENTATION_PORTRAIT_UP = @"portraitUp";
static NSString* const ORIENTATION_PORTRAIT_DOWN = @"portraitDown";
static NSString* const ORIENTATION_LANDSCAPE_LEFT = @"landscapeLeft";
static NSString* const ORIENTATION_LANDSCAPE_RIGHT = @"landscapeRight";

@implementation FlutterIOSDevicePlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    FlutterMethodChannel* channel = [FlutterMethodChannel
                                     methodChannelWithName:CHANNEL_NAME
                                     binaryMessenger:[registrar messenger]];
    FlutterIOSDevicePlugin* instance = [[FlutterIOSDevicePlugin alloc] newInstance:registrar flutterViewController:nil];
    [registrar addMethodCallDelegate:instance channel:channel];
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar flutterViewController:(FlutterViewController*) controller {
    FlutterMethodChannel* channel = [FlutterMethodChannel
                                     methodChannelWithName:CHANNEL_NAME
                                     binaryMessenger:[registrar messenger]];
    FlutterIOSDevicePlugin* instance = [[FlutterIOSDevicePlugin alloc] newInstance:registrar flutterViewController:controller];
    [registrar addMethodCallDelegate:instance channel:channel];
}

- (instancetype)newInstance:(NSObject<FlutterPluginRegistrar>*)registrar flutterViewController:(FlutterViewController*) controller{
    _registrar = registrar;
    _controller = controller;
    return self;
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
    if ([METHOD_CHANGE_ORIENTATION isEqualToString:call.method]) {
        NSArray *arguments = call.arguments;
        NSString *orientation = arguments[0];
        NSInteger iOSOrientation;
        if ([orientation isEqualToString:ORIENTATION_LANDSCAPE_LEFT]){
            iOSOrientation = UIDeviceOrientationLandscapeLeft;
        }else if([orientation isEqualToString:ORIENTATION_LANDSCAPE_RIGHT]){
            iOSOrientation = UIDeviceOrientationLandscapeRight;
        }else if ([orientation isEqualToString:ORIENTATION_PORTRAIT_DOWN]){
            iOSOrientation = UIDeviceOrientationPortraitUpsideDown;
        }else{
            iOSOrientation = UIDeviceOrientationPortrait;
        }
        [[UIDevice currentDevice] setValue:@(iOSOrientation) forKey:@"orientation"];
        result(nil);
    } else {
        result(FlutterMethodNotImplemented);
    }
}
@end
复制代码

注册插件

打开 AppDelegate.mdidFinishLaunchingWithOptions 方法中注册插件

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
    ...
    
    // flutter: Device Plugin
    [FlutterIOSDevicePlugin registerWithRegistrar:[self registrarForPlugin:@"FlutterIOSDevicePlugin"] flutterViewController:controller];
}
复制代码

使用插件

import 'package:flutter/services.dart';

MethodChannel _channel = const MethodChannel('flutter_ios_device');

@override
void initState() {
  super.initState();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.landscapeRight,
    DeviceOrientation.landscapeRight,
  ]);
  if (Platform.isIOS) {
    changeScreenOrientation(DeviceOrientation.landscapeLeft);
  }
}

@override
void dispose() {
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
  ]);
  if (Platform.isIOS) {
    changeScreenOrientation(DeviceOrientation.portraitUp);
  }
  super.dispose();
}

Future<void> changeScreenOrientation(DeviceOrientation orientation) {
  String o;
  switch (orientation) {
    case DeviceOrientation.portraitUp:
      o = 'portraitUp';
      break;
    case DeviceOrientation.portraitDown:
      o = 'portraitDown';
      break;
    case DeviceOrientation.landscapeLeft:
      o = 'landscapeLeft';
      break;
    case DeviceOrientation.landscapeRight:
      o = 'landscapeRight';
      break;
  }
  return _channel.invokeMethod('change_screen_orientation', [o]);
}
复制代码

到此, 我们的工作基本完成. 可以强制某些特定页面改变布局方向.

还没有结束

在实践中, 我发现上面这样的做法会导致一个问题.

如果只想让特定的页面可以改变方向(横屏), 其它页面一直保持竖屏该怎么办?

"图一" 中, 我们设置了 iOS 的 Device Orientation 只要设备方向改变了, 布局就会改变.

现在, 根据图一的步骤将 Device Orientation 改为 仅 Portrait

修改 AppDelegate.h , 加入 isLandscape 这个属性

@interface AppDelegate : FlutterAppDelegate
@property (nonatomic,assign)BOOL isLandscape;
@end
复制代码

AppDelegate.m 中加入下列方法

// 是否允许横屏
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window{
    if (self.isLandscape) {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    }
    return UIInterfaceOrientationMaskPortrait;
}
复制代码

修改 FlutterIOSDevicePlugin.m

#import "AppDelegate.h"

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
    ...
        if ([orientation isEqualToString:ORIENTATION_LANDSCAPE_LEFT]){
            iOSOrientation = UIDeviceOrientationLandscapeLeft;
            ((AppDelegate *)[UIApplication sharedApplication].delegate).isLandscape = YES;
        }else if([orientation isEqualToString:ORIENTATION_LANDSCAPE_RIGHT]){
            iOSOrientation = UIDeviceOrientationLandscapeRight;
            ((AppDelegate *)[UIApplication sharedApplication].delegate).isLandscape = YES;
        }else if ([orientation isEqualToString:ORIENTATION_PORTRAIT_DOWN]){
            iOSOrientation = UIDeviceOrientationPortraitUpsideDown;
            ((AppDelegate *)[UIApplication sharedApplication].delegate).isLandscape = NO;
        }else{
            iOSOrientation = UIDeviceOrientationPortrait;
            ((AppDelegate *)[UIApplication sharedApplication].delegate).isLandscape = NO;
        }
    ...
}
复制代码

完成


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python高级编程(第二版)

Python高级编程(第二版)

[波兰] Michał Jaworski、[法] Tarek Ziadé / 张亮、阿信 / 人民邮电出版社 / 2017-9-19 / 89.00元

Python作为一种高级程序设计语言,凭借其简洁、易读及可扩展性日渐成为程序设计领域备受推崇的语言之一。 本书基于Python 3.5版本进行讲解,通过13章的内容,深度揭示了Python编程的高级技巧。本书从Python语言及其社区的现状开始介绍,对Python语法、命名规则、Python包的编写、部署代码、扩展程序开发、管理代码、文档编写、测试开发、代码优化、并发编程、设计模式等重要话题......一起来看看 《Python高级编程(第二版)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具