objective-c UITextField:出现键盘时移动视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1775860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:32:23  来源:igfitidea点击:

UITextField: move view when keyboard appears

iphoneobjective-ccocoa-touchuitextfield

提问by ComSubVie

I'm currently working on an iPhone application with a single view, which has multiple UITextFields for input. When the keyboard shows, it overlays the bottom textfields. So I added the corresponding textFieldDidBeginEditing:method, to move the view up, which works great:

我目前正在开发一个带有单个视图的 iPhone 应用程序,它有多个 UITextFields 用于输入。当键盘显示时,它会覆盖底部的文本字段。所以我添加了相应的textFieldDidBeginEditing:方法,将视图向上移动,效果很好:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    if ( ( textField != inputAmount ) && ( textField != inputAge ) ) {
        NSTimeInterval animationDuration = 0.300000011920929;
        CGRect frame = self.view.frame;
        frame.origin.y -= kOFFSET_FOR_KEYBOARD;
        frame.size.height += kOFFSET_FOR_KEYBOARD;
        [UIView beginAnimations:@"ResizeForKeyboard" context:nil];
        [UIView setAnimationDuration:animationDuration];
        self.view.frame = frame;
        [UIView commitAnimations];      
    }
}

This method checks, if the source of the message is one of the textfields that are visible when the keyboard shows, and if not, it moves the view up.

此方法检查消息的来源是否是键盘显示时可见的文本字段之一,如果不是,则向上移动视图。

I also added the textFieldDidEndEnditing:method, which moves the view down again (and updates some model objects according to the changed input):

我还添加了该textFieldDidEndEnditing:方法,该方法再次向下移动视图(并根据更改的输入更新一些模型对象):

- (void)textFieldDidEndEditing:(UITextField *)textField {
    if ( ( textField != inputMenge ) && ( textField != inputAlter ) ) {
        NSTimeInterval animationDuration = 0.300000011920929;
        CGRect frame = self.view.frame;
        frame.origin.y += kOFFSET_FOR_KEYBOARD;
        frame.size.height -= kOFFSET_FOR_KEYBOARD;
        [UIView beginAnimations:@"ResizeForKeyboard" context:nil];
        [UIView setAnimationDuration:animationDuration];
        self.view.frame = frame;
        [UIView commitAnimations];      
    }
    // Additional Code
}

However, this solution has a simple flaw: When I finish editing one of the "hidden" textfields and touch another textfield, the keyboard vanishes, the view moves down, the view moves up again and the keyboard reappears.

然而,这个解决方案有一个简单的缺陷:当我完成编辑一个“隐藏”的文本字段并触摸另一个文本字段时,键盘消失,视图向下移动,视图再次向上移动并且键盘重新出现。

Is there any possibility to keep the keyboard from vanishing and reappearing between two edits (of the "hidden" textfields - so that the view only moves when the selected textfield changes from one that would be hidden by the keyboard to one that would not be hidden)?

是否有可能防止键盘在两次编辑之间消失和重新出现(“隐藏”文本字段 - 这样视图仅在所选文本字段从键盘隐藏的文本字段更改为不会隐藏的文本字段时移动)?

采纳答案by Vladimir Grigorov

This solution is based on ComSubVie's one.

此解决方案基于 ComSubVie 的解决方案。

Advantages:

好处:

  • It supports device rotation - works for all orientations;
  • It doesn't hardcode the values for animation duration and curve, it reads them from the keyboard notification;
  • It utilizes UIKeyboardWillShowNotificationinstead of UIKeyboardDidShowNotificationto sync keyboard animation and custom actions;
  • It doesn't use the deprecated UIKeyboardBoundsUserInfoKey;
  • It handles keyboard resize due to pressing the International key;
  • Fixed memory leak by unregistering for keyboard events;
  • All keyboard handling code is encapsulated in a separate class - KBKeyboardHandler;
  • Flexibility - KBKeyboardHandlerclass may be easy extended / modified to better suit specific needs;
  • 它支持设备旋转 - 适用于所有方向;
  • 它不会对动画持续时间和曲线的值进行硬编码,而是从键盘通知中读取它们;
  • 它利用UIKeyboardWillShowNotification而不是UIKeyboardDidShowNotification同步键盘动画和自定义动作;
  • 它不使用已弃用的UIKeyboardBoundsUserInfoKey;
  • 它处理因按下国际键而导致的键盘大小调整;
  • 通过注销键盘事件修复内存泄漏;
  • 所有键盘处理代码都封装在一个单独的类中 - KBKeyboardHandler;
  • 灵活性 -KBKeyboardHandler可以轻松扩展/修改类以更好地满足特定需求;

Limitations:

限制:

  • Works for iOS 4 and above, it needs small modifications to support older versions;
  • It works for applications with a single UIWindow. If you use multiple UIWindows, you may need to modify retrieveFrameFromNotification:method.
  • 适用于 iOS 4 及更高版本,需要稍作修改以支持旧版本;
  • 它适用于具有单个UIWindow. 如果您使用多个 UIWindows,您可能需要修改retrieveFrameFromNotification:方法。

Usage:

用法:

Include KBKeyboardHandler.h, KBKeyboardHandler.m and KBKeyboardHandlerDelegate.h in your project. Implement the KBKeyboardHandlerDelegateprotocol in your view controller - it consists of a single method, which will be called when keyboard is shown, hidden or its size is changed. Instantiate the KBKeyboardHandlerand set its delegate (typically self). See sample MyViewControllerbelow.

在您的项目中包含 KBKeyboardHandler.h、KBKeyboardHandler.m 和 KBKeyboardHandlerDelegate.h。KBKeyboardHandlerDelegate在您的视图控制器中实现协议 - 它由一个方法组成,当键盘显示、隐藏或更改大小时将调用该方法。实例化KBKeyboardHandler并设置它的委托(通常是 self)。请参阅MyViewController下面的示例。

KBKeyboardHandler.h:

KBKeyboardHandler.h:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@protocol KBKeyboardHandlerDelegate;

@interface KBKeyboardHandler : NSObject

- (id)init;

// Put 'weak' instead of 'assign' if you use ARC
@property(nonatomic, assign) id<KBKeyboardHandlerDelegate> delegate; 
@property(nonatomic) CGRect frame;

@end

KBKeyboardHandler.m:

KBKeyboardHandler.m:

#import "KBKeyboardHandler.h"
#import "KBKeyboardHandlerDelegate.h"

@implementation KBKeyboardHandler

- (id)init
{
    self = [super init];
    if (self)
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillShow:)
                                                     name:UIKeyboardWillShowNotification
                                                   object:nil];

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

    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

@synthesize delegate;
@synthesize frame;

- (void)keyboardWillShow:(NSNotification *)notification
{
    CGRect oldFrame = self.frame;    
    [self retrieveFrameFromNotification:notification];

    if (oldFrame.size.height != self.frame.size.height)
    {
        CGSize delta = CGSizeMake(self.frame.size.width - oldFrame.size.width,
                                  self.frame.size.height - oldFrame.size.height);
        if (self.delegate)
            [self notifySizeChanged:delta notification:notification];
    }
}

- (void)keyboardWillHide:(NSNotification *)notification
{
    if (self.frame.size.height > 0.0)
    {
        [self retrieveFrameFromNotification:notification];
        CGSize delta = CGSizeMake(-self.frame.size.width, -self.frame.size.height);

        if (self.delegate)
            [self notifySizeChanged:delta notification:notification];
    }

    self.frame = CGRectZero;
}

- (void)retrieveFrameFromNotification:(NSNotification *)notification
{
    CGRect keyboardRect;
    [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardRect];
    self.frame = [[UIApplication sharedApplication].keyWindow.rootViewController.view convertRect:keyboardRect fromView:nil];
}

- (void)notifySizeChanged:(CGSize)delta notification:(NSNotification *)notification
{
    NSDictionary *info = [notification userInfo];

    UIViewAnimationOptions curve;
    [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];

    NSTimeInterval duration;
    [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration];

    void (^action)(void) = ^{
        [self.delegate keyboardSizeChanged:delta];
    };

    [UIView animateWithDuration:duration
                          delay:0.0
                        options:curve
                     animations:action
                     completion:nil];    
}

@end

KBKeyboardHandlerDelegate.h:

KBKeyboardHandlerDelegate.h:

@protocol KBKeyboardHandlerDelegate

- (void)keyboardSizeChanged:(CGSize)delta;

@end

Sample MyViewController.h:

示例MyViewController.h

@interface MyViewController : UIViewController<KBKeyboardHandlerDelegate>
...
@end

Sample MyViewController.m:

示例MyViewController.m

@implementation MyViewController
{
    KBKeyboardHandler *keyboard;
}

- (void)dealloc
{
    keyboard.delegate = nil;
    [keyboard release];
    [super dealloc];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    keyboard = [[KBKeyboardHandler alloc] init];
    keyboard.delegate = self;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    keyboard.delegate = nil;
    [keyboard release];
    keyboard = nil;
}

- (void)keyboardSizeChanged:(CGSize)delta
{
    // Resize / reposition your views here. All actions performed here 
    // will appear animated.
    // delta is the difference between the previous size of the keyboard 
    // and the new one.
    // For instance when the keyboard is shown, 
    // delta may has width=768, height=264,
    // when the keyboard is hidden: width=-768, height=-264.
    // Use keyboard.frame.size to get the real keyboard size.

    // Sample:
    CGRect frame = self.view.frame;
    frame.size.height -= delta.height;
    self.view.frame = frame;
}

UPDATE: Fixed iOS 7 warning, thanks @weienv.

更新:修复了 iOS 7 警告,感谢 @weienv。

回答by ComSubVie

I just solved this problem. The solution is a combination of a UIKeyboardDidShowNotificationand UIKeyboardDidHideNotificationobserver with the above textFieldDidBeginEditing:and textFieldDidEndEditing:methods.

我刚刚解决了这个问题。解决方案是将 aUIKeyboardDidShowNotificationUIKeyboardDidHideNotification观察者与上述textFieldDidBeginEditing:textFieldDidEndEditing:方法相结合。

You need three additional variables, one to store the current selected UITextField (which I have named activeField), one to indicate if the current view has been moved, and one to indicate if the keyboard is displayed.

您需要三个附加变量,一个用于存储当前选定的 UITextField(我将其命名为 activeField),一个用于指示当前视图是否已移动,另一个用于指示是否显示键盘。

This is how the two UITextFielddelegate methods look now:

这就是两个UITextField委托方法现在的样子:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    activeField = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    activeField = nil;
    // Additional Code
}

When the view is loaded, the following two observers are created:

加载视图时,会创建以下两个观察者:

- (void)viewDidLoad {
    // Additional Code
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasHidden:)
                                                 name:UIKeyboardDidHideNotification
                                               object:nil];
}

And the corresponding methods are implemented as follows:

相应的方法实现如下:

- (void)keyboardWasShown:(NSNotification *)aNotification {
    if ( keyboardShown )
        return;

    if ( ( activeField != inputAmount ) && ( activeField != inputAge ) ) {
        NSDictionary *info = [aNotification userInfo];
        NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
        CGSize keyboardSize = [aValue CGRectValue].size;

        NSTimeInterval animationDuration = 0.300000011920929;
        CGRect frame = self.view.frame;
        frame.origin.y -= keyboardSize.height-44;
        frame.size.height += keyboardSize.height-44;
        [UIView beginAnimations:@"ResizeForKeyboard" context:nil];
        [UIView setAnimationDuration:animationDuration];
        self.view.frame = frame;
        [UIView commitAnimations];

        viewMoved = YES;
    }

    keyboardShown = YES;
}

- (void)keyboardWasHidden:(NSNotification *)aNotification {
    if ( viewMoved ) {
        NSDictionary *info = [aNotification userInfo];
        NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
        CGSize keyboardSize = [aValue CGRectValue].size;

        NSTimeInterval animationDuration = 0.300000011920929;
        CGRect frame = self.view.frame;
        frame.origin.y += keyboardSize.height-44;
        frame.size.height -= keyboardSize.height-44;
        [UIView beginAnimations:@"ResizeForKeyboard" context:nil];
        [UIView setAnimationDuration:animationDuration];
        self.view.frame = frame;
        [UIView commitAnimations];

        viewMoved = NO;
    }

    keyboardShown = NO;
}

This code works now as expected. The keyboard is only dismissed when the Done button is pressed, otherwise it stays visible and the view is not moved around.

此代码现在按预期工作。只有在按下 Done 按钮时键盘才会关闭,否则它保持可见并且视图不会四处移动。

As an additional note, I think it is possible to get the animationDurationdynamically by asking the NSNotificationobject, since I have already played with a similar solution but didn't get it to work (which it does now).

作为附加说明,我认为可以animationDuration通过询问NSNotification对象来动态获取,因为我已经使用了类似的解决方案,但没有让它起作用(现在确实如此)。

回答by coolcool1994

This view controller must be UITextViewDelegate and you must set self.textview.delegate = selfin viewdidload

这个视图控制器必须是UITextViewDelegate 并且你必须self.textview.delegate = selfviewdidload

 -(void) textViewDidBeginEditing:(UITextView *)textView
    {
        NSLog(@"%f",self.view.frame.origin.y);
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.25f];
        CGRect frame = self.view.frame;
        frame.origin.y =frame.origin.y -204;
        [self.view setFrame:frame];
        [UIView commitAnimations];
    }

-(void) textViewDidEndEditing:(UITextView *)textView
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.25f];
    CGRect frame = self.view.frame;
    frame.origin.y = frame.origin.y + 204;
    [self.view setFrame:frame];
    [UIView commitAnimations];
}

回答by utkal patel

I got your Problem just do simple thing just give outlet to UIScrollview. set unique Tag property for each textfield in view.

我知道你的问题只是做简单的事情,只是给 UIScrollview 提供出口。为视图中的每个文本字段设置唯一的 Tag 属性。

-(void)textFieldDidBeginEditing:(UITextField *)textField
    {   
        switch (textField.tag)
        {
            case 2:    //can be your textfiled tag
              { CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-150); 
                                           //set figure y-150 as per your comfirt
                  [scrollview setContentOffset:scrollPoint animated:YES]; 
             }break;

              case 3:   
              { CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-180); 
                                           //set figure y-180 as per your comfirt
                  [scrollview setContentOffset:scrollPoint animated:YES]; 
             }break;

             ...

         }
    }

    -(void)textFieldDidEndEditing:(UITextField *)textField{

        if(textField.tag==3){
            [scrollview setContentOffset:CGPointZero animated:YES];
                }
         //set the last textfield when you want to disappear keyboard.
    }

回答by Vibhooti

Write below code in your view controller. tbl is your table view. 

-(void)viewWillAppear:(BOOL)animated{


    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
    [[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
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}



#pragma mark - Keyboard Methods
-(void)keyboardWillShow:(NSNotification *)notification
{
//    375 × 667  ( 750 × 1334 ) iPhone 6
    //414 × 736
    CGRect keyboardRect = [[[notification userInfo] valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    int H = [[UIScreen mainScreen] bounds].size.height - 64- 20 -keyboardRect.size.height;
    [UIView animateWithDuration:0.5 animations:^{
        tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, H, tbl.contentInset.right);
    }];
}

-(void)keyboardWillChangeFrame:(NSNotification *)notification
{
    CGRect keyboardRect = [[[notification userInfo] valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
//    int H = IS_IPHONE_5?504-keyboardRect.size.height:416-keyboardRect.size.height;
     int H = [[UIScreen mainScreen] bounds].size.height - 64- 20  -keyboardRect.size.height;
    [UIView animateWithDuration:0.5 animations:^{
        //        scroll.frame = rect;
        tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, H, tbl.contentInset.right);
    }];
}


-(void)keyboardWillHide:(NSNotification *)notification
{

    [UIView animateWithDuration:0.3 animations:^{
        //        scroll.frame = rect;
        tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, 0, tbl.contentInset.right);
    }];
}

回答by Alexey Savchenko

Fairly easy solution, works with all screen sizes

相当简单的解决方案,适用于所有屏幕尺寸

First you have to embed you UITextFields to a UIScrollView. In my case, I had several UITextFields and a UITextView.

首先,您必须将 UITextFields 嵌入到 UIScrollView 中。就我而言,我有几个 UITextFields 和一个 UITextView。

enter image description here

在此处输入图片说明

Then you have to inherit from UITextFieldDelegate, UITextViewDelegate.

然后你必须继承 UITextFieldDelegate,UITextViewDelegate。

class SettingsVC: UIViewController, UITextFieldDelegate, UITextViewDelegate

class SettingsVC: UIViewController, UITextFieldDelegate, UITextViewDelegate

Assign textfield's and textview's delegates to self.

将 textfield 和 textview 的委托分配给 self.

fullNameTextField.delegate = self usernameTextField.delegate = self websiteTextField.delegate = self profileDescription.delegate = self

fullNameTextField.delegate = self usernameTextField.delegate = self websiteTextField.delegate = self profileDescription.delegate = self

Then use this code:

然后使用此代码:

var editingTextInput: UIView!


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

    NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardShown(notification:)),
                                           name: NSNotification.Name.UIKeyboardDidShow,
                                           object: nil)
    

  }
  
    override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
  }
  
  func keyboardShown(notification: NSNotification) {
    
    if let infoKey  = notification.userInfo?[UIKeyboardFrameEndUserInfoKey],
      let rawFrame = (infoKey as AnyObject).cgRectValue {
      
      let keyboardFrame = view.convert(rawFrame, to: view)
      let editingTextInputFrame = self.editingTextInput.convert(self.editingTextInput.frame, to: view)

      
      if editingTextInputFrame.maxY > keyboardFrame.minY{
        
        let diff = keyboardFrame.minY - editingTextInputFrame.maxY
        containerScrollView.setContentOffset(CGPoint(x: 0, y: -diff), animated: true)
        
      }
    }
  }
  
  func textFieldDidBeginEditing(_ textField: UITextField) {
    self.editingTextInput = textField
  }
  
  func textViewDidBeginEditing(_ textView: UITextView) {
    self.editingTextInput = textView
  }
  
  func textFieldDidEndEditing(_ textField: UITextField) {
    containerScrollView.setContentOffset(CGPoint.zero, animated: true)
  }
  
  func textViewDidEndEditing(_ textView: UITextView) {
    containerScrollView.setContentOffset(CGPoint.zero, animated: true)
  }

In short, you subscribe to UIKeyboardDidShow notification. When you tap on textField or textView keyboard is shown and you grab keyboard's frame and frame of input element you have tapped on. Convert them to viewController's coordinate system and compare input element's lowest point to a keyboard's highest. If element's lower part is lower than keyboard's highest, than set offset of containerScrollView to the difference between them.

简而言之,您订阅了 UIKeyboardDidShow 通知。当您点击 textField 或 textView 键盘时,您会抓住键盘的框架和您点击的输入元素框架。将它们转换为 viewController 的坐标系,并将输入元素的最低点与键盘的最高点进行比较。如果元素的下半部分低于键盘的上半部分,则将 containerScrollView 的偏移量设置为它们之间的差值。

if editingTextInputFrame.maxY > keyboardFrame.minY{
            
            let diff = keyboardFrame.minY - editingTextInputFrame.maxY
            containerScrollView.setContentOffset(CGPoint(x: 0, y: -diff), animated: true)
            
          }

res1res2

资源 1资源2

回答by Or?un Deniz

Like I mentioned in this answer:

就像我在这个答案中提到的:

I've developed a framework for my own need to solve this issue better, and made it public now. It's not just for UITextField and UITextView, It works for any custom UIView that adopts UITextInput protocol like UITextField and UITextView and offers many useful features. You can install it via Carthage, CocoaPods or Swift Package Manager.

我已经根据自己的需要开发了一个框架来更好地解决这个问题,现在将其公之于众。它不仅适用于 UITextField 和 UITextView,它还适用于任何采用 UITextInput 协议的自定义 UIView,如 UITextField 和 UITextView,并提供许多有用的功能。你可以通过 Carthage、CocoaPods 或 Swift Package Manager 安装它。

ODScrollView GitHub

ODScrollView GitHub

ODScrollView Medium

ODScrollView 媒体

ODScrollView is just a UIScrollView that automatically moves editable text areas like UITextField and UITextView vertically depending on keyboard visibility to offer better user experience.

ODScrollView 只是一个 UIScrollView,它根据键盘可见性自动垂直移动可编辑文本区域,如 UITextField 和 UITextView,以提供更好的用户体验。

Features

特征

  • Automatically moves first responder UIViews that adopt the UITextInput protocol up/down when the keyboard appears/disappears, e.g., UITextField, UITextView, UISearchTextField or any custom UIView that adopts UITextInput protocol.
    • Note that if UITextInput's frame does NOT fits the remaining area between ODScrollView and keyboard, then ODScrollView adjusts UITextInput based on cursor position instead of frame. In such cases, "trackTextInputCursor" feature can be used. Example
  • Adjustment margin can be applied for each UITextInput seperately for .Top and .Bottom adjustment direction setting. 20 CGFloat by default.

  • Adjustment can be enabled/disabled for each UITextInput seperately. true by default.

  • Adjustment directon - .Top, .Center, .Bottom - can be applied for each UITextInput seperately. .Bottom by default. Example

  • Adjustment options determines how ODScrollView adjusts. .Always by default.
    • .Always : ODScrollView always adjusts the UITextInput which is placed anywhere in the ODScrollView regardless UITextInput overlaps or not with shown keyboard. Example
    • .IfNeeded : ODScrollView only adjusts the UITextInput if it overlaps with the shown keyboard. Example
  • Besides UIScrollView.keyboardDismissModes, the keyboard can be dismissed by tapping a UIView which is provided by ODScrollViewDelegate. After the keyboard is dismissed, ODScrollView can return its original position. nil and false by default. Example
  • 当键盘出现/消失时,自动向上/向下移动采用 UITextInput 协议的第一响应者 UIViews,例如 UITextField、UITextView、UISearchTextField 或任何采用 UITextInput 协议的自定义 UIView。
    • 请注意,如果 UITextInput 的框架不适合 ODScrollView 和键盘之间的剩余区域,则 ODScrollView 根据光标位置而不是框架调整 UITextInput。在这种情况下,可以使用“trackTextInputCursor”功能。例子
  • 对于 .Top 和 .Bottom 调整方向设置,可以分别为每个 UITextInput 应用调整边距。默认为 20 CGFloat。

  • 可以分别为每个 UITextInput 启用/禁用调整。默认为真。

  • 调整方向 - .Top, .Center, .Bottom - 可以单独应用于每个 UITextInput。.默认为底部。例子

  • 调整选项决定了 ODScrollView 如何调整。.始终默认。
    • .Always : ODScrollView 始终调整放置在 ODScrollView 中任意位置的 UITextInput,无论 UITextInput 是否与显示的键盘重叠。例子
    • .IfNeeded : ODScrollView 仅在 UITextInput 与显示的键盘重叠时调整它。例子
  • 除了 UIScrollView.keyboardDismissModes 之外,还可以通过点击 ODScrollViewDelegate 提供的 UIView 来关闭键盘。键盘关闭后,ODScrollView 可以返回原来的位置。默认为 nil 和 false。例子

Usage

用法

1 -First thing you need to do is setting up ODScrollView and its content view properly. Since ODScrollView is just a UIScrollView, you can implement ODScrollView same way you do for UIScrollView. It's up to you to create ODScrollView by using storyboard or programmatically.

1 -您需要做的第一件事是正确设置 ODScrollView 及其内容视图。由于 ODScrollView 只是一个 UIScrollView,因此您可以按照与 UIScrollView 相同的方式实现 ODScrollView。您可以使用故事板或以编程方式创建 ODScrollView。

If you're creating ODScrollView programmatically, you can continue from step 4.

如果您以编程方式创建 ODScrollView,则可以从第 4 步继续。

Suggested way to create UIScrollView in Storyboard

在 Storyboard 中创建 UIScrollView 的建议方法

- If you are using Content Layout Guide and Frame Layout Guide:
    1.1 - scrollView: Place UIScrollView anywhere you want to use.  
    1.2 - contentView: Place UIView inside scrollView.
    1.3 - Set contentView's top, bottom, leading and trailing constraints to Content Layout Guide's constraints.
    1.4 - Set contentView's width equal to Frame Layout Guide's width.
    1.5 - Set contentView's height equal to Frame Layout Guide's height or set static height which is larger than scrollView's height.
    1.6 - Build your UI inside contentView.

- If you are NOT using Content Layout Guide and Frame Layout Guide:
    1.1 - scrollView: Place UIScrollView anywhere you want to use.  
    1.2 - contentView: Place UIView inside scrollView.
    1.3 - Set contentView's top, bottom, leading and trailing constraints to 0.
    1.4 - Set contentView's width equal to scrollView's width.
    1.5 - Set contentView's height equal to scrollView's superview's height or set static height which is larger than scrollView's height.
    1.6 - Build your UI inside contentView.

2 -Change the scrollView's class from UIScrollView to ODScrollView in the identity inspector on Storyboard.

2 -在 Storyboard 的身份检查器中将 scrollView 的类从 UIScrollView 更改为 ODScrollView。

3 -Create IBOutlets for scrollView and contentView on ViewController.

3 -在 ViewController 上为 scrollView 和 contentView 创建 IBOutlets。

4 -Call the following methods inside ViewDidLoad() on ViewController:

4 -在 ViewController 的 ViewDidLoad() 中调用以下方法:

override func viewDidLoad() {
    super.viewDidLoad()

    //ODScrollView setup
    scrollView.registerContentView(contentView)
    scrollView.odScrollViewDelegate = self
}  

5 -Optional: You still can use UIScrollView's features:

5 -可选:您仍然可以使用 UIScrollView 的功能:

override func viewDidLoad() {
    super.viewDidLoad()

    //ODScrollView setup
    scrollView.registerContentView(contentView)
    scrollView.odScrollViewDelegate = self

    // UIScrollView setup
    scrollView.delegate = self // UIScrollView Delegate
    scrollView.keyboardDismissMode = .onDrag // UIScrollView keyboardDismissMode. Default is .none.

    UITextView_inside_contentView.delegate = self
}

6 -Adopt ODScrollViewDelegate from ViewController and decide ODScrollView options:

6 -从 ViewController 中采用 ODScrollViewDelegate 并决定 ODScrollView 选项:

extension ViewController: ODScrollViewDelegate {

    // MARK:- State Notifiers: are responsible for notifiying ViewController about what is going on while adjusting. You don't have to do anything if you don't need them.

    // #Optional
    // Notifies when the keyboard showed.
    func keyboardDidShow(by scrollView: ODScrollView) {}

    // #Optional
    // Notifies before the UIScrollView adjustment.
    func scrollAdjustmentWillBegin(by scrollView: ODScrollView) {}

    // #Optional
    // Notifies after the UIScrollView adjustment.
    func scrollAdjustmentDidEnd(by scrollView: ODScrollView) {}

    // #Optional
    // Notifies when the keyboard hid.
    func keyboardDidHide(by scrollView: ODScrollView) {}

    // MARK:- Adjustment Settings

    // #Optional
    // Specifies the margin between UITextInput and ODScrollView's top or bottom constraint depending on AdjustmentDirection
    func adjustmentMargin(for textInput: UITextInput, inside scrollView: ODScrollView) -> CGFloat {
        if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {
            return 20
        } else {
            return 40
        }
    }

    // #Optional
    // Specifies that whether adjustment is enabled or not for each UITextInput seperately.
    func adjustmentEnabled(for textInput: UITextInput, inside scrollView: ODScrollView) -> Bool {
        if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {
            return true
        } else {
            return false
        }
    }


    // Specifies adjustment direction for each UITextInput. It means that  some of UITextInputs inside ODScrollView can be adjusted to the bottom, while others can be adjusted to center or top.
    func adjustmentDirection(selected textInput: UITextInput, inside scrollView: ODScrollView) -> AdjustmentDirection {
        if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {
            return .bottom
        } else {
            return .center
        }
    }

    /**
     - Always : ODScrollView always adjusts the UITextInput which is placed anywhere in the ODScrollView.
     - IfNeeded : ODScrollView only adjusts the UITextInput if it overlaps with the shown keyboard.
     */
    func adjustmentOption(for scrollView: ODScrollView) -> AdjustmentOption {
        .Always
    }

    // MARK: - Hiding Keyboard Settings

    /**
     #Optional

     Provides a view for tap gesture that hides keyboard.

     By default, keyboard can be dismissed by keyboardDismissMode of UIScrollView.

     keyboardDismissMode = .none
     keyboardDismissMode = .onDrag
     keyboardDismissMode = .interactive

     Beside above settings:

     - Returning UIView from this, lets you to hide the keyboard by tapping the UIView you provide, and also be able to use isResettingAdjustmentEnabled(for scrollView: ODScrollView) setting.

     - If you return nil instead of UIView object, It means that hiding the keyboard by tapping is disabled.
     */
    func hideKeyboardByTappingToView(for scrollView: ODScrollView) -> UIView? {
        self.view
    }

    /**
     #Optional

     Resets the scroll view offset - which is adjusted before - to beginning its position after keyboard hid by tapping to the provided UIView via hideKeyboardByTappingToView.

     ## IMPORTANT:
     This feature requires a UIView that is provided by hideKeyboardByTappingToView().
     */
    func isResettingAdjustmentEnabled(for scrollView: ODScrollView) -> Bool {
        true
    }
}

7 -Optional: You can adjust the ODScrollView when the cursor overlaps with keyboard while typing in multiline UITextInput. trackTextInputCursor(for UITextInput) must be called by UITextInput functions that is fired while typing.

7 -可选:您可以在输入多行 UITextInput 时,当光标与键盘重叠时调整 ODScrollView。trackTextInputCursor(for UITextInput) 必须由键入时触发的 UITextInput 函数调用。

/**
## IMPORTANT:
This feature is not going to work unless textView is subView of _ODScrollView
*/
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
       _ODScrollView.trackTextInputCursor(for textView)
   return true
}