Как прокрутить вид вверх при появлении клавиатуры? - PullRequest
37 голосов
/ 03 января 2012

Я знаю, что этот вопрос задавался снова и снова, но мне кажется, что ничего не работает.Большинство решений вокруг устарели, а остальные представляют собой невероятно огромные блоки кода, которые в десять раз больше, чем сами проекты.У меня есть несколько UITextFields, выстроенных вертикально, но когда клавиатура запускается для редактирования, она закрывает текстовое поле.Мне было интересно, есть ли простой способ для начинающих прокручивать представление вверх, а затем назад, когда редактирование начинается и заканчивается?

Ответы [ 7 ]

29 голосов
/ 03 января 2012

Я разработал решения, которые работают с представлениями с прокруткой и без прокрутки, используя уведомление клавиатуры и обнаружение текущего первого респондента, но иногда я использую это тривиальное решение: простой способ - обнаружить открывающую клавиатуру через текстовое поледелегировать метод textViewDidBeginEditing: и переместить весь вид вверх.Самый простой способ сделать это с помощью изменения значения self.view.bounds.origin.y на -100 (или как угодно).Используйте соответствующий метод textViewShouldEndEditing:, чтобы установить противоположное значение, в данном случае равное 100.Изменение bounds является относительной процедурой.После его изменения рамка перемещается, но начало координат по-прежнему равно нулю.

25 голосов
/ 03 января 2012

Поскольку я нашел его, я использую TPKeyboardAvoiding - https://github.com/michaeltyson/TPKeyboardAvoiding.

Он отлично работает и очень прост в настройке:

  • Добавьте UIScrollView в ваше представлениеКонтроллер xib
  • Установите класс представления прокрутки на TPKeyboardAvoidingScrollView (все еще в xib, через инспектор идентификации)
  • Поместите все свои элементы управления в это представление прокрутки

Вы также можете создать его программно, если хотите.


Внутри UITableViewController есть класс для такой же потребности;это необходимо только в том случае, если вы поддерживаете версию iOS ниже 4.3.

3 голосов
/ 19 ноября 2015

@ BenLu и другие пользователи, которые сталкиваются с проблемой этой функции, никогда не обращаются по следующей причине: Так как встроенная функция делегата 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];
}
1 голос
/ 22 августа 2013

Я потратил некоторое время на эту проблему и собрал куски кода, чтобы создать одно окончательное решение.Моя проблема была связана с прокруткой 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);
        }
    }  
0 голосов
/ 02 ноября 2016

Начиная с ответа Питера, я разработал следующий подход в 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
        })
    }
}
0 голосов
/ 01 августа 2014

Если у вас есть UITableView или UIScrollView, лучше изменить значения на contentOffset вместо внесения изменений в frame.

Работая над Peter's 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.


Мне не нужно это говорить, но чтобы это работало, ваш UITextField или UITextView должен быть делегатом вашего контроллера.

0 голосов
/ 22 октября 2012

У меня есть прокрутка и 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 файл:

#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
...