Крышки клавиатуры iPhone UITextField
У меня есть приложение, в котором в Interface Builder я настроил UIView
у которого есть текстовое поле около основания представления. Когда я запускаю приложение и пытаюсь ввести текст в это поле, клавиатура скользит вверх над полем, поэтому я не могу видеть, что я печатаю, пока снова не скрою клавиатуру.
Кто-нибудь еще сталкивался с этой проблемой и нашел хороший способ решить ее без необходимости прокручивать родительский вид или перемещать текстовое поле дальше вверх по экрану?
20 ответов
Обычное решение - сдвинуть поле (и все, что над ним) с анимацией, а затем отступить, когда вы закончите. Возможно, вам придется поместить текстовое поле и некоторые другие элементы в другое представление и сдвинуть представление как единое целое. (Я называю эти вещи "плитами", как в "тектонических плитах", но это только я). Но вот общая идея, если вам не нужно наворочиваться.
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = 80; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
Это творило чудеса для меня скольжения uitextfields
В частности, он имеет преимущество вычисления расстояния анимации слайда в зависимости от положения текстового поля.
IQKeyboardManager сделает это для вас без БЕЗ СТРОКИ КОДА, нужно только перетащить соответствующий исходный файл в проект. IQKeyboardManager также поддерживает ориентацию устройства, автоматическое управление UIToolbar, клавиатура DistanceFromTextField и многое другое, чем вы думаете.
Вот схема управления:
Шаг 1:- Добавлены глобальные уведомления о UITextField
, UITextView
, а также UIKeyboard
в одиночном классе. Я назвал это IQKeyboardManager.
Шаг 2:- Если найден UIKeyboardWillShowNotification
, UITextFieldTextDidBeginEditingNotification
или же UITextViewTextDidBeginEditingNotification
уведомления, затем попробуйте получить topMostViewController
экземпляр из UIWindow.rootViewController
иерархия. Для того, чтобы правильно раскрыть UITextField
/ UITextView
в теме, topMostViewController.view
Рамка должна быть скорректирована.
Шаг 3:- Расчетное ожидаемое расстояние перемещения topMostViewController.view
в отношении первого ответившего UITextField
/ UITextView
,
Шаг 4:- Переехал topMostViewController.view.frame
вверх / вниз в соответствии с ожидаемым расстоянием перемещения.
Шаг 5:- Если найден UIKeyboardWillHideNotification
, UITextFieldTextDidEndEditingNotification
или же UITextViewTextDidEndEditingNotification
уведомление, затем снова попробуйте получить topMostViewController
экземпляр из UIWindow.rootViewController
иерархия.
Шаг 6:- Рассчитано нарушенное расстояние topMostViewController.view
который должен быть восстановлен в исходное положение.
Шаг 7:- Восстановлено topMostViewController.view.frame
вниз по нарушенному расстоянию.
Шаг 8:- Созданный экземпляр синглтона класса IQKeyboardManager при загрузке приложения, поэтому каждый UITextField
/ UITextView
в приложении будет корректироваться автоматически в зависимости от предполагаемого расстояния перемещения.
Это все
Как насчет официального решения: перемещение контента, расположенного под клавиатурой
Корректировка содержимого обычно включает временное изменение размера одного или нескольких представлений и расположение их так, чтобы текстовый объект оставался видимым. Самый простой способ управления текстовыми объектами с клавиатуры - это встроить их в объект UIScrollView (или в один из его подклассов, таких как UITableView). Когда отображается клавиатура, все, что вам нужно сделать, это сбросить область содержимого представления прокрутки и прокрутить нужный текстовый объект в нужное положение. Таким образом, в ответ на UIKeyboardDidShowNotification ваш метод-обработчик будет делать следующее:
- Получите размер клавиатуры.
- Отрегулируйте нижнюю вставку содержимого представления прокрутки по высоте клавиатуры.
- Прокрутите целевое текстовое поле в поле зрения.
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
[self.scrollView scrollRectToVisible:activeField.frame animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
У меня есть такая же проблема в UITableView
ячейки textField. Я решил эту проблему, реализовав следующий метод для прослушивания уведомлений клавиатуры.
Наблюдатель за уведомлениями здесь:
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
Обработайте эти уведомления с помощью функции ниже:
(void)keyboardWasShown:(NSNotification*)aNotification
(void)keyboardWillBeHidden:(NSNotification*)aNotification
Чтобы расширить ответ Amagrammer, вот пример класса:
LoginViewController.h
@interface LoginViewController : UIViewController <UITextFieldDelegate> {
}
@property (nonatomic, retain) IBOutlet UITextField *emailTextField;
@property (nonatomic, retain) IBOutlet UITextField *passwordTextField;
Обратите внимание, что мы реализуем UITextFieldDelegate
LoginViewController.m
@implementation LoginViewController
@synthesize emailTextField=_emailTextField;
@synthesize passwordTextField=_passwordTextField;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
//Register to receive an update when the app goes into the backround
//It will call our "appEnteredBackground method
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appEnteredBackground)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
}
return self;
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = 80; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: @"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
//This is called when the app goes into the background.
//We must reset the responder because animations will not be saved
- (void)appEnteredBackground{
[self.emailTextField resignFirstResponder];
[self.passwordTextField resignFirstResponder];
}
Ниже приводится быстрая версия ответа Amagrammer. Кроме того, вариант с использованием события UIKeyboardWillShowNotification, так как мне нужно было знать размер клавиатуры, прежде чем сдвинуть представление с пути.
var keyboardHeight:CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChange:", name: UIKeyboardWillShowNotification, object: nil)
}
func textFieldDidBeginEditing(textField: UITextField) {
//keyboardWillChange (below) is used instead of textFieldDidBeginEditing because textFieldDidBeginEditing
//is called before the UIKeyboardWillShowNotification necessary to determine the keyboard height.
}
func textFieldDidEndEditing(textField: UITextField) {
animateTextField(false)
}
func animateTextField(textFieldUp:Bool) {
let movementDistance:CGFloat = keyboardHeight
let movementDuration = 0.3
let movement:CGFloat = (textFieldUp ? -movementDistance : movementDistance)
UIView.beginAnimations("anim", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
func keyboardWillChange(notification:NSNotification) {
let keyboardRect:CGRect = ((notification.userInfo![UIKeyboardFrameEndUserInfoKey])?.CGRectValue)!
keyboardHeight = keyboardRect.height
animateTextField(true)
}
Проверь это. Нет проблем для вас.
Это решение очень аккуратное. Все, что вам нужно сделать, это добавить свои текстовые поля в UIScrollView
и изменить его класс на TPKeyboardAvoidingScollView
, если вы используете раскадровки. Представление прокрутки расширено таким образом, что оно будет определять, когда клавиатура видна, и будет перемещаться над клавиатурой на разумном расстоянии. Это идеальное решение, потому что оно не зависит от вашего UIViewController
, Все необходимое делается в вышеупомянутом классе. Спасибо Майкл Тайсон и все.
Был отличный пошаговое руководство по редактированию текстовых полей без затенения (теперь ссылка не работает, вот ссылка на Wayback: https://web.archive.org/web/20091123074029/http://acts-as-geek.blogspot.com/2009/11/editing-textfields-without-obscuring.html). Это показывает, как переместить существующий UIView
на UIScrollView
и для автоматической прокрутки при появлении клавиатуры.
Я немного обновил его, чтобы вычислить правильную высоту UIScrollView
когда есть элементы управления (такие как UITabBar
) ниже UIScrollBar
, Смотрите пост обновления uiview.
Вот решение с использованием Xcode5, iOS7:
Используйте UITextfieldDelegate и блоки анимации.
Это почти весь код для ViewController, но я хотел включить код делегата для тех, кто все еще незнаком с шаблоном делегата (как я). Я также включил код, чтобы скрыть клавиатуру, когда вы нажимаете в сторону от просмотра текста.
Вы можете перемещать представления (кнопки, текстовые поля и т. Д.) Так высоко, как вам хотелось бы, просто обязательно верните их на место (+100, а затем -100).
@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) IBOutlet UITextField *MyTextField;
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.MyTextField.delegate = self;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(@"text began editing");
CGPoint MyPoint = self.MyTextField.center;
[UIView animateWithDuration:0.3
animations:^{
self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y - 100);
}];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSLog(@"text ENDED editing");
CGPoint MyPoint = self.MyTextField.center;
[UIView animateWithDuration:0.3
animations:^{
self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y + 100);
}];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
Я предполагаю, что одним из способов было бы переместить всю позицию ваших представлений из (x,y) в (x,y-keybaardHeight) при нажатии текстового поля и вернуть его обратно, когда клавиатура отклонена, может выглядеть немного странно, поскольку представление просто подходит (возможно, это не будет плохо, если вы оживите его).
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGRect frame=self.view.frame;
frame.origin=CGPointMake(x...//set point here
self.view.frame=frame;
}
Просто сдвиньте вид вверх и вниз по мере необходимости:
- (void)textFieldDidEndEditing:(UITextField *)textField {
self.currentTextField = nil;
[self animateTextField: textField up: NO];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.currentTextField resignFirstResponder];
return YES;
}
- (void) animateTextField:(UITextField*) textField up:(BOOL)up {
const int movementDistance = 80; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView animateWithDuration:movementDuration animations:^{
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
}];
}
Не забудьте установить self
как UITextFieldDelegate
и как фактический textField delegate
,
(Спасибо Ammagrammer, это просто более короткий ответ с использованием блоков для анимации)
У меня была та же проблема, и я обнаружил, что GTKeyboardHelper - это легкий выход.
После перетаскивания рамки в вашем проекте, включите заголовочный файл. Загрузите и откройте пример проекта, затем перетащите объект "Помощник по клавиатуре" из раздела объектов в XIB в раздел объектов в конструкторе интерфейса вашего проекта.
Перетащите все свои представления, чтобы стать детьми "Помощника по клавиатуре".
Пожалуйста, посмотрите на мой комментарий в этом:
Я полагаю, что в более новых версиях iOS (6.1+, возможно, даже раньше) базовое представление, по крайней мере для UITableView, автоматически сжимается при всплывающей клавиатуре. Таким образом, вам нужно только сделать текстовое поле видимым в этом представлении. В init
:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
затем:
- (void)keyboardWasShown:(NSNotification*)notification
{
// Scroll the text field into view so it's not under the keyboard.
CGRect rect = [self.tableView convertRect:inputView.bounds fromView:inputView];
[self.tableView scrollRectToVisible:rect animated:YES];
}
В дополнение к решению Amagrammer, если вы используете cocos2d в портретном режиме, измените эту строку:
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
к этому:
[CCDirector sharedDirector].openGLView.frame = CGRectOffset([CCDirector sharedDirector].openGLView.frame, movement, 0);
Если вы используете cocos2d в ландшафтном режиме, внесите вышеуказанные изменения и переключите up
значения в textFieldDidBeginEditing:
а также textFieldDidEndEditing:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[self animateTextField:textField up:NO];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
[self animateTextField:textField up:YES];
}
У меня есть что-то еще, если хотите. Дело в том, что вы хотите установить центр вашего UIView на текстовое поле, которое вы редактируете.
Перед этим вам нужно сохранить INITIAL_CENTER как CGPoint из self.view.center и INITIAL_VIEW как CGRect из self.view.frame в свойстве const.
Вы можете создать такой метод:
- (void) centerOn: (CGRect) fieldFrame {
// Set up the center by taking the original view center
CGPoint center = CGPointMake(INITIAL_CENTER.x,
INITIAL_CENTER.y - ((fieldFrame.origin.y + fieldFrame.size.height/2) - INITIAL_CENTER.y));
[UIView beginAnimations:@"centerViewOnField" context:nil];
[UIView setAnimationDuration:0.50];
if (CGRectEqualToRect(fieldFrame,INITIAL_VIEW)) {
self.view.frame = INITIAL_VIEW;
[self.view setCenter:INITIAL_CENTER];
} else {
[self.view setCenter:center];
}
[UIView commitAnimations];
}
Затем в UITextFieldDelegate вам нужно вызвать centerOn:(CGRect) следующими методами:
textFieldDidBeginEditing: (UITextField *) с, в качестве параметра, рамкой текстового поля, на котором вы хотите центрироваться.
И вы должны вызвать его в обработчике событий, где вы закрываете клавиатуру,
textFieldDidEndEditing: (UITextField *) может быть одним из способов сделать это, поместив INITIAL_VIEW в качестве параметра centerOn:(CGRect).
Перетащите рамки, которые я использую в своих проектах. Поддерживает автоматическое увольнение при нажатии за пределами первого респондента или при прокрутке.
Как вы справляетесь с ситуацией, когда клавиатура поднята, а размер кадра изменен с помощью анимации и прокручен, чтобы текстовое поле не закрывалось, оттуда, когда я выбираю другое текстовое поле (все еще редактируя первое текстовое поле), как мне не воспроизводить анимацию снова и просто прокрутите немного дальше, если это необходимо? Проблема заключается в воспроизведении всей анимации, когда это не нужно. Спасибо
https://github.com/ZulwiyozaPutra/Shift-Keyboard-Example Я надеюсь, что это решение помогло. Все они написаны на Swift 3.
//
// ViewController.swift
// Shift Keyboard Example
//
// Created by Zulwiyoza Putra on 11/23/16.
// Copyright © 2016 Zulwiyoza Putra. All rights reserved.
//
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
//connecting textfield from storyboard
@IBOutlet weak var textField: UITextField!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
subscribeToKeyboardNotifications()
}
override func viewDidAppear(_ animated: Bool) {
self.textField.delegate = self
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
unsubscribeFromKeyboardNotifications()
}
//Hide keyboard after finished editing
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
//Setup view before keyboard appeared
func keyboardWillAppear(_ notification:Notification) {
view.frame.origin.y = 0 - getKeyboardHeight(notification)
}
//Setup view before keyboard disappeared
func keyboardWillDisappear(_ notification: Notification) {
view.frame.origin.y = 0
}
//Getting keyboard height
func getKeyboardHeight(_ notification:Notification) -> CGFloat {
let userInfo = notification.userInfo
let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue // of CGRect
return keyboardSize.cgRectValue.height
}
//Subscribing to notifications to execute functions
func subscribeToKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(_:)), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(_:)), name: .UIKeyboardWillHide, object: nil)
}
//Unsubscribing from notifications
func unsubscribeFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
}