Я попытался создать пользовательскую клавиатуру в iOS 8, которая заменяет запасную. Я действительно искал и не мог узнать, возможно ли создать клавиатуру с большей высотой, чем клавиатура iOS на складе. Я заменил UIInputView, но мне никогда не удавалось изменить высоту, доступную мне.
Пользовательская клавиатура iOS 8: изменение высоты
Ответ 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) мне пришлось объединить вышеуказанные ответы по трем причинам:
-
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
не был вызван, когда я изменил 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
- представление контроллера входного представления, а затем задает ограничение высоты, контроллер представления ввода будет учитывать эту высоту, не нарушая никаких ограничений.
Это идеально, так как вы можете добавить представление стека, к которому вы можете добавить представления, которые предоставляют внутренний размер контента. Тогда вам не нужно было бы указывать ограничение высоты, поскольку размер стека будет неявно изменен в зависимости от того, какие представления вы добавляете в него.