пользовательская клавиатура iOS 8: изменение высоты
Я попытался создать пользовательскую клавиатуру в iOS 8, которая заменяет запасную. Я действительно искал и не мог узнать, можно ли создать клавиатуру с большей высотой, чем клавиатура iOS. Я заменил UIInputView, но никогда не мог изменить высоту, доступную мне.
16 ответов
Это мой код на 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.м
#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)
}
}
недавно Apple обновила свою App расширение руководство по программированию чтобы изменить высоту пользовательского расширения клавиатуры:
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];
это минимальное решение, которое я нашел, чтобы заставить высоту обновляться должным образом. Кажется, есть два ключевых компонента:
- вид с
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
}
}
принятый ответ не работает для iOS 9. Я объединил его части и некоторые другие предложения здесь вместе с кодом Apple в Руководство По Программированию Расширений Приложений.
это решение отлично работает, поскольку оно не задерживает изменение высоты до viewDidAppear
, и при вращении вы можете изменить высоту, если это необходимо, в зависимости от размера экрана. Проверено, что это работает в iOS 8 и 9.
несколько важных замечаний:
- по крайней мере один элемент в inputView
необходимо использовать Auto Layout
~ ограничение высоты не может быть активировано до viewWillAppear
~ ограничения высоты необходимо понизить, чтобы избежать неудовлетворительных ограничений
~ updateViewConstraints
хорошее место для того чтобы установить пожеланную высоту
советы:
~ при тестировании на симуляторе, я обнаружил, что он сильно шелушиться и будет вести себя неожиданно. Если он делает это с вами, сбросьте симулятор и запустите снова. Или вы можете просто отключить клавиатуру и добавить ее снова.
Примечание:
~ в настоящее время это не работает в бета-версии iOS 10. Он правильно изменит высоту, когда появится, но если вы повернете устройство, высота не изменится. Это потому что updateViewConstraints
не запускается при повороте. Пожалуйста, подайте отчет об ошибке против iOS 10. Чтобы обойти проблему, вы можете вызвать constant
изменение .
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
}
}
другие ответы не учитывают конфликтующие ограничения и поворот устройства. Этот ответ позволяет избежать ошибок, таких как "неспособность одновременно удовлетворять ограничения" и проблемы, возникающие в результате этого. Он частично зависит от поведения, которое может измениться в будущих версиях 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;
}
у меня были аналогичные проблемы с размером пользовательской клавиатуры от 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
}
}
}
поместите это в 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
- (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];
}
это работает для меня
Я создаю эту работу fonction, отлично для меня. Добавить 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()
}
для более плавной анимации при изменении ориентации я добавляю следующее:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
CGFloat width = [UIScreen mainScreen].bounds.size.width;
self.view.window.frame = CGRectMake(0, 0, width, heigth);
}
Я также делаю клавиатуру и борюсь с проблемой высоты. Я попробовал все упомянутые решения, а также решение руководства по программированию приложений, но не смог его исправить. Моя клавиатура имеет очень сложную иерархию представления. После борьбы я нашел решение, которое полностью работает на меня. Это своего рода хак, но я проверил все сценарии, даже с вращением устройства, и это прекрасно. Я думал, что это поможет кому-то, поэтому я помещаю свой код здесь..
// 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];
}
Это невозможно. От docs
кроме того, невозможно отобразить обложку клавиш над верхней строкой, как это делает системная клавиатура на iPhone, когда вы нажимаете клавишу в верхнем ряду.`
Итак, если бы это было возможно, мы могли бы легко нарисовать что-то над верхним рядом.
Edit:
кажется, Apple исправила эту вещь. Пожалуйста, смотрите принятый ответ
если принятый ответ не работает ни для кого, используйте ниже.весь код будет одинаковым, только измените код внутри 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];
}
}
наконец-то я понял, добавьте этот блок кода в свой 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
Это то, что я сделал для iOS 9 охота и раскадровка.
я использовал ответ @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];
}
}
в IOS 10 (swift 4) мне пришлось объединить вышеуказанные ответы по трем причинам:
-
updateViewConstraints
не вызывается при повороте iPhone - задание
heightConstraint
создает ограничение, которое игнорируется макетом -
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
не был вызван, когда я изменил the UIInputViewController
мне не нужно self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = false