ฉันจะเลื่อน UIScrollView เมื่อแป้นพิมพ์ปรากฏขึ้นได้อย่างไร


107

ฉันมีปัญหากับรหัสของฉัน ฉันกำลังพยายามย้ายUIScrollViewเมื่อฉันแก้ไขสิ่งUITextFieldที่ควรจะซ่อนโดยป๊อปแป้นพิมพ์

ตอนนี้ฉันกำลังย้ายเฟรมหลักเพราะฉันไม่รู้ว่าจะ "เลื่อนขึ้น" ในโค้ดอย่างไร ดังนั้นฉันทำโค้ดนิดหน่อยมันก็ใช้งานได้ดี แต่เมื่อฉันแก้ไข UItextfield และฉันเปลี่ยนไปใช้อันอื่นUITextFieldโดยไม่ต้องกดปุ่ม 'return' มุมมองหลักจะไปไกลขึ้น

ฉันทำNSLog()กับตัวแปรขนาดระยะทางและ textFieldRect.origin.y ดังที่คุณเห็นด้านล่าง เมื่อฉันใส่สองตัวUITextFieldในที่เดียวกัน (จุดเริ่มต้น y) และฉันทำ 'สวิตช์' นี้โดยเฉพาะ (โดยไม่ต้องกด return) ฉันจะได้ตัวเลขเดียวกันในขณะที่รหัสของฉันทำงานได้ดีสำหรับการUITextFieldแก้ไขครั้งแรกแต่ไม่ใช่สำหรับการแก้ไขครั้งที่สอง

ลองดู:

- (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];
}

ความคิดใด ๆ ?

คำตอบ:


204

วิธีที่แนะนำจาก Apple คือการเปลี่ยนcontentInsetไฟล์UIScrollView. เป็นวิธีที่ดีมากเพราะคุณไม่ต้องยุ่งกับไฟล์contentSize. รหัสต่อไปนี้คัดลอกมาจากคู่มือการเขียนโปรแกรมแป้นพิมพ์ซึ่งมีการอธิบายการจัดการปัญหานี้ คุณควรจะดูมัน

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

เวอร์ชัน 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
อาโอเค. เดี๋ยวก่อนฉันไม่เข้าใจว่าคุณกำลังพูดถึงส่วนการเลื่อน ใช่ activeField เป็นเพียงตัวยึดสำหรับคุณสมบัติ UITextField ของคุณ ดังนั้นแทนที่และลองอีกครั้ง คุณไม่จำเป็นต้องเปลี่ยนขนาดมิฉะนั้น textField จะมีความสูงมากขึ้น
Masa

2
คุณไม่ต้องการเขียนทับ contentInsets.top ที่มีอยู่หากคุณทำมุมมองของคุณอาจเลื่อนขึ้นด้านหลังการนำทาง
SwiftArchitect

6
github.com/michaeltyson/TPKeyboard หลีกเลี่ยง นี่เป็นวิธีแก้ปัญหาที่ง่ายมาก
Pramod

2
เป็นเรื่องที่ดีในการแปลงactiveField.frameกรอบญาติไม่จำเป็นต้องเป็นเด็กทันทีเพื่อactiveField self.viewรหัสที่อัปเดตควรมีลักษณะดังนี้: 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
ฉันต้องใช้UIKeyboardFrameEndUserInfoKeyคีย์บน iOS 11 เพราะUIKeyboardFrameBeginUserInfoKeyมักจะให้ความสูงเป็นศูนย์
Collin

66

ฉันเพิ่งใช้สิ่งนี้กับ Swift 2.0 สำหรับ iOS9 บน Xcode 7 (เบต้า 6) ทำงานได้ดีที่นี่

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
}

แก้ไขสำหรับ Swift 3

ดูเหมือนว่าคุณจะต้องตั้งค่าcontentInsetและscrollIndicatorInsetด้วย Swift 3 เท่านั้นการเลื่อน / contentOffset จะทำโดยอัตโนมัติ ..

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
}

คุณช่วยอธิบายรหัสของคุณได้ไหม ฉันมีช่องข้อความสองช่องและเมื่อฉันแก้ไขช่องแรกมันจะเลื่อนลงในขณะที่ช่องข้อความที่สองเลื่อนขึ้น
สามารถ

บน iPad สิ่งนี้จะเลื่อนมุมมองแบบเลื่อนลงแทนที่จะขึ้น มีความคิดว่าเกิดอะไรขึ้นที่นั่น?
Justin Vallely

2
@can textField ที่อ้างถึงเป็นตัวแปรที่คุณตั้งค่าสำหรับ viewcontroller ของคุณตามการตอบกลับแรกปัจจุบัน
Johannes

ฉันสงสัยว่าทำไม Apple จึงเลื่อนช่องข้อความที่ใช้งานอยู่เหนือแป้นพิมพ์ให้เราตอนนี้
paulvs

2
ใน swift 4 ใส่ @objc บน keyboardWillShow และ keyboardWillHide method
Ronaldo Albertini

16

คำตอบทั้งหมดที่นี่ดูเหมือนจะลืมเกี่ยวกับความเป็นไปได้ของภูมิทัศน์ หากคุณต้องการให้ใช้งานได้เมื่อหมุนอุปกรณ์เป็นมุมมองแนวนอนคุณจะประสบปัญหา

เคล็ดลับที่นี่คือแม้ว่ามุมมองจะรับรู้ถึงการวางแนว แต่แป้นพิมพ์ไม่ได้ ซึ่งหมายความว่าในแนวนอนความกว้างของแป้นพิมพ์คือความสูงและวีซ่าในทางกลับกัน

หากต้องการแก้ไขวิธีที่แนะนำของแอปเปิ้ลในการเปลี่ยนการแทรกเนื้อหาและให้รองรับการวางแนวนอนฉันขอแนะนำให้ใช้สิ่งต่อไปนี้:

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

ส่วนที่ต้องให้ความสนใจมีดังต่อไปนี้:

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;
}

คืออะไรคือตรวจจับว่าอุปกรณ์อยู่ในแนวใดหากเป็นแนวนอนอุปกรณ์จะ 'สลับ' ค่าความกว้างและความสูงของตัวแปร keyboardSize เพื่อให้แน่ใจว่ามีการใช้ค่าที่ถูกต้องในแต่ละทิศทาง


คุณอาจต้องการทำการปรับแต่งเพิ่มเติม (ลด) ของด้านล่างที่แทรกเนื้อหาตามstackoverflow.com/questions/25704513/…นี้ในกรณีที่ตัวเลื่อนใช้ความสูงทั้งหมดของหน้าจอ UIEdgeInsetsMake (0.0, 0.0, kbSize.height - ([UIScreen mainScreen] .bounds.size.height - cvf.origin.y - cvf.size.height), 0.0); โดยที่ cvf คือ scroller.frame
Anton Tropashko

if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight )
schmidt9

13

โซลูชัน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
ทำงานเป็นส่วนใหญ่เพียงแค่ต้องเปลี่ยนUIKeyboardFrameBeginUserInfoKeyเป็นUIKeyboardFrameEndUserInfoKey
Fonix

ฉันใช้รหัสนี้ใน UITableView แต่ TableView ไม่ได้เลื่อนขึ้นทันที
Shawn Baek

3
UIKeyboardWillShow, UIKeyboardWillHideและ UIKeyboardFrameBeginUserInfoKeyได้รับการเปลี่ยนชื่อUIResponder.keyboardWillShowNotification, และUIResponder.keyboardWillHideNotification UIResponder.keyboardFrameBeginUserInfoKey
Aaron Brager

9

สำหรับสิ่งนี้ไม่จำเป็นต้องเข้ารหัสมากมายมันง่ายมากเหมือนโค้ดด้านล่าง: -

textfiled ทั้งหมดของคุณใน UIScrollview จากปลายปากกาเช่นภาพนี้: -

ใส่คำอธิบายภาพที่นี่

YourViewController.h

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

เชื่อมต่อ IBOutlet จากปลายปากกาและเชื่อมต่อผู้รับมอบสิทธิ์ UItextfiled และ scrollview จาก 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;
}

หมายเหตุหากไม่ได้เชื่อมต่อผู้รับมอบสิทธิ์แบบข้อความแสดงว่าไม่มีวิธีใดที่ใช้งานได้โปรดตรวจสอบให้แน่ใจว่า iBOulate และผู้ร่วมประชุมทั้งหมดเชื่อมต่ออย่างถูกต้อง


5
นี่เป็นแนวทางที่เก่ามากและไม่ควรใช้ มันขึ้นอยู่กับค่าและสมมติฐานที่กำหนดไว้ซึ่งไม่เกี่ยวข้องอีกต่อไป
Womble

@Womble มีคำตอบมากมายที่เก่า แต่เกี่ยวข้องกับคำถามในขณะนั้น (เมื่อคำถามถูกถาม) ดังนั้นอย่าลงคะแนนโดยไม่มีเหตุผล
Ashish Kakkad

7

ข้อเสนอแนะของ Apple recoded ในสวิฟท์ + ใช้ UIScrollView ด้วย Auto Layout ใน iOS (เบสที่ลิงค์ดังต่อไปนี้: การเชื่อมโยง 1 , การเชื่อมโยง 2 , การเชื่อมโยง 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)
    }

}

หลังจากทำงานหนักมา 1 วันฉันสามารถใช้คำแนะนำของ Apple ใน Swift + แก้ไขโค้ดของพวกเขาเล็กน้อย + ปรับให้ตอบสนองบนอุปกรณ์แอปเปิ้ลทั้งหมดดังนั้นก่อนลงคะแนนโปรดบอกเหตุผลด้วย ไม่มีรหัสใดข้างต้นทำงานได้อย่างถูกต้องในทุกอุปกรณ์และทุกสถานการณ์ของเลย์เอาต์ อย่างไรก็ตามของฉันใช้งานได้กับอุปกรณ์ Apple และสถานการณ์เค้าโครงทั้งหมด
King-Wizard

ฉันคิดว่าคุณจำเป็นต้องยกเลิกการสมัครจากศูนย์การแจ้งเตือนก่อนที่มุมมองจะตาย?
Cyril Duchon-Doris

4

สิ่งเดียวที่ฉันจะอัปเดตในรหัส Apple คือวิธี keyboardWillBeHidden: เพื่อให้การเปลี่ยนแปลงราบรื่น

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

นี่คือคำตอบที่เข้ากันได้กับSwift 3ซึ่งจะทำงานร่วมกับตัวควบคุมมุมมองภายในตัวควบคุมการนำทางเช่นกันเนื่องจากจะเปลี่ยน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

โซลูชันSwift 4.2ที่คำนึงถึงความสูงของ UIToolbar และ 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
}

และหากคุณกำหนดเป้าหมาย <iOS 9 คุณต้องยกเลิกการลงทะเบียนผู้สังเกตการณ์ในบางจุด (ขอบคุณโจ )


คำนึงถึงพื้นที่ใต้แถบแท็บบน iPhone X หรือไม่ เป็นที่ที่แถบ iOS ปรากฏขึ้น
surfrider

iOS9 + คุณไม่จำเป็นต้องลบผู้สังเกตการณ์developer.apple.com/documentation/foundation/notificationcenter/…
โจ

ใช่คุณพูดถูก. ฉันได้อัปเดตคำตอบตามนั้น
JanApotheker

3

ฉันพบว่าคำตอบข้างต้นล้าสมัยแล้ว ยังไม่สมบูรณ์แบบเมื่อเลื่อน

นี่คือเวอร์ชันที่รวดเร็ว

มันจะเลื่อนไปทางขวาล่าง textField ไม่มีที่ว่าง และมันจะกลับคืนสู่สภาพเดิมเหมือนครั้งแรกที่ปรากฏ

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

มันเลื่อนขึ้นเล็กน้อย แต่ไม่เพียงพอที่จะเปิดเผยความสูงทั้งหมด ฉันใช้ Swift 2.3 และทดสอบบน iphone 5
KMC

2

นี่คือสิ่งที่ฉันใช้ ง่ายและใช้งานได้ดี

#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);
    }];
}

ใช้การUITextFieldโทรของผู้ร่วมประชุมtextFieldDidBeginEditing:เพื่อเลื่อนมุมมองของคุณขึ้นและยังเพิ่มผู้สังเกตการณ์การแจ้งเตือนเพื่อทำให้มุมมองกลับมาเป็นปกติเมื่อแป้นพิมพ์ซ่อน:

-(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

นี่คือรหัสสุดท้ายที่มีการปรับปรุงใน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
ฉันคิดว่าตรรกะของคุณกลับด้าน - คุณต้องการเลื่อนก็ต่อเมื่อ CGRectContainsPoint ไม่มี relativeFieldFrame.origin
Rayfleck

2

วิธีแก้ปัญหาที่ง่ายที่สุดวิธีหนึ่งคือการใช้โปรโตคอลต่อไปนี้:

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 })
    }
}

เมื่อคุณต้องการใช้โปรโตคอลนี้คุณจะต้องปฏิบัติตามและกำหนดมุมมองการเลื่อนในคอนโทรลเลอร์ของคุณดังนี้:

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

ฉันจะทำแบบนี้ มีรหัสจำนวนมาก แต่ช่วยให้มั่นใจได้ว่า textField ที่อยู่ในโฟกัสอยู่ในแนวตั้งอยู่ตรงกลางใน 'พื้นที่ว่าง':

- (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;

โปรดทราบว่าการ- (IBAction)textFieldGotFocus:ดำเนินการเชื่อมต่อกับทุก textField'sDidBeginEditingสถานะ

นอกจากนี้จะเป็นการดีกว่าเล็กน้อยที่จะได้รับระยะเวลาการเคลื่อนไหวจากการแจ้งเตือนของแป้นพิมพ์และใช้สำหรับภาพเคลื่อนไหวแบบ scrollview แทนค่าคงที่ แต่ฟ้องฉันนี่ดีพอสำหรับฉัน;)


1

ใช้ส่วนขยายต่อไปนี้หากคุณไม่ต้องการคำนวณมากเกินไป:

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)
    }
}

และบางทีคุณอาจต้องการให้ UITextField ของคุณมองเห็นได้เสมอ:

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

1

ลองใช้รหัสนี้ใน 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

โซลูชันSwift 5 ที่ใช้โซลูชันMasaด้านบน - การเปลี่ยนแปลงที่เกี่ยวข้อง:

  • โดยใช้keyboardFrameEndUserInfoKeyแทน keyboardFrameBeginUserInfoKeyเนื่องจาก keyboardFrameBeginUserInfoKeyในครั้งแรกสามารถแสดงค่าอื่น ๆ ตามที่อธิบายไว้ที่นี่: ความสูงของแป้นพิมพ์จะแตกต่างกันไปเมื่อปรากฏ
  • โดยใช้การแจ้งเตือน "will" แทน "did" รวมทั้งเปลี่ยนเป็นชื่อคีย์ Swift 5: UIResponder.keyboardWillShowNotification/ UIResponder.keyboardWillHideNotificationแทนNSNotification.Name.UIKeyboardDidShow/NSNotification.Name.UIKeyboardDidHide

รหัส:

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

คุณไม่จำเป็นต้องมี UIScrollView เพื่อทำสิ่งนี้ ฉันใช้รหัสนี้และใช้ได้กับฉัน:

-(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){

                 }];
}

ปัญหา: ใช้ค่าฮาร์ดโค้ด เลื่อน UI ทั้งหมดของคุณขึ้นและลงซึ่งมักจะทำให้รูปลักษณ์ของมุมมองยุ่งเหยิง
เรื่องความหมาย

0

คุณสามารถเลื่อนโดยใช้คุณสมบัติcontentOffsetในUIScrollViewเช่น

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

นอกจากนี้ยังมีวิธีการเลื่อนแบบเคลื่อนไหว

สำหรับสาเหตุที่การแก้ไขครั้งที่สองของคุณเลื่อนไม่ถูกต้องอาจเป็นเพราะคุณคิดว่าแป้นพิมพ์ใหม่จะปรากฏขึ้นทุกครั้งที่เริ่มการแก้ไข คุณสามารถลองตรวจสอบว่าคุณได้ปรับตำแหน่งที่มองเห็นของ "แป้นพิมพ์" แล้วหรือยัง (และตรวจสอบการมองเห็นแป้นพิมพ์ในขณะนั้นก่อนที่จะเปลี่ยนกลับ)

ทางออกที่ดีกว่าอาจเป็นการฟังการแจ้งเตือนของแป้นพิมพ์เช่น:

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

0

ตอนนี้ฉันรู้ว่ามันเป็นคำถามเก่า แต่ฉันคิดว่ามันอาจช่วยคนอื่นได้ ฉันต้องการบางสิ่งที่ง่ายกว่าในการใช้งานสำหรับแอพบางตัวที่ฉันมีดังนั้นฉันจึงสร้างคลาสสำหรับสิ่งนี้ คุณสามารถดาวน์โหลดได้ที่นี่หากคุณต้องการ: https://github.com/sdernley/iOSTextFieldHandler

ทำได้ง่ายเพียงแค่ตั้งค่า UITextFields ทั้งหมดให้มีตัวแทนของตัวเอง

textfieldname.delegate = self;

จากนั้นเพิ่มสิ่งนี้ไปยังตัวควบคุมมุมมองของคุณด้วยชื่อของปุ่ม scrollView และส่งของคุณ

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

0

ต่อไปนี้เป็นวิธีแก้ปัญหาของฉันที่ใช้งานได้ (5 ขั้นตอน)

ขั้นตอนที่ 1: เพิ่มผู้สังเกตการณ์เพื่อตรวจจับว่า UITEXTFIELD หรือ UITEXTVIEW ShoudBeginEditing ตัวใด (โดยที่วัตถุอยู่ในการเข้าหรือ ViewDidLoad

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

ขั้นตอนที่ 2: โพสต์การแจ้งเตือนเมื่อ .. ควรเริ่มการแก้ไขด้วย OBJECT ของ UITEXTFIELD หรือ UITEXTVIEW

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

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

ขั้นตอนที่ 3: วิธีการที่ (Step1 calles) กำหนด UITEXTFIELD หรือ UITEXTVIEW ปัจจุบัน

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

ขั้นตอนที่ 4: เพิ่มผู้สังเกตการณ์คีย์บอร์ด UIKeyboardWillShowNotification (ที่เดียวกับขั้นตอนที่ 1)

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWasShown:)
                                             name:UIKeyboardDidShowNotification 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);

    _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;
    }
}

ขั้นตอนที่ 5: เพิ่มผู้สังเกตการณ์แป้นพิมพ์ UIKeyboardWillHideNotification (ที่เดียวกับขั้นตอนที่ 1)

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

และวิธีการ:

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

อย่าลืมลบผู้สังเกตการณ์!


0

ฉันใช้คำตอบนี้ที่จัดทำโดย Sudheer Palchuri https://stackoverflow.com/users/2873919/sudheer-palchuri https://stackoverflow.com/a/32583809/6193496

ใน ViewDidLoad ลงทะเบียนการแจ้งเตือน:

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

เพิ่มวิธีการสังเกตการณ์ด้านล่างซึ่งจะเลื่อนอัตโนมัติเมื่อแป้นพิมพ์ปรากฏขึ้น

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

วิธีแก้ปัญหาของฉันมี 4 ขั้นตอน:
- ขั้นตอนที่ 1: ฟังก์ชั่นจะฟังเมื่อแป้นพิมพ์ปรากฏขึ้น

- (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;
}

- ขั้นตอนที่ 2: ฟังก์ชั่นจะฟังเมื่อแป้นพิมพ์หายไป

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

- ขั้นตอนที่ 3: เพิ่มฟังก์ชันเหล่านี้ในศูนย์การแจ้งเตือน:

- (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];
}

- ขั้นตอนที่ 4: ลบฟังเมื่อตัวควบคุมมุมมองหายไป

- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.