Làm cách nào để cuộn UIScrollView khi bàn phím xuất hiện?


107

Tôi đang gặp sự cố với mã của mình. Tôi đang cố gắng di chuyển UIScrollViewkhi tôi đang chỉnh sửa một tài UITextFieldliệu sẽ được ẩn bởi cửa sổ bật lên trên bàn phím.

Tôi đang di chuyển khung chính ngay bây giờ vì tôi không biết cách 'cuộn lên' trong mã. Vì vậy, tôi đã làm một chút mã, nó hoạt động tốt nhưng khi tôi chỉnh sửa một UItextfield và tôi chuyển sang một trường khác UITextFieldmà không cần nhấn vào nút 'quay lại', chế độ xem chính sẽ đi xa.

Tôi đã thực hiện NSLog()với các biến size, distance và textFieldRect.origin.y của mình như bạn có thể thấy bên dưới. Khi tôi đặt hai mã UITextFieldở cùng một vị trí (nguồn gốc y) và tôi thực hiện 'chuyển đổi' cụ thể này (wihtout nhấn quay lại), tôi nhận được các số giống nhau, trong khi mã của tôi hoạt động tốt cho lần UITextFieldchỉnh sửa đầu tiên nhưng không hoạt động tốt cho lần chỉnh sửa thứ hai.

Kiểm tra cái này:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
{
    int size;
    CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
    size = textFieldRect.origin.y + textFieldRect.size.height;
    if (change == FALSE)
    {
        size = size - distance;
    }
    if (size < PORTRAIT_KEYBOARD_HEIGHT)
    {
        distance = 0;
    }
    else if (size > PORTRAIT_KEYBOARD_HEIGHT)
    {
        distance = size - PORTRAIT_KEYBOARD_HEIGHT + 5; // +5 px for more visibility
    }
    NSLog(@"origin %f", textFieldRect.origin.y);
    NSLog(@"size %d", size);
    NSLog(@"distance %d", distance);
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y -= distance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
    change = FALSE;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    change = TRUE;
    CGRect viewFrame = self.view.frame;
    viewFrame.origin.y += distance;
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
    [self.view setFrame:viewFrame];
    [UIView commitAnimations];
}

Bất kỳ ý tưởng?

Câu trả lời:


204

Cách đề nghị từ Apple là thay đổi contentInsetcủa UIScrollView. Đó là một giải pháp rất thanh lịch, bởi vì bạn không cần phải gây rối với contentSize. Mã sau được sao chép từ Hướng dẫn lập trình bàn phím , nơi giải thích cách xử lý vấn đề này. Bạn nên có một cái nhìn vào nó.

// 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 application might not need or want this behavior.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;
    if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y-kbSize.height);
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent    
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}

Phiên bản Swift:

func registerForKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardAppear(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisappear(_:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

// Don't forget to unregister when done
deinit {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

@objc func onKeyboardAppear(_ notification: NSNotification) {
    let info = notification.userInfo!
    let rect: CGRect = info[UIKeyboardFrameBeginUserInfoKey] as! CGRect
    let kbSize = rect.size

    let insets = UIEdgeInsetsMake(0, 0, kbSize.height, 0)
    scrollView.contentInset = insets
    scrollView.scrollIndicatorInsets = insets

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your application might not need or want this behavior.
    var aRect = self.view.frame;
    aRect.size.height -= kbSize.height;

    let activeField: UITextField? = [addressTextView, servicePathTextView, usernameTextView, passwordTextView].first { $0.isFirstResponder }
    if let activeField = activeField {
        if !aRect.contains(activeField.frame.origin) {
            let scrollPoint = CGPoint(x: 0, y: activeField.frame.origin.y-kbSize.height)
            scrollView.setContentOffset(scrollPoint, animated: true)
        }
    }
}

@objc func onKeyboardDisappear(_ notification: NSNotification) {
    scrollView.contentInset = UIEdgeInsets.zero
    scrollView.scrollIndicatorInsets = UIEdgeInsets.zero
}

2
À, được rồi. Sry, tôi không hiểu rằng bạn đang nói về phần cuộn. Có, ActiveField chỉ là một trình giữ chỗ cho thuộc tính UITextField của bạn. Vì vậy, hãy thay thế nó và thử lại. Bạn không cần phải thay đổi kích thước, nếu không textField sẽ thực sự lớn hơn về chiều cao.
Masa

2
Bạn thực sự không muốn ghi đè contentInsets.top hiện có, điều này nếu bạn làm như vậy, chế độ xem của bạn có thể trượt lên phía sau Điều hướng.
SwiftArchitect

6
github.com/michaeltyson/TPKeyboardAvoiding Đây là siêu giải pháp đơn giản
Pramod

2
Thật tốt khi chuyển đổi activeField.framesang khung tương đối vì activeFieldkhông cần phải là một đứa trẻ ngay lập tức self.view. Mã cập nhật sẽ trông giống như sau: CGRect aRect = self.view.frame; aRect.size.height -= kbSize.height; CGRect relativeFieldFrame = [activeField convertRect:activeField.frame toView:self.view]; if (!CGRectContainsPoint(aRect, relativeFieldFrame.origin) ) { CGPoint scrollPoint = CGPointMake(0.0, relativeFieldFrame.origin.y-kbSize.height); [self.mainView.scrollView setContentOffset:scrollPoint animated:YES]; }
paxx

4
Tôi đã phải sử dụng UIKeyboardFrameEndUserInfoKeykhóa trên iOS 11 vì khóa UIKeyboardFrameBeginUserInfoKeythường cho tôi chiều cao bằng 0.
Collin

66

Tôi vừa triển khai điều này với Swift 2.0 cho iOS9 trên Xcode 7 (beta 6), hoạt động tốt ở đây.

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    registerKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo!
    let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size
    let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    var viewRect = view.frame
    viewRect.size.height -= keyboardSize.height
    if CGRectContainsPoint(viewRect, textField.frame.origin) {
        let scrollPoint = CGPointMake(0, textField.frame.origin.y - keyboardSize.height)
        scrollView.setContentOffset(scrollPoint, animated: true)
    }
}

func keyboardWillHide(notification: NSNotification) {
    scrollView.contentInset = UIEdgeInsetsZero
    scrollView.scrollIndicatorInsets = UIEdgeInsetsZero
}

Đã chỉnh sửa cho Swift 3

Có vẻ như bạn chỉ cần đặt contentInsetscrollIndicatorInsetvới Swift 3, quá trình cuộn / contentOffset được thực hiện tự động ..

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    registerKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self,
                                         selector: #selector(keyboardWillShow(notification:)),
                                         name: NSNotification.Name.UIKeyboardWillShow,
                                         object: nil)
    NotificationCenter.default.addObserver(self,
                                         selector: #selector(keyboardWillHide(notification:)),
                                         name: NSNotification.Name.UIKeyboardWillHide,
                                         object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
    let keyboardSize = keyboardInfo.cgRectValue.size
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

func keyboardWillHide(notification: NSNotification) {
    scrollView.contentInset = .zero
    scrollView.scrollIndicatorInsets = .zero
}

Bạn có thể giải thích mã của bạn được không? Tôi có hai trường văn bản và khi tôi chỉnh sửa trường đầu tiên, trường này sẽ cuộn xuống trong khi trường văn bản thứ hai cuộn lên.
CÓ THỂ

Trên iPad, điều này sẽ di chuyển chế độ xem cuộn xuống thay vì lên trên. Bất kỳ ý tưởng những gì đang xảy ra ở đó?
Justin Vallely

2
@can the textField được tham chiếu là một biến bạn đặt cho bộ điều khiển chế độ xem của mình dựa trên phản hồi đầu tiên hiện tại
Johannes

Tôi tự hỏi tại sao Apple lại tự cho mình cuộn trường văn bản hiện hoạt phía trên bàn phím cho chúng ta.
paulvs

2
trong nhanh chóng 4 đưa @objc về phương pháp keyboardWillShow và keyboardWillHide
Ronaldo Albertini

16

Tất cả các câu trả lời ở đây dường như quên mất khả năng cảnh quan. Nếu bạn muốn điều này hoạt động khi thiết bị được xoay sang chế độ xem ngang, thì bạn sẽ gặp phải vấn đề.

Bí quyết ở đây là mặc dù khung nhìn nhận biết được hướng nhưng bàn phím thì không. Điều này có nghĩa là trong Khổ ngang, chiều rộng bàn phím thực sự là chiều cao của nó và ngược lại.

Để sửa đổi cách thay đổi nội dung được đề xuất của Táo khuyết và hỗ trợ hướng ngang, tôi khuyên bạn nên sử dụng như sau:

// 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
{
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight ) {
        CGSize origKeySize = keyboardSize;
        keyboardSize.height = origKeySize.width;
        keyboardSize.width = origKeySize.height;
    }
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0);
    scroller.contentInset = contentInsets;
    scroller.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your application might not need or want this behavior.
    CGRect rect = scroller.frame;
    rect.size.height -= keyboardSize.height;
    NSLog(@"Rect Size Height: %f", rect.size.height);

    if (!CGRectContainsPoint(rect, activeField.frame.origin)) {
        CGPoint point = CGPointMake(0, activeField.frame.origin.y - keyboardSize.height);
        NSLog(@"Point Height: %f", point.y);
        [scroller setContentOffset:point animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent    
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}

Phần cần chú ý ở đây là:

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight ) {
    CGSize origKeySize = keyboardSize;
    keyboardSize.height = origKeySize.width;
    keyboardSize.width = origKeySize.height;
}

What is does, là phát hiện hướng thiết bị đang ở. Nếu nó nằm ngang, nó sẽ 'hoán đổi' các giá trị chiều rộng và chiều cao của biến keyboardSize để đảm bảo rằng các giá trị chính xác đang được sử dụng trong mỗi hướng.


tốt, bạn có thể muốn điều chỉnh thêm (giảm) phần dưới cùng của nội dung trên mỗi stackoverflow.com/questions/25704513/… này trong trường hợp con lăn chiếm toàn bộ chiều cao của màn hình UIEdgeInsetsMake (0,0, 0,0, kbSize.height - ([Màn hình chính UIScreen] .bounds.size.height - cvf.origin.y - cvf.size.height), 0.0); nơi CVF là scroller.frame
Anton Tropashko

if (định hướng == UIInterfaceOrientationLandscapeLeft || hướng == UIInterfaceOrientationLandscapeRight )
schmidt9

13

Giải pháp Swift 4 :

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    registerKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self,
                                         selector: #selector(keyboardWillShow(notification:)),
                                         name: NSNotification.Name.UIKeyboardWillShow,
                                         object: nil)
    NotificationCenter.default.addObserver(self,
                                         selector: #selector(keyboardWillHide(notification:)),
                                         name: NSNotification.Name.UIKeyboardWillHide,
                                         object: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardWillShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
    let keyboardSize = keyboardInfo.cgRectValue.size
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

@objc func keyboardWillHide(notification: NSNotification) {
    scrollView.contentInset = .zero
    scrollView.scrollIndicatorInsets = .zero
}

3
đã hoạt động gần hết, chỉ cần thay đổi UIKeyboardFrameBeginUserInfoKeythànhUIKeyboardFrameEndUserInfoKey
Fonix

Tôi áp dụng mã này trong UITableView. Nhưng TableView không cuộn lên ngay lập tức.
Shawn Baek

3
UIKeyboardWillShow, UIKeyboardWillHideUIKeyboardFrameBeginUserInfoKeyđã được đổi tên thành UIResponder.keyboardWillShowNotification, UIResponder.keyboardWillHideNotificationUIResponder.keyboardFrameBeginUserInfoKey.
Aaron Brager

9

Đối với công cụ này, không cần nhiều mã, nó rất dễ dàng như mã dưới đây: -

tất cả văn bản của bạn được soạn thảo trong UIScrollview từ nib như hình ảnh này: -

nhập mô tả hình ảnh ở đây

YourViewController.h

@interface cntrInquiryViewController : UIViewController<UIScrollViewDelegate,UITextFieldDelegate>
{
     IBOutlet UITextField *txtName;
     IBOutlet UITextField *txtEmail;
     IBOutlet UIScrollView *srcScrollView;
}
@end

kết nối IBOutlet từ nib và cũng Kết nối từng đại biểu của UItextfiled và đại biểu scrollview từ NIB

-(void)viewWillAppear:(BOOL)animated
{
    srcScrollView.contentSize = CGSizeMake(320, 500);

    [super viewWillAppear:YES];
}


-(void)textFieldDidBeginEditing:(FMTextField *)textField
{
    [srcScrollView setContentOffset:CGPointMake(0,textField.center.y-140) animated:YES];//you can set your  y cordinate as your req also
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
     [textField resignFirstResponder];
     [srcScrollView setContentOffset:CGPointMake(0,0) animated:YES];


    return YES;
}

LƯU Ý nếu đại biểu được gửi Văn bản không được kết nối thì không có phương pháp nào hoạt động, vui lòng đảm bảo rằng tất cả iBOulate và đại biểu được kết nối chính xác


5
Đây là một cách tiếp cận rất cũ và không nên được sử dụng. Nó dựa trên các giá trị được mã hóa và các giả định không còn phù hợp nữa.
Womble

@Womble Có nhiều câu trả lời cũ nhưng phù hợp với câu hỏi tại thời điểm đó (Khi câu hỏi được hỏi). Vì vậy, Đừng bỏ phiếu mà không có lý do.
Ashish Kakkad

7

Đề xuất của Apple được mã hóa trong Swift + Sử dụng UIScrollView với Bố cục Tự động trong iOS (dựa trên các liên kết sau: liên kết 1 , liên kết 2 , liên kết 3 ):

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var t1: UITextField!
    @IBOutlet var t2: UITextField!
    @IBOutlet var t3: UITextField!
    @IBOutlet var t4: UITextField!

    @IBOutlet var srcScrollView: UIScrollView!

    @IBOutlet var contentView: UIView!

    var contentViewCoordinates: CGPoint!

    override func viewDidLoad() {

        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        /* Constraints on content view */
        let leftConstraint = NSLayoutConstraint(item:self.contentView,
            attribute:NSLayoutAttribute.Leading,
            relatedBy:NSLayoutRelation.Equal,
            toItem:self.view,
            attribute:NSLayoutAttribute.Left,
            multiplier:1.0,
            constant:0)
        self.view.addConstraint(leftConstraint)

        let rightConstraint = NSLayoutConstraint(item:self.contentView,
            attribute:NSLayoutAttribute.Trailing,
            relatedBy:NSLayoutRelation.Equal,
            toItem:self.view,
            attribute:NSLayoutAttribute.Right,
            multiplier:1.0,
            constant:0)
        self.view.addConstraint(rightConstraint)

        /* Tap gesture */
        let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "hideKeyboard")
        // prevents the scroll view from swallowing up the touch event of child buttons
        tapGesture.cancelsTouchesInView = false
        srcScrollView.addGestureRecognizer(tapGesture)

        /* Save content view coordinates */
        contentViewCoordinates = contentView.frame.origin
    }

    func hideKeyboard() {
        t1.resignFirstResponder()
        t2.resignFirstResponder()
        t3.resignFirstResponder()
        t4.resignFirstResponder()
    }

    var activeField: UITextField?

    func textFieldDidBeginEditing(textField: UITextField) {
        activeField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        activeField = nil
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        let center = NSNotificationCenter.defaultCenter()
        center.addObserver(self, selector: "keyboardOnScreen:", name: UIKeyboardDidShowNotification, object: nil)
        center.addObserver(self, selector: "keyboardOffScreen:", name: UIKeyboardDidHideNotification, object: nil)
    }

    func keyboardOnScreen(notification: NSNotification){
        // Retrieve the size and top margin (inset is the fancy word used by Apple) 
        // of the keyboard displayed.
        let info: NSDictionary  = notification.userInfo!
        let kbSize = info.valueForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue().size
        let contentInsets: UIEdgeInsets  = UIEdgeInsetsMake(0.0, 0.0, kbSize!.height, 0.0)

        srcScrollView.contentInset = contentInsets
        srcScrollView.scrollIndicatorInsets = contentInsets

        var aRect: CGRect = self.view.frame
        aRect.size.height -= kbSize!.height
        //you may not need to scroll, see if the active field is already visible
        if (CGRectContainsPoint(aRect, activeField!.frame.origin) == false) {
            let scrollPoint:CGPoint = CGPointMake(0.0, activeField!.frame.origin.y - kbSize!.height)
            srcScrollView.setContentOffset(scrollPoint, animated: true)
        }
    }

//    func keyboardOnScreen(aNotification: NSNotification) {
//        let info: NSDictionary  = aNotification.userInfo!
//        let kbSize = info.valueForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue().size
//        
//        var bkgndRect: CGRect! = activeField?.superview?.frame
//        
//        bkgndRect.size.height += kbSize!.height
//        
//        activeField?.superview?.frame = bkgndRect
//        
//        srcScrollView.setContentOffset(CGPointMake(0.0, activeField!.frame.origin.y - kbSize!.height), animated: true)
//    }

    func keyboardOffScreen(notification: NSNotification){
        let contentInsets:UIEdgeInsets = UIEdgeInsetsZero

        srcScrollView.contentInset = contentInsets
        srcScrollView.scrollIndicatorInsets = contentInsets

        self.srcScrollView.setContentOffset(CGPointMake(0, -self.view.frame.origin.y/2), animated: true)
    }

}

Sau một ngày làm việc chăm chỉ, tôi đã cố gắng thực hiện đề xuất của apple trong Swift + sửa đổi mã của họ một chút + điều chỉnh nó để nó đáp ứng trên tất cả các thiết bị của Apple, vì vậy trước khi bỏ phiếu, vui lòng cho tôi biết lý do. Không có mã nào ở trên hoạt động chính xác trên mọi thiết bị và mọi tình huống bố cục. Tuy nhiên của tôi không hoạt động trên tất cả các thiết bị apple và các tình huống bố cục.
King-Wizard

Tôi cho rằng bạn cũng cần hủy đăng ký khỏi trung tâm thông báo trước khi chế độ xem chết?
Cyril Duchon-Doris

4

Điều duy nhất tôi muốn cập nhật trong mã Apple là phương thức keyboardWillBeHidden: để cung cấp quá trình chuyển đổi mượt mà.

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    [UIView animateWithDuration:0.4 animations:^{
        self.scrollView.contentInset = contentInsets;
    }];
    self.scrollView.scrollIndicatorInsets = contentInsets;

}

4

Đây là câu trả lời tương thích với Swift 3 , cũng sẽ hoạt động với bộ điều khiển chế độ xem trong bộ điều khiển điều hướng - vì chúng sẽ thay đổi thuộc tính chế độ xem cuộn contentInset.top.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    self.registerKeyboardNotifications()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.unregisterKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.keyboardDidShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(LoginViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func unregisterKeyboardNotifications() {
    NotificationCenter.default.removeObserver(self)
}


func keyboardDidShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardInfo = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
    let keyboardSize = keyboardInfo.cgRectValue.size

    // Get the existing contentInset for the scrollView and set the bottom property to be the height of the keyboard
    var contentInset = self.scrollView.contentInset
    contentInset.bottom = keyboardSize.height

    self.scrollView.contentInset = contentInset
    self.scrollView.scrollIndicatorInsets = contentInset
}

func keyboardWillHide(notification: NSNotification) {
    var contentInset = self.scrollView.contentInset
    contentInset.bottom = 0

    self.scrollView.contentInset = contentInset
    self.scrollView.scrollIndicatorInsets = UIEdgeInsets.zero
}

4

Giải pháp Swift 4.2 có tính đến chiều cao có thể của UIToolbar và UITabBar.

private func setupKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIControl.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIControl.keyboardWillHideNotification, object: nil)
}

@objc func keyboardWillShow(_ notification: Notification) {
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.size

    let tabbarHeight = tabBarController?.tabBar.frame.size.height ?? 0
    let toolbarHeight = navigationController?.toolbar.frame.size.height ?? 0
    let bottomInset = keyboardSize.height - tabbarHeight - toolbarHeight

    scrollView.contentInset.bottom = bottomInset
    scrollView.scrollIndicatorInsets.bottom = bottomInset
}

@objc func keyboardWillHide(_ notification: Notification) {
    scrollView.contentInset = .zero
    scrollView.scrollIndicatorInsets = .zero
}

Và, nếu bạn đang nhắm mục tiêu <iOS 9, bạn phải hủy đăng ký trình quan sát tại một số điểm (cảm ơn Joe )


Nó có tính đến không gian dưới thanh tab trên iPhone X không? Đó là nơi sọc iOS xuất hiện.
lướt ván

iOS9 + bạn không cần phải xóa trình quan sát developer.apple.com/documentation/foundation/notificationcenter/…
Joe

Vâng bạn đã đúng. Tôi đã cập nhật câu trả lời cho phù hợp.
JanApotheker

3

Tôi thấy các câu trả lời trên đã lỗi thời. Cũng không hoàn hảo khi cuộn.

Đây là một phiên bản nhanh.

Nó sẽ cuộn ngay bên dưới textField, không có dung lượng trống. Và nó sẽ khôi phục lại như lần đầu xuất hiện.

//add observer
override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ARVHttpPlayVC.keyboardDidShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ARVHttpPlayVC.keyboardDidHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}

func keyboardDidShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo!
    let keyboardSize = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)!.CGRectValue.size
    let difference = keyboardSize.height - (self.view.frame.height - inputTextField.frame.origin.y - inputTextField.frame.size.height)
    if difference > 0 {
        var contentInset:UIEdgeInsets = self.scrollView.contentInset
        contentInset.bottom = difference
        self.scrollView.contentInset = contentInset

        let scrollPoint = CGPointMake(0, difference)
        self.scrollView.setContentOffset(scrollPoint, animated: true)
    }

}

func keyboardDidHide(notification: NSNotification) {
    let contentInset:UIEdgeInsets = UIEdgeInsetsZero
    self.scrollView.contentInset = contentInset
}

//remove observer
deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

Nó có cuộn lên một chút, nhưng không đủ để hiển thị toàn bộ chiều cao. Tôi đang sử dụng Swift 2.3 và thử nghiệm nó trên iPhone 5.
KMC

2

Đây là những gì tôi đã được sử dụng. Nó đơn giản và nó hoạt động tốt.

#pragma mark - Scrolling

-(void)scrollElement:(UIView *)view toPoint:(float)y
{
    CGRect theFrame = view.frame;
    float orig_y = theFrame.origin.y;
    float diff = y - orig_y;

    if (diff < 0) 
        [self scrollToY:diff];

    else 
        [self scrollToY:0];
}

-(void)scrollToY:(float)y
{
    [UIView animateWithDuration:0.3f animations:^{
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
        self.view.transform = CGAffineTransformMakeTranslation(0, y);
    }];
}

Sử dụng lệnh UITextFieldgọi ủy quyền textFieldDidBeginEditing:để chuyển chế độ xem của bạn lên trên, đồng thời thêm người quan sát thông báo để chế độ xem trở lại bình thường khi bàn phím ẩn:

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

    if (self.view.frame.origin.y == 0)
        [self scrollToY:-90.0];  // y can be changed to your liking

}

-(void)keyboardWillHide:(NSNotification*)note
{
    [self scrollToY:0];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

2

Đây là mã cuối cùng với những cải tiến trong Swift

    //MARK: UITextFieldDelegate
func textFieldDidBeginEditing(textField: UITextField!) {    //delegate method
    self.textField = textField
}

func textFieldShouldReturn(textField: UITextField!) -> Bool {   //delegate method
    textField.resignFirstResponder()
    return true
}

//MARK: Keyboard handling
override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    unregisterKeyboardNotifications()
}

func registerKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UCProfileSettingsViewController.keyboardDidShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UCProfileSettingsViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

func unregisterKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardDidShow(notification: NSNotification) {
    let userInfo: NSDictionary = notification.userInfo!
    let keyboardSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue.size
    let contentInsets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    var viewRect = self.view.frame
    viewRect.size.height -= keyboardSize.height
    let relativeFieldFrame: CGRect = textField.convertRect(textField.frame, toView: self.view)
    if CGRectContainsPoint(viewRect, relativeFieldFrame.origin) {
        let scrollPoint = CGPointMake(0, relativeFieldFrame.origin.y - keyboardSize.height)
        scrollView.setContentOffset(scrollPoint, animated: true)
    }

}

func keyboardWillHide(notification: NSNotification) {
    scrollView.contentInset = UIEdgeInsetsZero
    scrollView.scrollIndicatorInsets = UIEdgeInsetsZero
}

1
Tôi nghĩ logic của bạn bị đảo ngược - bạn chỉ muốn cuộn nếu CGRectContainsPoint KHÔNG chứa tương đốiFieldFrame.origin.
Rayfleck,

2

Một trong những giải pháp đơn giản nhất là sử dụng giao thức sau:

protocol ScrollViewKeyboardDelegate: class {
    var scrollView: UIScrollView? { get set }

    func registerKeyboardNotifications()
    func unregisterKeyboardNotifications()
}

extension ScrollViewKeyboardDelegate where Self: UIViewController {
    func registerKeyboardNotifications() {
        NotificationCenter.default.addObserver(
            forName: UIResponder.keyboardWillChangeFrameNotification,
            object: nil,
            queue: nil) { [weak self] notification in
                self?.keyboardWillBeShown(notification)
        }

        NotificationCenter.default.addObserver(
            forName: UIResponder.keyboardWillHideNotification,
            object: nil,
            queue: nil) { [weak self] notification in
                self?.keyboardWillBeHidden(notification)
        }
    }

    func unregisterKeyboardNotifications() {
        NotificationCenter.default.removeObserver(
            self,
            name: UIResponder.keyboardWillChangeFrameNotification,
            object: nil
        )
        NotificationCenter.default.removeObserver(
            self,
            name: UIResponder.keyboardWillHideNotification,
            object: nil
        )
    }

    func keyboardWillBeShown(_ notification: Notification) {
        let info = notification.userInfo
        let key = (info?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)
        let aKeyboardSize = key?.cgRectValue

        guard let keyboardSize = aKeyboardSize,
            let scrollView = self.scrollView else {
                return
        }

        let bottomInset = keyboardSize.height
        scrollView.contentInset.bottom = bottomInset
        scrollView.scrollIndicatorInsets.bottom = bottomInset
        if let activeField = self.view.firstResponder {
            let yPosition = activeField.frame.origin.y - bottomInset
            if yPosition > 0 {
                let scrollPoint = CGPoint(x: 0, y: yPosition)
                scrollView.setContentOffset(scrollPoint, animated: true)
            }
        }
    }

    func keyboardWillBeHidden(_ notification: Notification) {
        self.scrollView?.contentInset = .zero
        self.scrollView?.scrollIndicatorInsets = .zero
    }
}

extension UIView {
    var firstResponder: UIView? {
        guard !isFirstResponder else { return self }
        return subviews.first(where: {$0.firstResponder != nil })
    }
}

Khi bạn muốn sử dụng giao thức này, bạn chỉ cần tuân theo nó và chỉ định chế độ xem cuộn trong bộ điều khiển của bạn như sau:

class MyViewController: UIViewController {
      @IBOutlet var scrollViewOutlet: UIScrollView?
      var scrollView: UIScrollView?

      public override func viewDidLoad() {
        super.viewDidLoad()

        self.scrollView = self.scrollViewOutlet
        self.scrollView?.isScrollEnabled = true
        self.registerKeyboardNotifications()
    }

    extension MyViewController: ScrollViewKeyboardDelegate {}

    deinit {
       self.unregisterKeyboardNotifications()
    }

}

1

Tôi sẽ làm điều đó như thế này. Đó là rất nhiều mã nhưng nó đảm bảo rằng textField hiện đang được lấy nét được căn giữa theo chiều dọc trong 'không gian có sẵn':

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];
    NSValue *keyBoardEndFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGSize keyboardSize = [keyBoardEndFrame CGRectValue].size;
    self.keyboardSize = keyboardSize;

    [self adjustScrollViewOffsetToCenterTextField:self.currentTextField];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    self.keyboardSize = CGSizeZero;
}

- (IBAction)textFieldGotFocus:(UITextField *)sender {
    sender.inputAccessoryView = self.keyboardAccessoryView;
    self.currentTextField = sender;
    [self adjustScrollViewOffsetToCenterTextField:sender];    
}

- (void)adjustScrollViewOffsetToCenterTextField:(UITextField *)textField
{
    CGRect textFieldFrame = textField.frame;
    float keyboardHeight = MIN(self.keyboardSize.width, self.keyboardSize.height);

    float visibleScrollViewHeight = self.scrollView.frame.size.height - keyboardHeight;
    float offsetInScrollViewCoords = (visibleScrollViewHeight / 2) - (textFieldFrame.size.height / 2);

    float scrollViewOffset = textFieldFrame.origin.y - offsetInScrollViewCoords;


    [UIView animateWithDuration:.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        self.scrollView.contentOffset = CGPointMake(self.scrollView.contentOffset.x, scrollViewOffset);
    }completion:NULL];

}

you'll need these two properties in your @interface...
@property (nonatomic, assign) CGSize keyboardSize;
@property (nonatomic, strong) UITextField *currentTextField;

Lưu ý rằng - (IBAction)textFieldGotFocus:hành động được kết nối với mọi textField'sDidBeginEditing trạng thái .

Ngoài ra, sẽ tốt hơn một chút nếu lấy thời lượng hoạt ảnh từ thông báo bàn phím và sử dụng thời lượng đó cho hoạt ảnh scrollview thay vì một giá trị cố định, nhưng hãy kiện tôi, điều này đã đủ tốt đối với tôi;)


1

Sử dụng phần mở rộng sau nếu bạn không muốn tính toán quá nhiều:

func scrollSubviewToBeVisible(subview: UIView, animated: Bool) {
    let visibleFrame = UIEdgeInsetsInsetRect(self.bounds, self.contentInset)
    let subviewFrame = subview.convertRect(subview.bounds, toView: self)
    if (!CGRectContainsRect(visibleFrame, subviewFrame)) {
        self.scrollRectToVisible(subviewFrame, animated: animated)
    }
}

Và có thể bạn muốn giữ cho UITextField của mình luôn hiển thị:

func textViewDidChange(textView: UITextView) {
    self.scrollView?.scrollSubviewToBeVisible(textView, animated: false)
}

1

Hãy thử mã này trong Swift 3:

override func viewDidAppear(_ animated: Bool) {
    setupViewResizerOnKeyboardShown()
}

func setupViewResizerOnKeyboardShown() {
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardWillShowForResizing),
                                           name: Notification.Name.UIKeyboardWillShow,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardWillHideForResizing),
                                           name: Notification.Name.UIKeyboardWillHide,
                                           object: nil)
}

func keyboardWillShowForResizing(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
        let window = self.view.window?.frame {
        // We're not just minusing the kb height from the view height because
        // the view could already have been resized for the keyboard before
        self.view.frame = CGRect(x: self.view.frame.origin.x,
                                 y: self.view.frame.origin.y,
                                 width: self.view.frame.width,
                                 height: window.origin.y + window.height - keyboardSize.height)

    } else {
        debugPrint("We're showing the keyboard and either the keyboard size or window is nil: panic widely.")
    }
}

func keyboardWillHideForResizing(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        let viewHeight = self.view.frame.height
        self.view.frame = CGRect(x: self.view.frame.origin.x,
                                 y: self.view.frame.origin.y,
                                 width: self.view.frame.width,
                                 height: viewHeight) //viewHeight + keyboardSize.height

    } else {
        debugPrint("We're about to hide the keyboard and the keyboard size is nil. Now is the rapture.")
    }
}

deinit {
        NotificationCenter.default.removeObserver(self)
    }

1

Giải pháp Swift 5 dựa trên giải pháp Masa ở trên - những thay đổi liên quan đến nó:

  • sử dụng keyboardFrameEndUserInfoKeythay vì keyboardFrameBeginUserInfoKey, vì keyboardFrameBeginUserInfoKeycó thể hiển thị trước trả về giá trị khác như được mô tả, ví dụ ở đây: chiều cao bàn phím thay đổi khi xuất hiện
  • sử dụng thông báo "will" thay vì "did" cộng với việc thay đổi nó thành các tên phím Swift 5: UIResponder.keyboardWillShowNotification/ UIResponder.keyboardWillHideNotificationthay vì NSNotification.Name.UIKeyboardDidShow/NSNotification.Name.UIKeyboardDidHide

Mã:

override func viewDidLoad() {
    super.viewDidLoad()
    registerForKeyboardNotifications()
}

func registerForKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardAppear(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardDisappear(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func onKeyboardAppear(_ notification: NSNotification) {
    guard let info = notification.userInfo, let kbSize = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size else { return }

    let insets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0)

    scrollView.contentInset = insets
    scrollView.scrollIndicatorInsets = insets

    //Other changes if needed
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

0

Bạn thực sự không cần UIScrollView để làm điều này. Tôi đã sử dụng mã này và nó phù hợp với tôi:

-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{

   if (textField==_myTextField)
   {
      [self keyBoardAppeared];
   }
   return true;
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
   if (textField==_myTextField)
   {
      [self keyBoardDisappeared];
   }
}

-(void) keyBoardAppeared
{
   CGRect frame = self.view.frame;

[UIView animateWithDuration:0.3
                      delay:0
                    options: UIViewAnimationCurveEaseOut
                 animations:^{
                     self.view.frame = CGRectMake(frame.origin.x, frame.origin.y-215, frame.size.width, frame.size.height);
                 }
                 completion:^(BOOL finished){

                 }];
}

-(void) keyBoardDisappeared
{
   CGRect frame = self.view.frame;

  [UIView animateWithDuration:0.3
                      delay:0
                    options: UIViewAnimationCurveEaseOut
                 animations:^{
                     self.view.frame = CGRectMake(frame.origin.x, frame.origin.y+215, frame.size.width, frame.size.height);
                 }
                 completion:^(BOOL finished){

                 }];
}

Sự cố: Sử dụng các giá trị được mã hóa cứng. Thay đổi toàn bộ giao diện người dùng của bạn lên và xuống thường sẽ làm rối tung giao diện của chế độ xem.
ý nghĩa-vấn đề

0

Bạn có thể cuộn bằng cách sử dụng thuộc tính contentOffsettrong UIScrollView, ví dụ:

CGPoint offset = scrollview.contentOffset;
offset.y -= KEYBOARD_HEIGHT + 5;
scrollview.contentOffset = offset;

Ngoài ra còn có một phương pháp để thực hiện cuộn hoạt hình.

Về lý do tại sao lần chỉnh sửa thứ hai của bạn cuộn không chính xác, có thể là do bạn dường như cho rằng một bàn phím mới sẽ xuất hiện mỗi khi bắt đầu chỉnh sửa. Bạn có thể thử kiểm tra xem mình đã điều chỉnh vị trí hiển thị của "bàn phím" chưa (và tương tự như vậy, hãy kiểm tra khả năng hiển thị của bàn phím tại thời điểm này trước khi hoàn nguyên).

Giải pháp tốt hơn có thể là lắng nghe thông báo trên bàn phím, ví dụ:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardDidShow:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];

0

Bây giờ tôi biết đó là một câu hỏi cũ nhưng tôi nghĩ nó có thể giúp ích cho người khác. Tôi muốn một cái gì đó dễ triển khai hơn một chút cho một số ứng dụng mà tôi có, vì vậy tôi đã tạo một lớp học cho điều này. Bạn có thể tải xuống tại đây nếu muốn: https://github.com/sdernley/iOSTextFieldHandler

Nó đơn giản như thiết lập tất cả các Trường UIText để có một đại diện của chính mình

textfieldname.delegate = self;

Và sau đó thêm nó vào bộ điều khiển chế độ xem của bạn với tên của nút scrollView và gửi

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [iOSTextFieldHandler TextboxKeyboardMover:containingScrollView tf:textField btn:btnSubmit];
}

0

Sau đây là giải pháp của tôi hoạt động (5 bước)

Bước 1: Thêm người quan sát để nắm bắt UITEXTFIELD hoặc UITEXTVIEW ShoudBeginE Chỉnh sửa nào (nơi đối tượng được inited hoặc ViewDidLoad.

[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(updateActiveField:)
                                             name:@"UPDATE_ACTIVE_FIELD" object:nil];

Bước 2: Đăng thông báo khi ..ShouldBeginE Chỉnh sửa với OBJECT của UITEXTFIELD hoặc UITEXTVIEW

-(BOOL)textViewShouldBeginEditing:(UITextView *)textView {

[[NSNotificationCenter defaultCenter] postNotificationName:@"UPDATE_ACTIVE_FIELD" 
                                                    object:textView];
return YES;
}

Bước 3: Phương thức (Step1 gọi) chỉ định UITEXTFIELD hoặc UITEXTVIEW hiện tại

-(void) updateActiveField: (id) sender {
    activeField = [sender object];
}

Bước 4: Thêm trình quan sát bàn phím UIKeyboardWillShowNotification (giống như Bước 1)

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWasShown:)
                                             name:UIKeyboardDidShowNotification object:nil];

và phương pháp:

// 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);

    _currentEdgeInsets = self.layoutPanel.contentInset; // store current insets to restore them later
    self.layoutPanel.contentInset = contentInsets;
    self.layoutPanel.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    CGRect aRect =  self.view.frame;
    aRect.size.height -= kbSize.height;

    UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    CGPoint p = [activeField convertPoint:activeField.bounds.origin toView:window];

    if (!CGRectContainsPoint(aRect, p) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y +kbSize.height);
       [self.layoutPanel setContentOffset:scrollPoint animated:YES];
       self.layoutPanel.scrollEnabled = NO;
    }
}

Bước 5: Thêm trình quan sát bàn phím UIKeyboardWillHideNotification (giống như bước 1)

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];

và phương pháp:

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    self.layoutPanel.contentInset = _currentEdgeInsets;
    self.layoutPanel.scrollIndicatorInsets = _currentEdgeInsets;
    self.layoutPanel.scrollEnabled = YES;
}

Nhớ loại bỏ những người quan sát!


0

Tôi đã sử dụng câu trả lời này do Sudheer Palchuri cung cấp https://stackoverflow.com/users/2873919/sudheer-palchuri https://stackoverflow.com/a/32583809/6193496

Trong ViewDidLoad, đăng ký thông báo:

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DetailsViewController.keyboardWillShow(_:)), name:UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(DetailsViewController.keyboardWillHide(_:)), name:UIKeyboardWillHideNotification, object: nil)

Thêm bên dưới các phương thức quan sát để tự động cuộn khi bàn phím xuất hiện.

func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}

func keyboardWillShow(notification:NSNotification){

var userInfo = notification.userInfo!
var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
keyboardFrame = self.view.convertRect(keyboardFrame, fromView: nil)

var contentInset:UIEdgeInsets = self.scrollView.contentInset
contentInset.bottom = keyboardFrame.size.height
self.scrollView.contentInset = contentInset
}

func keyboardWillHide(notification:NSNotification){

var contentInset:UIEdgeInsets = UIEdgeInsetsZero
self.scrollView.contentInset = contentInset
}

0

Giải pháp của tôi có 4 bước:
- Bước 1: chức năng lắng nghe khi bàn phím xuất hiện

- (void)keyboardWasShown:(NSNotification *)notification {
// Get the size of the keyboard.
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//top: 64 for navigation bar, 0 for without navigation
UIEdgeInsets contentInsets = UIEdgeInsetsMake(64, 0, keyboardSize.height, 0);
_scrollView.contentInset = contentInsets;
_scrollView.scrollIndicatorInsets = contentInsets;
}

- Bước 2: Chức năng lắng nghe khi bàn phím biến mất

- (void)keyboardWillHide:(NSNotification *)notification {
//top: 64 for navigatiob bar
UIEdgeInsets contentInsets = UIEdgeInsetsMake(64, 0, 0, 0);
[_editScrollView setContentInset: contentInsets];
[_editScrollView setScrollIndicatorInsets: contentInsets];
}

- Bước 3: Thêm các chức năng này vào trung tâm thông báo:

- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- Bước 4: Loại bỏ nghe khi bộ điều khiển chế độ xem biến mất

- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.