Как прокручивать просмотр, когда появляется клавиатура?
Я знаю, что этот вопрос задавали снова и снова, но, похоже, для меня ничего не работает. Большинство решений вокруг довольно устарели, а остальные - невероятно огромные блоки кода, которые в десять раз больше, чем собственно кодирование проектов. У меня есть несколько UITextFields, выстроенных вертикально, но когда клавиатура запускает для редактирования, она закрывает текстовое поле. Мне было интересно, есть ли простой новичок, чтобы прокрутить представление вверх, а затем отступить, когда начинается и заканчивается редактирование?
Спасибо.
Ответы
Ответ 1
Я разработал решения, которые работают со списком прокрутки и без прокрутки с помощью уведомления клавиатуры и обнаружения текущего первого ответчика, но иногда я использую это тривиальное решение: простой способ - обнаружить открытую клавиатуру через текстовое поле делегата textViewDidBeginEditing:
и переместить весь вид вверх. Самый простой способ сделать это - это что-то вроде изменения self.view.bounds.origin.y
-100 (или что-то еще). Используйте соответствующий метод textViewShouldEndEditing:
, чтобы установить его на противоположное, что в этом случае равно 100. Изменение bounds
является относительной процедурой. После его изменения кадр перемещается, но начало координат по-прежнему равно нулю.
Ответ 2
Поскольку я нашел его, я использую TPKeyboardAvoiding - https://github.com/michaeltyson/TPKeyboardAvoiding.
Он отлично работает и очень прост в настройке:
- Добавить
UIScrollView
в ваш контроллер просмотра xib
- Установите класс представления прокрутки в
TPKeyboardAvoidingScrollView
(все еще в xib, через инспектор идентификации)
- Поместите все элементы управления в это представление прокрутки
Вы также можете создать его программно, если хотите.
Существует класс для той же потребности внутри UITableViewController
; это необходимо только в том случае, если вы поддерживаете версию iOS ниже 4.3.
Ответ 3
@BenLu и другие пользователи, которые сталкиваются с проблемой функции, никогда не получают вызов по следующей причине:
Поскольку функция делегата inbuild bydefaults возвращает void вместо BOOL, это должно выглядеть следующим образом:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGRect frame = self.view.frame;
frame.origin.y = -100;
[self.view setFrame:frame];
[UIView commitAnimations];
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGRect frame = self.view.frame;
frame.origin.y = 100;
[self.view setFrame:frame];
[UIView commitAnimations];
}
Ответ 4
Я потратил некоторое время на эту проблему и собрал код для создания одного окончательного решения. Моя проблема связана с прокруткой UITableView и открытием/закрытием клавиатуры.
В вашем классе ячейки вам понадобятся два частичных метода:
void EditingBegin(UITextField sender)
{
// Height of tallest cell, you can ignore this!
float tableMargin = 70.0f;
float tableHeight = _tableView.Frame.Size.Height;
float keyBoardHeight = KeyboardHeight();
NSIndexPath[] paths = this._tableView.IndexPathsForVisibleRows;
RectangleF rectLast = this._tableView.RectForSection(paths[paths.Length - 1].Section);
RectangleF rectFirst = this._tableView.RectForSection(paths[0].Section);
float lastCellY = rectLast.Y - rectFirst.Y;
if (lastCellY > tableHeight - keyBoardHeight)
{
float diff = lastCellY - (tableHeight - tableMargin - keyBoardHeight);
this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, diff, 0.0f);
}
float cellPosition = this._tableView.RectForSection(this._section).Y;
if (cellPosition > tableHeight - keyBoardHeight)
{
if (this._tableView.ContentInset.Bottom == 0.0f)
{
float diff = cellPosition - (tableHeight - tableMargin - keyBoardHeight);
this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, diff, 0.0f);
}
else
{
this._tableView.ScrollToRow(NSIndexPath.FromItemSection(0, this._section), UITableViewScrollPosition.Middle, true);
}
}
}
partial void EditingEnd(UITextField sender)
{
UIView.BeginAnimations(null);
UIView.SetAnimationDuration(0.3f);
this._tableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, 0.0f, 0.0f);
UIView.CommitAnimations();
}
а затем в вашем классе контроллера контроллера:
public override void WillAnimateRotation(UIInterfaceOrientation toInterfaceOrientation, double duration)
{
base.WillAnimateRotation(toInterfaceOrientation, duration);
float bottom = this.TableView.ContentInset.Bottom;
if (bottom > 0.0f)
{
if (toInterfaceOrientation == UIInterfaceOrientation.Portrait || toInterfaceOrientation == UIInterfaceOrientation.PortraitUpsideDown)
{
bottom = bottom * UIScreen.MainScreen.Bounds.Width / UIScreen.MainScreen.Bounds.Height;
}
else
{
bottom = bottom * UIScreen.MainScreen.Bounds.Height / UIScreen.MainScreen.Bounds.Width;
}
UIEdgeInsets insets = this.TableView.ContentInset;
this.TableView.ContentInset = new UIEdgeInsets(0.0f, 0.0f, bottom, 0.0f);
}
}
Ответ 5
Если у вас есть UITableView
или UIScrollView
, лучше изменить значения для contentOffset
вместо внесения изменений в frame
.
Работа над Peter Answer, добавление этого метода в ваш класс прекрасно работает:
- (void)textViewDidBeginEditing:(UITextField *)textField {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.35f];
CGPoint offset = self.tableView.contentOffset;
offset.y += 200; // You can change this, but 200 doesn't create any problems
[self.tableView setContentOffset:offset];
[UIView commitAnimations];
}
Для этого не нужно добавлять метод textViewDidEndEditing
.
Мне не нужно это говорить, но для этого вам нужно26 > или UITextView
быть делегатом вашего контроллера.
Ответ 6
Начиная с ответа Питера, я разработал следующий подход в Swift 3.0 под iOS 10.1. Я делаю это для textView, поэтому я реализовал функции UITextViewDelegate textViewDidBeginEditing и textViewDidEndEditing, где я настраиваю границы представления. Как вы можете видеть, я устанавливаю значение начала Y для небольшого положительного числа для прокрутки вверх, а затем обратно в 0, чтобы вернуться в исходное положение.
Вот соответствующий код моего ViewController. Вам не нужно анимировать, но это добавляет приятный штрих.
func textViewDidBeginEditing(_ textView: UITextView)
{
if UIScreen.main.bounds.height < 568 {
UIView.animate(withDuration: 0.75, animations: {
self.view.bounds.origin.y = 60
})
}
}
func textViewDidEndEditing(_ textView: UITextView)
{
if UIScreen.main.bounds.height < 568 {
UIView.animate(withDuration: 0.75, animations: {
self.view.bounds.origin.y = 0
})
}
}
Ответ 7
У меня есть scrollview и 3 текстовых поля. У меня есть простой код из моего собственного приложения:
.h файл:
#import <UIKit/UIKit.h>
@interface AddContactViewController : UIViewController<UITextFieldDelegate, UIScrollViewDelegate>
@property (nonatomic, retain) NSDictionary *dict_contactDetail;
@property (nonatomic, retain) IBOutlet UILabel *lbl_name;
@property (nonatomic, retain) IBOutlet UITextField *txtField_tel;
@property (nonatomic, retain) IBOutlet UITextField *txtField_address;
@property (nonatomic, retain) IBOutlet UITextField *txtField_email;
@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
@end
.m file:
#import "AddContactViewController.h"
@interface AddContactViewController ()
@end
@implementation AddContactViewController
@synthesize dict_contactDetail;
@synthesize lbl_name, txtField_tel, txtField_email, txtField_address, scrollView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// NSLog(@"dict_contactDetail : %@", dict_contactDetail);
UIBarButtonItem * rightButton = [[UIBarButtonItem alloc] initWithTitle:@"Add" style:UIBarButtonSystemItemDone target:self action:@selector(addEmergencyContact:)];
self.navigationItem.rightBarButtonItem = rightButton;
lbl_name.text = [NSString stringWithFormat:@"%@ %@", [dict_contactDetail valueForKey:@"fname"], [dict_contactDetail valueForKey:@"lname"]];
txtField_tel.returnKeyType = UIReturnKeyDone;
txtField_email.returnKeyType = UIReturnKeyDone;
txtField_address.returnKeyType = UIReturnKeyDone;
}
-(void)addEmergencyContact:(id)sender
{
scrollView.frame = CGRectMake(0, 0, 320, 460);
}
#pragma mark - text field delegates
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if([textField isEqual:txtField_tel])
{
[scrollView setContentOffset:CGPointMake(0, 70)];
scrollView.frame = CGRectMake(0, 0, 320, 210);
}
if([textField isEqual:txtField_address])
{
[scrollView setContentOffset:CGPointMake(0, 140)];
scrollView.frame = CGRectMake(0, 0, 320, 210);
}
if([textField isEqual:txtField_email])
{
[scrollView setContentOffset:CGPointMake(0, 210)];
scrollView.frame = CGRectMake(0, 0, 320, 210);
}
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
scrollView.frame = CGRectMake(0, 0, 320, 460);
[textField resignFirstResponder];
return YES;
}
@end