如何滚动的UIScrollView键盘出现时?(How do I scroll the UIScro

2019-06-18 18:00发布

我有我的代码的麻烦。 我想移动UIScrollView当我编辑UITextField应该由键盘弹出隐藏。

现在我移动主框架,因为我不知道如何在代码中“滚动”。 所以,我做的代码一点点,它的正常工作,但是当我编辑的UITextField,我切换到另一个UITextField不按压“返回”按钮,主视图去waaayyyyy远了。

我做了NSLog()跟我的变量的大小,距离和textFieldRect.origin.y,你可以看到下面。 当我放了两个UITextField在同一个地方(y原点),我做这个特殊的“开关”(wihtout按回车键),我得到了相同的数字,而我的代码为第一工作得很好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];
}

有任何想法吗 ?

Answer 1:

从苹果公司推荐的方法是改变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;
}

斯威夫特版本:

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
}


Answer 2:

我只是实现了这个与雨燕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
}

编辑的斯威夫特3

好像你只需要设置contentInsetscrollIndicatorInset与斯威夫特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
}


Answer 3:

这里所有的答案似乎对景观的可能性忘记。 如果你想这个当设备被旋转到横向视图的工作,那么你将面临的问题。

这里的技巧是,虽然观点是知道方位的,键盘是不是。 这意味着,在景观,键盘宽度实际上是它的高度,反之亦然。

要修改建议苹果方式改变内容的插图,并得到其支持横向,我会建议使用下列内容:

// 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变量的宽度和高度值,以确保每个方位都使用了正确的价值观。



Answer 4:

斯威夫特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
}


Answer 5:

这个东西没有必要编码它的很多的是很容易像下面的代码: -

在UIScrollView中所有textfiled从笔尖这样的形象: -

YourViewController.h

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

从笔尖连接IBOutlet中,也连接从NIB UItextfiled的各授权和委托滚动视图

-(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和代表正确连接



Answer 6:

Apple的建议重新编码斯威夫特 +使用的UIScrollView与自动布局中的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)
    }

}


Answer 7:

我会在苹果代码更新的唯一的事情就是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;

}


Answer 8:

这里是一个斯威夫特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
}


Answer 9:

我发现上面的答案已经过时。 也没有完美的,当滚动。

这里有一个快速的版本。

它会向右滚动文本字段下方,没有多余的空间。 它会还原到它就像它第一次出现的方式。

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


Answer 10:

这是我一直使用的是什么。 这很简单,而且运作良好。

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


Answer 11:

这与斯威夫特的改进最终代码

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


Answer 12:

尝试在斯威夫特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)
    }


Answer 13:

我是这样做的。 这是一个很大的代码,但它可以确保,当前处于焦点的文本字段在“可用空间”垂直居中:

- (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:动作被挂在每一个文本框的DidBeginEditing状态。

此外,它会是一个好一点摆脱键盘的通知动画的持续时间和使用的滚动型动画,而不是一个固定值,而是告我,这对我来说不够好;)



Answer 14:

雨燕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,你必须在某个时候注销观察者(感谢乔 )



Answer 15:

实际上,你并不需要一个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){

                 }];
}


Answer 16:

您可以通过使用属性滚动contentOffsetUIScrollView ,例如,

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


Answer 17:

我知道这是一个老问题,但现在我认为这可能帮助别人。 我想要的东西更容易实现的一些应用程序,我有一点点,所以我做了类此。 你可以在这里下载,如果你想: https://github.com/sdernley/iOSTextFieldHandler

这是因为设置所有UITextFields的简单拥有自我的委托

textfieldname.delegate = self;

然后用你的滚动视图,并提交按钮的名称添加给你的视图控制器

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


Answer 18:

下面是我的解决方案,它的工作原理(5级)

步骤1:添加观察者赶上其中的UITextField或UITextView的ShoudBeginEditing(其中对象被inited或viewDidLoad中。

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

第二步:用的UITextField或UITextView的对象..ShouldBeginEditing时发布的通知

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

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

步骤3:该(第一步卡列斯)的方法,分配当前的UITextField或UITextView的

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

第四步:添加键盘观察员UIKeyboardWillShowNotification(同一地点的第一步)

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

第五步:添加键盘观察员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;
}

记得删除观察家!



Answer 19:

使用下面的扩展,如果你不想计算太多:

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


Answer 20:

我使用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
}


Answer 21:

我的解决方案有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:除去听当视图控制器disappers

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


文章来源: How do I scroll the UIScrollView when the keyboard appears?