【问题标题】:How to detect Orientation Change in Custom Keyboard Extension in iOS 8?如何在 iOS 8 中检测自定义键盘扩展的方向变化?
【发布时间】:2014-08-01 17:51:26
【问题描述】:

在自定义键盘扩展中,我们不能使用

`didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation` 

sharedApplication

我需要在旋转时检测键盘中的纵向或横向。

如何检测自定义键盘扩展中的方向何时发生变化?

【问题讨论】:

  • 我鼓励您更改已接受的答案。由于当前的解决方案不适用于 iPad。
  • 为什么?对于 iPad,您可以将纵向视图框架大小宽度更改为 768。对于横向,您可以使用 if else 来完成。
  • 虽然不支持未来的设备尺寸。您将不得不更新您的应用程序。我相信我读过一些关于苹果推出两种新 iPhone 屏幕尺寸的消息。 macrumors.com/roundup/iphone-6
  • 是的。当他们发布具有新尺寸的设备时,我们可以检测每个设备的 View.frame.size.width 或高度。
  • 但是您会因为这个原因而不得不更新您的应用程序吗?为什么不从一开始就检测到这一切?另外,您最终会得到多个条件语句,而不仅仅是一个。

标签: ios8 ios-app-extension custom-keyboard uiinputviewcontroller


【解决方案1】:

为了在方向改变时更新您的自定义键盘,请覆盖UIInputViewController 中的viewDidLayoutSubviews。据我所知,当发生旋转时,总是会调用此方法。

此外,由于传统的[UIApplication sharedApplication] statusBarOrientation] 不起作用,要确定当前方向,请使用以下 sn-p:

if([UIScreen mainScreen].bounds.size.width < [UIScreen mainScreen].bounds.size.height){
    //Keyboard is in Portrait
}
else{
    //Keyboard is in Landscape
}

希望这会有所帮助!

【讨论】:

  • @iAn 旋转到横向时它在我的应用程序中工作。
  • @Sabo 您应该将此标记为已回答的回复。对我有用
  • 魔术数字...哦,太恐怖了。不要这样做!
  • 在 iPad 上,在 viewDidLayoutSubviews 内部,[[UIScreen mainScreen] bounds] 具有方向更改前的旧值:/
  • 为我工作。目前在我的应用中使用它。
【解决方案2】:

未弃用,适用于任何设备屏幕尺寸(包括未来的屏幕尺寸Apple will be releasing this year)。

在自定义键盘ViewController.m:

-(void)viewDidLayoutSubviews {
    NSLog(@"%@", (self.view.frame.size.width == ([[UIScreen mainScreen] bounds].size.width*([[UIScreen mainScreen] bounds].size.width<[[UIScreen mainScreen] bounds].size.height))+([[UIScreen mainScreen] bounds].size.height*([[UIScreen mainScreen] bounds].size.width>[[UIScreen mainScreen] bounds].size.height))) ? @"Portrait" : @"Landscape");
}

完成。


或者...对于此代码的更易于阅读的版本:

-(void)viewDidLayoutSubviews {
    
    int appExtensionWidth = (int)round(self.view.frame.size.width);
    
    int possibleScreenWidthValue1 = (int)round([[UIScreen mainScreen] bounds].size.width);
    int possibleScreenWidthValue2 = (int)round([[UIScreen mainScreen] bounds].size.height);
    
    int screenWidthValue;
    
    if (possibleScreenWidthValue1 < possibleScreenWidthValue2) {
        screenWidthValue = possibleScreenWidthValue1;
    } else {
        screenWidthValue = possibleScreenWidthValue2;
    }
    
    if (appExtensionWidth == screenWidthValue) {
        NSLog(@"portrait");
    } else {
        NSLog(@"landscape");
    }
}

【讨论】:

  • 在 iPhone 6 模拟器上,即使设备处于纵向模式,它也会打印出Landscape
  • @SalavatKhanov 在 iPhone6 模拟器中对我来说效果很好。您正在运行哪个 xCode BETA?
  • 这与不是为 iphone 6 和 phone 6+ 尺寸构建的应用程序不同。例如,我现在正在测试 whatsapp,它报告 self.view.frame 为 (0, 0, 320, 216),屏幕尺寸为 (414, 736),所以它会抛出这个逻辑。
  • @fatshu 逻辑仍然可以正常工作吗?只是数字不对哈哈
  • 我有同样的设备,但如何获取设备是landScapeLeft 或landScapeRight,如果可能的话,请检查并帮助我stackoverflow.com/questions/25462091/…
【解决方案3】:

有一个简单的方法,就是看屏幕宽度:

 double width = [[UIScreen mainScreen] bounds].size.width;
 double interfaceWidth = MIN([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);

 BOOL isPortrait = (width == interfaceWidth) ? YES : NO;

【讨论】:

  • 只看宽度CGSize screenSize = [UIScreen mainScreen].bounds.size; BOOL isPortrait = screenSize.width < screenSize.height;
【解决方案4】:

使用viewWillTransitionToSize:(CGSize)size withTransitionCoordinator: 在你的 viewController 里面

【讨论】:

  • 控制器在键盘扩展模式下运行时似乎没有调用该方法。从 iOS 8 Beta 5 开始,对我在模拟器和实际设备上都不起作用。它对你有用吗?我希望它能够工作,它看起来是正确的、面向未来的解决方案。
  • 老实说我在发布之前没有测试它,你是对的,它不起作用,作为一种替代方式,你可以使用稍后调用的 viewDidLayoutSubviews,但希望将来它将像普通 UIViewControllers 一样工作。
  • 我的 Radar 问题被标记为 17472132 的副本,该问题目前仍处于打开状态。希望这意味着这个解决方案最终会奏效。
  • 从 iOS 8.3 beta 2 开始,viewWillTransitionToSize 终于在方向更改期间被调用。另一方面,viewDidLayoutSubviews 中的旧解决方法对我不起作用,因为报告的视图大小是错误的。希望我们不必根据特定的 iOS 版本来处理轮换……(雷达问题仍未解决。)
  • 我相信这是现在被接受的方法。它在我的应用程序中运行,当方向改变时,我使用它来触发程序化文本视图的重新布局。
【解决方案5】:
- (void)updateViewConstraints {
    [super updateViewConstraints];

    // Add custom view sizing constraints here
    if (self.view.frame.size.width == 0 || self.view.frame.size.height == 0)
        return;

    [self.inputView removeConstraint:self.heightConstraint];
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    CGFloat screenH = screenSize.height;
    CGFloat screenW = screenSize.width;
    BOOL isLandscape =  !(self.view.frame.size.width ==
                      (screenW*(screenW<screenH))+(screenH*(screenW>screenH)));
    NSLog(isLandscape ? @"Screen: Landscape" : @"Screen: Potriaint");
    self.isLandscape = isLandscape;
    if (isLandscape) {
        self.heightConstraint.constant = self.landscapeHeight;
        [self.inputView addConstraint:self.heightConstraint];
    } else {
        self.heightConstraint.constant = self.portraitHeight;
        [self.inputView addConstraint:self.heightConstraint];
    }

    //trigger default first view
    [btn_gif sendActionsForControlEvents: UIControlEventTouchUpInside];
}

【讨论】:

    【解决方案6】:

    willRotateToInterfaceOrientationdidRotateFromInterfaceOrientation 可以使用,我只是在我的 iPad 上尝试过,在 iOS 8.1 上运行键盘。请注意,这些在 iOS 8 中已被弃用,但它们的替代品 willTransitionToTraitCollection 并没有被调用,因为旋转时键盘的特征集合不会改变。

    【讨论】:

      【解决方案7】:

      在iOS 8.3之前,你必须使用

      -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
                                     duration:(NSTimeInterval)duration
      

      这个不行(应该是bug):

      -(void)viewWillTransitionToSize:(CGSize)size
            withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
      

      在 iOS 8.3 及更高版本上,您最好使用

      -(void)viewWillTransitionToSize:(CGSize)size
            withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
      

      因为

      -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
                                     duration:(NSTimeInterval)duration
      

      已弃用。

      【讨论】:

      • 好吧,我认为 viewWillTransitionToSize 在 8.3 之前仍然可以工作,除了你必须在每个子视图的控制器上调用这个函数,而现在你不需要
      • 好吧,我收回来,我糊涂了。试过了,它仍然像以前一样工作。澄清一下,viewWillTransitionToSize 仅被第一个视图控制器拾取,并且从那里您必须依赖 viewDidLayoutSubviews 传播或在所有子视图上调用您的自定义方向更改函数。无论如何,这可能就是它始终打算如何工作的方式。这就是我在 8.3 之前一直在使用它的方式。
      【解决方案8】:

      在某些情况下 [UIScreen mainscreen].bounds 可能不起作用。有时会在 viewWillTransitionToSize 之后更新:

      试试这个

      - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator{
      
          CGSize screenSize = [[UIScreen mainScreen] bounds].size;
          CGFloat realScreenHeight = MAX(screenSize.height, screenSize.width);
          if(size.width == realScreenHeight)
              NSLog(@"Landscape");
          else
              NSLog(@"Portrait");
      }
      

      【讨论】:

        【解决方案9】:

        对于那些在 Swift 5 中寻找答案的人。

        通过覆盖func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) 方法。您可以检测设备方向。

        这是我的自定义键盘的代码。

        override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
                let screen = UIScreen.main.bounds
                if screen.width < screen.height {
                    print("!!! portrait")
                    let constraintForHeight:NSLayoutConstraint = NSLayoutConstraint(item: mainView!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 0, constant: 325)
                    constraintForHeight.isActive = true
                    constraintForHeight.priority = UILayoutPriority.defaultHigh
                    self.inputView?.addConstraint(constraintForHeight)
                } else {
                    print("!!! landspace")
                    let constraintForHeight:NSLayoutConstraint = NSLayoutConstraint(item: mainView!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 0, constant: 210)
                    constraintForHeight.isActive = true
                    constraintForHeight.priority = UILayoutPriority.defaultHigh
                    self.inputView?.addConstraint(constraintForHeight)
                }
            }
        

        【讨论】:

          【解决方案10】:
                - (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator 
              {   
               [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) 
                  {      UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];      // do whatever 
                    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {    }];       [super viewWillTransitionToSize: size withTransitionCoordinator: coordinator]; 
           }
          

          【讨论】:

          • 错了。 “'sharedApplication' 不可用:在 iOS 上不可用(应用程序扩展) - 在适当的情况下使用基于视图控制器的解决方案。”
          猜你喜欢
          • 1970-01-01
          • 2014-11-15
          • 2015-03-16
          • 1970-01-01
          • 2014-11-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多