iOS 8自定义键盘:更改高度

时间:2014-06-11 16:22:09

标签: keyboard ios8 ios-app-extension

我试图在iOS 8中创建一个替换库存的自定义键盘。我真的搜索过,无法找出是否有可能创建一个比iOS iOS键盘更高的键盘。我替换了UIInputView但却永远无法改变我可用的高度。

17 个答案:

答案 0 :(得分:45)

这是我在Xcode 6.0 GM上的代码。两种方向都得到支持。

更新:感谢@SoftDesigner,我们现在可以消除constraint conflict警告。

警告:未测试XIB和故事板。据一些人报道,这不适用于XIB。

KeyboardViewController.h

#import <UIKit/UIKit.h>

@interface KeyboardViewController : UIInputViewController

@property (nonatomic) CGFloat portraitHeight;
@property (nonatomic) CGFloat landscapeHeight;
@property (nonatomic) BOOL isLandscape;
@property (nonatomic) NSLayoutConstraint *heightConstraint;
@property (nonatomic) UIButton *nextKeyboardButton;

@end

KeyboardViewController.m

#import "KeyboardViewController.h"

@interface KeyboardViewController ()
@end

@implementation KeyboardViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Perform custom initialization work here
        self.portraitHeight = 256;
        self.landscapeHeight = 203;
    }
    return self;
}

- (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];
    }
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    // Perform custom UI setup here
    self.nextKeyboardButton = [UIButton buttonWithType:UIButtonTypeSystem];

    [self.nextKeyboardButton setTitle:NSLocalizedString(@"Next Keyboard", @"Title for 'Next Keyboard' button") forState:UIControlStateNormal];
    [self.nextKeyboardButton sizeToFit];
    self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = NO;

    [self.nextKeyboardButton addTarget:self action:@selector(advanceToNextInputMode) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:self.nextKeyboardButton];

    NSLayoutConstraint *nextKeyboardButtonLeftSideConstraint = [NSLayoutConstraint constraintWithItem:self.nextKeyboardButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0];
    NSLayoutConstraint *nextKeyboardButtonBottomConstraint = [NSLayoutConstraint constraintWithItem:self.nextKeyboardButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0];
    [self.view addConstraints:@[nextKeyboardButtonLeftSideConstraint, nextKeyboardButtonBottomConstraint]];


    self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.inputView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:self.portraitHeight];

    self.heightConstraint.priority = UILayoutPriorityRequired - 1; // This will eliminate the constraint conflict warning.

}

- (void)textWillChange:(id<UITextInput>)textInput {
    // The app is about to change the document's contents. Perform any preparation here.
}

- (void)textDidChange:(id<UITextInput>)textInput {
}

@end

Swift 1.0版本:

class KeyboardViewController: UIInputViewController {

    @IBOutlet var nextKeyboardButton: UIButton!

    let portraitHeight:CGFloat = 256.0
    let landscapeHeight:CGFloat = 203.0
    var heightConstraint: NSLayoutConstraint?
    override func updateViewConstraints() {
        super.updateViewConstraints()
        // Add custom view sizing constraints here
        if (self.view.frame.size.width == 0 || self.view.frame.size.height == 0) {
            return
        }
        inputView.removeConstraint(heightConstraint!)
        let screenSize = UIScreen.mainScreen().bounds.size
        let screenH = screenSize.height;
        let screenW = screenSize.width;
        let isLandscape =  !(self.view.frame.size.width == screenW * ((screenW < screenH) ? 1 : 0) + screenH * ((screenW > screenH) ? 1 : 0))
        NSLog(isLandscape ? "Screen: Landscape" : "Screen: Potriaint");
        if (isLandscape) {
            heightConstraint!.constant = landscapeHeight;
            inputView.addConstraint(heightConstraint!)
        } else {
            heightConstraint!.constant = self.portraitHeight;
            inputView.addConstraint(heightConstraint!)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Perform custom UI setup here
        self.nextKeyboardButton = UIButton.buttonWithType(.System) as UIButton

        self.nextKeyboardButton.setTitle(NSLocalizedString("Next Keyboard", comment: "Title for 'Next Keyboard' button"), forState: .Normal)
        self.nextKeyboardButton.sizeToFit()
    self.nextKeyboardButton.setTranslatesAutoresizingMaskIntoConstraints(false)

        self.nextKeyboardButton.addTarget(self, action: "advanceToNextInputMode", forControlEvents: .TouchUpInside)

        self.view.addSubview(self.nextKeyboardButton)

        var nextKeyboardButtonLeftSideConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 0.0)
        var nextKeyboardButtonBottomConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
        self.view.addConstraints([nextKeyboardButtonLeftSideConstraint, nextKeyboardButtonBottomConstraint])

        heightConstraint = NSLayoutConstraint(item: self.inputView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: portraitHeight)
        heightConstraint!.priority = 999.0
    }

    override func textWillChange(textInput: UITextInput) {
        // The app is about to change the document's contents. Perform any preparation here.
    }

    override func textDidChange(textInput: UITextInput) {
        // The app has just changed the document's contents, the document context has been updated.

        var textColor: UIColor
        var proxy = self.textDocumentProxy as UITextDocumentProxy
        if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
            textColor = UIColor.whiteColor()
        } else {
            textColor = UIColor.blackColor()
        }
        self.nextKeyboardButton.setTitleColor(textColor, forState: .Normal)
    }
}

答案 1 :(得分:19)

最近,Apple更新了他们的App extension programming guide以更改自定义键盘扩展程序的高度:

CGFloat _expandedHeight = 500;

NSLayoutConstraint *_heightConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant: _expandedHeight];

[self.view addConstraint: _heightConstraint];

答案 2 :(得分:11)

这是我发现的导致高度正确更新的最小解决方案。似乎有两个关键组成部分:

  • 需要将translatesAutoresizingMaskIntoConstraints设置为false的视图添加到视图层次结构中。
  • 高度限制需要在viewWillAppear之前添加。

我仍然在日志中看到Unable to simultaneously satisfy constraints错误,但无论如何它似乎都正常。我还看到一个跳跃,其中高度最初设置为默认值,然后跳转到设定值。我还没有想出任何解决这些问题的方法。

import UIKit

class KeyboardViewController: UIInputViewController {

    var heightConstraint: NSLayoutConstraint!

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.inputView.addConstraint(self.heightConstraint)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let dummyView = UILabel(frame:CGRectZero)
        dummyView.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.view.addSubview(dummyView);

        let height : CGFloat = 400

        self.heightConstraint = NSLayoutConstraint( item:self.inputView, attribute:.Height, relatedBy:.Equal, toItem:nil, attribute:.NotAnAttribute, multiplier:0.0, constant:height)
    }
}

Swift 4更新:

import UIKit

class KeyboardViewController: UIInputViewController
{
    private weak var _heightConstraint: NSLayoutConstraint?

    override func viewWillAppear(_ animated: Bool)
    {
        super.viewWillAppear(animated)

        guard nil == _heightConstraint else { return }

        // We must add a subview with an `instrinsicContentSize` that uses autolayout to force the height constraint to be recognized.
        //
        let emptyView = UILabel(frame: .zero)
        emptyView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(emptyView);

        let heightConstraint = NSLayoutConstraint(item: view,
                                                  attribute: .height,
                                                  relatedBy: .equal,
                                                  toItem: nil,
                                                  attribute: .notAnAttribute,
                                                  multiplier: 0.0,
                                                  constant: 240)
        heightConstraint.priority = .required - 1
        view.addConstraint(heightConstraint)
        _heightConstraint = heightConstraint
    }
}

答案 3 :(得分:7)

接受的答案不适用于iOS 9.我在此结合了部分内容和其他一些建议以及App Extension Programming Guide中的Apple代码。

此解决方案效果很好,因为它不会延迟修改高度直到viewDidAppear,并且在旋转时您可以根据需要根据屏幕大小更改高度。已经过验证,适用于iOS 8和9。

一些重要的注意事项:
inputView中至少有一个元素需要使用自动布局
〜在viewWillAppear之前不能激活高度约束
〜需要降低高度约束的priority以避免不可满足的约束
updateViewConstraints是设定所需高度的好地方

提示:
〜在模拟器上进行测试时,我发现它非常脆弱,会出现意外情况。如果它对您执行此操作,请重置模拟器并再次运行。或者您可以只禁用键盘并再次添加。

注意:
〜这目前不适用于iOS 10测试版。当它出现时它会正确地改变高度,但如果你旋转设备,高度不会改变。这是因为在旋转时不会触发updateViewConstraints。请提交针对iOS 10的错误报告。要解决此问题,您可以触发constant中的viewDidLayoutSubviews更改。

var nextKeyboardButton: UIButton!
var heightConstraint: NSLayoutConstraint?


override func viewDidLoad() {
    super.viewDidLoad()

    self.nextKeyboardButton = UIButton(type: .System)

    self.nextKeyboardButton.setTitle(NSLocalizedString("Next Keyboard", comment: "Title for 'Next Keyboard' button"), forState: .Normal)
    self.nextKeyboardButton.sizeToFit()
    self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = false

    self.nextKeyboardButton.addTarget(self, action: "advanceToNextInputMode", forControlEvents: .TouchUpInside)

    self.view.addSubview(self.nextKeyboardButton)

    let nextKeyboardButtonLeftSideConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1, constant: 0)
    let nextKeyboardButtonBottomConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1, constant: 0)
    NSLayoutConstraint.activateConstraints([nextKeyboardButtonLeftSideConstraint, nextKeyboardButtonBottomConstraint])
}

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    self.heightConstraint = NSLayoutConstraint(item:self.inputView!, attribute:.Height, relatedBy:.Equal, toItem:nil, attribute:.NotAnAttribute, multiplier:0, constant:0)
    self.heightConstraint!.priority = 999
    self.heightConstraint!.active = true
}

override func updateViewConstraints() {
    super.updateViewConstraints()

    guard self.heightConstraint != nil && self.view.frame.size.width != 0 && self.view.frame.size.height != 0 else { return }

    let portraitHeight: CGFloat = 400
    let landscapeHeight: CGFloat = 200
    let screenSize = UIScreen.mainScreen().bounds.size

    let newHeight = screenSize.width > screenSize.height ? landscapeHeight : portraitHeight

    if (self.heightConstraint!.constant != newHeight) {
        self.heightConstraint!.constant = newHeight
    }
}

答案 4 :(得分:4)

其他答案没有考虑冲突的约束和设备轮换。这个答案避免了诸如“无法同时满足约束”之类的错误以及由此产生的问题。它部分依赖于可能在iOS未来版本中发生变化的行为,但似乎是在iOS 8上解决此问题的唯一方法。

UIInputViewController子类中,添加以下方法:

- (void)updateViewConstraints {
    [super updateViewConstraints];
    // Update height when appearing
    [self updateViewHeightConstraintIfNeeded];
}

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    // Update height when rotating
    [self updateViewHeightConstraintIfNeeded];
}

- (void)updateViewHeightConstraintIfNeeded {
    CGFloat preferedHeight = 216; // Portrait
    if ( [UIScreen mainScreen].bounds.size.width
         > [UIScreen mainScreen].bounds.size.height ) {
        // Landscape
        preferedHeight = 162;
    }
    NSLayoutConstraint *constraint = [self findViewHeightConstraint];
    if ( preferedHeight != constraint.constant ) {
        if ( constraint ) {
            constraint.constant = preferedHeight;
        } else {
            // This is not run on current versions of iOS, but we add it to
            // make sure the constraint exits
            constraint = [NSLayoutConstraint constraintWithItem:self.view
                          attribute:NSLayoutAttributeHeight
                          relatedBy:NSLayoutRelationEqual
                             toItem:nil
                          attribute:NSLayoutAttributeNotAnAttribute
                         multiplier:0
                           constant:preferedHeight];
            [self.view.superview addConstraint:constraint];
        }
    }
}

- (NSLayoutConstraint*)findViewHeightConstraint {
    NSArray *constraints = self.view.superview.constraints;
    for ( NSLayoutConstraint *constraint in constraints ) {
        if ( constraint.firstItem == self.view
             && constraint.firstAttribute == NSLayoutAttributeHeight )
            return constraint;
    }
    return nil;
}

答案 5 :(得分:4)

我在将自定义键盘从iOS 8调整到iOS 10时遇到了类似的问题。我认为正确的解决方案是让输入视图提供正确的intrinsicContentSize并在需要时更改(和无效!)该值改变视图的高度。示例代码:

class CustomInputView: UIInputView {
    var intrinsicHeight: CGFloat = 200 {
        didSet {
            self.invalidateIntrinsicContentSize()
        }
    }

    init() {
        super.init(frame: CGRect(), inputViewStyle: .keyboard)
        self.translatesAutoresizingMaskIntoConstraints = false
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.translatesAutoresizingMaskIntoConstraints = false
    }

    override var intrinsicContentSize: CGSize {
        return CGSize(width: UIViewNoIntrinsicMetric, height: self.intrinsicHeight)
    }
}

class ViewController: UIViewController {
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.becomeFirstResponder()

        let inputView = CustomInputView()
        // To make the view's size more clear.
        inputView.backgroundColor = UIColor(red: 0.5, green: 1, blue: 0.5, alpha: 1)
        textView.inputView = inputView

        // To demonstrate a change to the view's intrinsic height.
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(2)) {
            inputView.intrinsicHeight = 400
        }
    }
}

答案 6 :(得分:2)

将其放入ViewDidAppear:

NSLayoutConstraint *heightConstraint = 
                            [NSLayoutConstraint constraintWithItem: self.view
                                 attribute: NSLayoutAttributeHeight
                                 relatedBy: NSLayoutRelationEqual
                                    toItem: nil
                                 attribute: NSLayoutAttributeNotAnAttribute
                                multiplier: 0.0
                                  constant: 300];
    [self.view addConstraint: heightConstraint];

适用于iOS 8.1

答案 7 :(得分:1)

- (void)updateViewConstraints {


[super updateViewConstraints];

// Add custom view sizing constraints here
CGFloat _expandedHeight = 500;
NSLayoutConstraint *_heightConstraint =
[NSLayoutConstraint constraintWithItem: self.view
                             attribute: NSLayoutAttributeHeight
                             relatedBy: NSLayoutRelationEqual
                                toItem: nil
                             attribute: NSLayoutAttributeNotAnAttribute
                            multiplier: 0.0
                              constant: _expandedHeight];
[self.view addConstraint: _heightConstraint];
}   
 -(void)viewDidAppear:(BOOL)animated
{
    [self updateViewConstraints];
}

它适合我

答案 8 :(得分:1)

我创造了这个功能,对我来说很好。 添加 prepareHeightConstraint() heightConstraint ,并在 updateViewConstraints和viewWillAppear 中调用 prepareHeightConstraint()

    private var heightConstraint: NSLayoutConstraint!

    /**
        Prepare the height Constraint when create or change orientation keyboard
    */
    private func prepareHeightConstraint() {

        guard self.heightConstraint != nil else {
            let dummyView = UILabel(frame:CGRectZero)
            dummyView.translatesAutoresizingMaskIntoConstraints = false
            self.view.addSubview(dummyView)

            self.heightConstraint = NSLayoutConstraint( item:self.view, attribute:.Height, relatedBy:.Equal, toItem:nil, attribute:.NotAnAttribute, multiplier:0.0, constant: /* Here your height */)
            // /* Here your height */ Here is when your create your keyboard

            self.heightConstraint.priority = 750
            self.view.addConstraint(self.heightConstraint!)
            return
        }

        // Update when change orientation etc..
        self.heightConstraint.constant = /* Here your height */ 

    }


    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        // When keyboard is create
        self.prepareHeightConstraint()
    }


    override func updateViewConstraints() {
        super.updateViewConstraints()
        guard let viewKeyboard = self.inputView where viewKeyboard.frame.size.width != 0 && viewKeyboard.frame.size.width != 0 {
            return
        }
        //Update change orientation, update just the constant
        self.prepareHeightConstraint()
}

答案 9 :(得分:1)

为了更改方向上更流畅的动画,我添加:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    CGFloat width = [UIScreen mainScreen].bounds.size.width;
    self.view.window.frame = CGRectMake(0, 0, width, heigth);
}

答案 10 :(得分:1)

我一直在制作键盘并且在高度问题上苦苦挣扎。我尝试了所有提到的解决方案以及App扩展编程指南解决方案但无法修复它。我的键盘视图层次非常复杂。经过努力,我找到了一个完全适合我的解决方案。这是一种黑客攻击,但我已经测试了所有场景,即使设备旋转也很完美。我认为它会帮助别人,所以我把我的代码放在这里..

// Keep this code inside the UIInputViewController

@implementation KeyBoardViewController

@property (strong, nonatomic) NSLayoutConstraint *heightConstraint;

// This method will first get the height constraint created by (Run time system or OS) then deactivate it and add our own custom height constraint.

(void)addHeightConstraint {
    for (NSLayoutConstraint* ct in self.view.superview.constraints) {
        if (ct.firstAttribute == NSLayoutAttributeHeight) {
            [NSLayoutConstraint deactivateConstraints:@[ct]];
        }
    }
    if (!_heightConstraint) {
        _heightConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant: 300];
        [_heightConstraint setPriority:UILayoutPriorityDefaultHigh];
        [self.view addConstraint:_heightConstraint];
    }else {
        _heightConstraint.constant = 300;
    }

    if (_heightConstraint && !_heightConstraint.isActive) {
        [NSLayoutConstraint activateConstraints:@[_heightConstraint]];
    }
    [self.view layoutIfNeeded];
}


(void)viewWillLayoutSubviews {
    [self addHeightConstraint];
}

答案 11 :(得分:0)

这是一个非常老的问题,但我只是想分享一下,我发现UIInputViewController实际上会根据您添加到其中的子视图来调整自身大小。因此,如果您将这样的视图添加到视图控制器中:

let myView: UIView(frame: .zero)
myView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
myView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
myView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
myView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

其中view是输入视图控制器的视图,然后指定一个高度约束,输入视图控制器将遵守该高度而不会破坏任何约束。

这是完美的,因为您可以添加一个堆栈视图,可以在其中添加提供内部内容大小的视图。这样一来,您就不必指定高度限制,因为堆栈视图将根据您添加到其中的视图隐式调整大小。

答案 12 :(得分:0)

这是不可能的。来自docs

  

此外,无法在顶行上方显示关键作品,因为当您点击顶行中的某个键时,系统键盘会在iPhone上显示。

所以,如果可能的话,我们可以很容易地在顶行之上绘制一些东西。

修改:

似乎苹果公司解决了这个问题。请参阅接受的答案

答案 13 :(得分:0)

在IOS 10(swift 4)中,由于三个原因,我不得不将上述答案结合起来:

    旋转iPhone时未调用
  1. updateViewConstraints
  2. 设置heightConstraint会产生布局忽略的约束
  3. intrinsicContentSize仅在我不理解的情况下才起作用

    @objc public class CustomInputView: UIInputView {
        var intrinsicHeight: CGFloat = 296.0 {
        didSet {
            self.invalidateIntrinsicContentSize()
        }
      }
      @objc public init() {
        super.init(frame: CGRect(), inputViewStyle: .keyboard)
        self.translatesAutoresizingMaskIntoConstraints = false
      }
      @objc public required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.translatesAutoresizingMaskIntoConstraints = false
      }
      @objc public override var intrinsicContentSize: CGSize {
        let screenSize = UIScreen.main.bounds.size
        let newHeight :CGFloat = screenSize.width > screenSize.height ? 230.0 : intrinsicHeight
        return CGSize(width: UIViewNoIntrinsicMetric, height: newHeight)
      }
    }
    
    @objc public class KeyboardViewController: UIInputViewController {
      let portraitHeight:CGFloat = 296.0
      let landscapeHeight:CGFloat = 230.0
      var heightConstraint: NSLayoutConstraint?
      func updateHeightConstraint(to size: CGSize){
        var heightConstant=portraitHeight
        if size.width>400 {
            heightConstant=landscapeHeight
        }
        if heightConstant != heightConstraint!.constant {
            inputView?.removeConstraint(heightConstraint!)
            heightConstraint!.constant = heightConstant;
            inputView?.addConstraint(heightConstraint!)
        }
      }
      override public func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        updateHeightConstraint(to: size)
      }
      override public func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        updateHeightConstraint(to: UIScreen.main.bounds.size)
      }
      override public func viewDidLoad() {
        super.viewDidLoad()
        heightConstraint = NSLayoutConstraint(item: self.inputView as Any, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1.0, constant: portraitHeight)
        heightConstraint!.priority = UILayoutPriority(rawValue: 999.0)
        heightConstraint!.isActive=true;
      }
    //... code to insert, delete,.. 
    }
    
  4. viewDidAppear

    我必须致电updateHeightConstraint,因为我更改了viewWillTransition

    时未调用UIInputViewController

    我不需要self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = false

答案 14 :(得分:0)

这是我为 iOS9 Storyboard 所做的。

我使用了@ skyline75489(非常感谢)的答案并对其进行了修改。

@property (nonatomic) CGFloat portraitHeight;
@property (nonatomic) CGFloat landscapeHeight;
@property (nonatomic) BOOL isLandscape;
@property (nonatomic) NSLayoutConstraint *heightConstraint;

@property (nonatomic) BOOL viewWillAppearExecuted;


- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // Perform custom initialization work here
        self.portraitHeight = 256;
        self.landscapeHeight = 203;
    }
    return self;
}

- (void)updateViewConstraints {
    [super updateViewConstraints];

    if (_viewWillAppearExecuted)
        [self adjustHeight];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self.view addConstraint:self.heightConstraint];
    _viewWillAppearExecuted = YES;
}

#pragma mark - Setters/Getters

- (NSLayoutConstraint *)heightConstraint
{
    if (!_heightConstraint) {
        _heightConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:self.portraitHeight];
        _heightConstraint.priority = UILayoutPriorityRequired - 1;
    }

    return _heightConstraint;
}

#pragma mark - Methods

- (void)adjustHeight
{
    if (self.view.frame.size.width == 0 || self.view.frame.size.height == 0)
        return;

    [self.view 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)));

    self.isLandscape = isLandscape;
    if (isLandscape) {
        self.heightConstraint.constant = self.landscapeHeight;
        [self.view addConstraint:self.heightConstraint];
    } else {
        self.heightConstraint.constant = self.portraitHeight;
        [self.view addConstraint:self.heightConstraint];
    }
}

答案 15 :(得分:0)

最后我明白了,将此代码块添加到UIInputViewController子类Class:

override func viewDidAppear(animated: Bool) {
      let desiredHeight:CGFloat = 300.0 // or anything you want
      let heightConstraint = NSLayoutConstraint(item: view,  attribute:NSLayoutAttribute.Height, 
relatedBy: NSLayoutRelation.Equal,
 toItem: nil, 
attribute: NSLayoutAttribute.NotAnAttribute, 
multiplier: 1.0, 
constant: desiredHeight)

view.addConstraint(heightConstraint)        
}

它将完美运行.. iOS 8.3

答案 16 :(得分:0)

如果接受的答案对任何人都不起作用,那么请使用以下方式。所有代码都相同,只更改 updateViewConstraints Reference

内的代码
- (void)updateViewConstraints {
   [super updateViewConstraints];
   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");
 if (isLandscape)
 {
    self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.inputView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant: self.landscapeHeight];
    [self.inputView addConstraint:self.heightConstraint];
  } else {
    self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.inputView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant: self.portraitHeight];
    [self.inputView addConstraint:self.heightConstraint];
}

}