Подтвердить что ты не робот

Пользовательская клавиатура iOS 8: изменение высоты

Я попытался создать пользовательскую клавиатуру в iOS 8, которая заменяет запасную. Я действительно искал и не мог узнать, возможно ли создать клавиатуру с большей высотой, чем клавиатура iOS на складе. Я заменил UIInputView, но мне никогда не удавалось изменить высоту, доступную мне.

4b9b3361

Ответ 1

Это мой код на 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 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 contents. Perform any preparation here.
    }

    override func textDidChange(textInput: UITextInput) {
        // The app has just changed the document 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)
    }
}

Ответ 2

Недавно Apple обновила руководство по программированию расширения приложений , чтобы изменить высоту пользовательского расширения клавиатуры:

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

Ответ 3

Это минимальное решение, которое я нашел для правильного обновления высоты. Кажется, есть два ключевых компонента:

  • Представление с 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
    }
}

Ответ 4

Принятый ответ не работал для iOS 9. Я объединил его и некоторые другие предложения здесь вместе с кодом Apple в Руководство по программированию расширений приложений.

Это решение отлично работает, так как оно не задерживает изменение высоты до viewDidAppear, а при повороте вы можете изменить высоту, если хотите, на основе размера экрана. Проверено это работает в iOS 8 и 9.

Несколько важных примечаний:
~ По крайней мере, один элемент в inputView должен использовать Auto Layout
~ Ограничение высоты не может быть активировано до viewWillAppear
~ Чтобы уменьшить недопустимые ограничения, необходимо уменьшить значение priority ограничения высоты
~ updateViewConstraints - хорошее место для установки желаемой высоты

Советы:
~ При тестировании на симуляторе я обнаружил, что он очень шелушащийся и будет вести себя неожиданно. Если он сделает это с вами, reset симулятор и снова запустите. Или вы можете просто отключить клавиатуру и добавить ее снова.

Примечание:
~ Это не работает в бета-версии 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
    }
}

Ответ 5

В других ответах не учитываются конфликтующие ограничения и поворот устройства. Этот ответ позволяет избежать ошибок, таких как "Невозможно одновременно удовлетворить ограничения" и проблемы, возникающие из-за этого. Он частично зависит от поведения, которое может измениться в будущих версиях 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;
}

Ответ 6

У меня были похожие проблемы с изменением размера пользовательской клавиатуры от 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 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 intrinsic height.
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(2)) {
            inputView.intrinsicHeight = 400
        }
    }
}

Ответ 7

Поместите это в 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

Ответ 8

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

Это работает для меня

Ответ 9

Я создаю эту работу, отлично для меня. Добавьте 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()
}

Ответ 10

Для более плавной анимации при изменении ориентации я добавляю следующее:

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

Ответ 11

Я также делаю Клавиатуру и борюсь с проблемой высоты. Я пробовал все упомянутые решения, а также руководство по программированию приложений для расширения приложений, но не смог его исправить. У моей клавиатуры очень сложная иерархия. После борьбы я нашел решение, которое полностью работает на меня. Это своего рода хак, но я протестировал все сценарии даже с поворотом устройства, и это прекрасно. Я думал, что это поможет кому-то, поэтому я размещаю свой код здесь.

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

Ответ 12

Это невозможно. Из docs

Кроме того, невозможно отображать ключевые иллюстрации над верхней строкой, так как клавиатура системы делает на iPhone при нажатии клавиши в верхней строке.

Итак, если бы это было возможно, мы могли бы легко нарисовать что-то выше верхней строки.

Изменить:

Кажется, Apple исправила это. См. Принятый ответ

Ответ 13

Если принятый ответ не работает ни для кого, то используйте ниже путь. Все коды будут одинаковыми, только измените код внутри updateViewConstraints Ссылка

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

}

Ответ 14

Наконец, я получил его, добавьте этот блок кода в подкласс 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)        
}

Он будет работать отлично. iOS 8.3

Ответ 15

Это то, что я сделал для iOS9 и раскадровки.

Я использовал @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];
    }
}

Ответ 16

В IOS 10 (swift 4) мне пришлось объединить вышеуказанные ответы по трем причинам:

  1. updateViewConstraints не вызывается при повороте iPhone
  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,.. 
    }
    

в viewDidAppear мне пришлось вызвать updateHeightConstraint потому что viewWillTransition не был вызван, когда я изменил UIInputViewController

Мне не нужно self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = false

Ответ 17

Это очень старый вопрос, но я просто хотел поделиться тем, что обнаружил, что UIInputViewController самом деле изменяет свой UIInputViewController зависимости от добавляемых в него 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 - представление контроллера входного представления, а затем задает ограничение высоты, контроллер представления ввода будет учитывать эту высоту, не нарушая никаких ограничений.

Это идеально, так как вы можете добавить представление стека, к которому вы можете добавить представления, которые предоставляют внутренний размер контента. Тогда вам не нужно было бы указывать ограничение высоты, поскольку размер стека будет неявно изменен в зависимости от того, какие представления вы добавляете в него.