Teclado personalizado iOS 8: cambiar la altura

Intenté crear un teclado personalizado en iOS 8 que reemplaza al de stock. Realmente busqué y no pude averiguar si es posible crear un teclado con más altura que el teclado estándar de iOS. Reemplacé UIInputView pero nunca pude cambiar la altura disponible para mí.

Este es mi código en Xcode 6.0 GM. Ambas orientaciones son compatibles.

Actualización: gracias a @SoftDesigner, podemos eliminar la advertencia de constraint conflict ahora.

Advertencia : XIB y el guión gráfico no se prueban. Algunos informaron que esto NO funciona con XIB.

KeyboardViewController.h

 #import  @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*(screenWscreenH))); 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)textInput { // The app is about to change the document's contents. Perform any preparation here. } - (void)textDidChange:(id)textInput { } @end 

Swift 1.0 versión:

 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) } } 

Recientemente, Apple ha actualizado su guía de progtwigción de extensiones de aplicaciones para cambiar la altura de la extensión de teclado personalizada:

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

Esta es la solución mínima que he encontrado para hacer que la altura se actualice correctamente. Parece que hay dos componentes clave:

  • Una vista con translatesAutoresizingMaskIntoConstraints establecido en false debe agregarse a la jerarquía de vista.
  • La restricción de altura se debe agregar no antes que viewWillAppear .

Todavía veo una Unable to simultaneously satisfy constraints error de Unable to simultaneously satisfy constraints en el registro, pero parece funcionar bien de todos modos. También sigo viendo un salto en el que la altura se establece inicialmente en su valor predeterminado, y luego salta al valor establecido. Todavía no he resuelto ninguno de estos problemas.

 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) } } 

Actualización para 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 } } 

La respuesta aceptada no funcionaba para iOS 9. Combiné partes de ella y algunas otras sugerencias aquí junto con el código de Apple en la Guía de progtwigción de extensión de la aplicación .

Esta solución funciona muy bien ya que no demora la modificación de la altura hasta viewDidAppear , y al girar puede cambiar la altura si lo desea en función del tamaño de la pantalla. Verificado esto funciona en iOS 8 y 9.

Algunas notas importantes:
~ Al menos un elemento en el inputView necesita usar diseño automático
~ La restricción de altura no se puede activar hasta que viewWillAppear
~ La priority de la restricción de altura debe reducirse para evitar restricciones insatisfactorias
~ updateViewConstraints es un buen lugar para establecer la altura deseada

Consejos:
~ Cuando probaba en el simulador, descubrí que era muy escamoso y se comportaría inesperadamente. Si te hace esto, reinicia el simulador y vuelve a correr. O puede desactivar el teclado y agregarlo nuevamente.

Nota:
~ Esto no funciona actualmente en iOS 10 beta. Cambiará correctamente la altura cuando aparezca, pero si gira el dispositivo, la altura no cambiará. Esto se debe a que updateViewConstraints no se activa al rotar. Por favor, presente un informe de error contra iOS 10. Para solucionar el problema, puede activar el cambio constant en viewDidLayoutSubviews en viewDidLayoutSubviews lugar.

 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 } } 

Otras respuestas no tienen en cuenta las restricciones conflictivas y la rotación del dispositivo. Esta respuesta evita errores como “Incapaz de satisfacer restricciones simultáneamente” y los problemas que resultan de ello. En parte, se basa en comportamientos que pueden cambiar en futuras versiones de iOS, pero parece ser la única forma de resolver este problema en iOS 8.

En su subclase UIInputViewController , agregue estos métodos:

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

Tuve problemas similares con el tamaño de un teclado personalizado de iOS 8 a iOS 10. Creo que la solución adecuada es hacer que la vista de entrada proporcione un tamaño de contenido intrinsicContentSize adecuado y cambie (¡e invalide!) Ese valor cuando desee cambiar la altura de la vista. Código de muestra:

 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 } } } 

Pon esto en ViewDidAppear:

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

Funciona en iOS 8.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]; } 

Funciona para mí

Creo este trabajo de fonction, bien para mí. Agregue prepareHeightConstraint () y heightConstraint y en su updateViewConstraints y viewWillAppear llame a 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() } 

Para una animación más fluida en la orientación de cambio agrego esto:

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

También he estado haciendo un Teclado y luchando con el problema de la altura. Intenté todas las soluciones mencionadas y también la solución de la guía de progtwigción de la extensión de la aplicación, pero no pude solucionarlo. Mi teclado tiene una jerarquía de vistas muy compleja. Después de luchar encontré una solución que funciona completamente para mí. Es una especie de truco, pero he probado todos los escenarios incluso con la rotación del dispositivo y es perfecto. Pensé que ayudaría a alguien, así que estoy poniendo mi código aquí …

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

No es posible. De los documentos

Además, no es posible mostrar ilustraciones clave encima de la fila superior, como lo hace el teclado del sistema en iPhone cuando toca una tecla en la fila superior.

Entonces, si fuera posible, podríamos dibujar fácilmente algo sobre la fila superior.

Editar:

Parece que Apple arregló esto. Por favor mira la respuesta aceptada

Si la respuesta aceptada no funciona para nadie, utilícela a continuación. Todos los códigos serán iguales. Solo cambie el código dentro de la referencia de actualización .

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

Finalmente lo obtuve, agregue este bloque de código a su UIInputViewController subclase UIInputViewController :

 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) } 

Funcionará perfectamente … iOS 8.3

Esto es lo que hice para iOS9 y Storyboard .

He usado la respuesta de @ skyline75489 (gracias grande) y la he modificado.

 @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*(screenWscreenH))); 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]; } } 

En IOS 10 (swift 4) tuve que combinar las respuestas anteriores por tres razones:

  1. no se llama a updateViewConstraints cuando gira el iPhone
  2. Establecer una restricción de heightConstraint produce una restricción que el diseño ignora
  3. intrinsicContentSize funcionó solo bajo circunstancias que no entendí

     @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,.. } 

en viewDidAppear tuve que llamar a updateHeightConstraint porque no se llamó a viewWillTransition cuando cambié el UIInputViewController

No necesitaba self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = false