使用iOS SDK:

我有一个带UITextFields的UIView,可以启动键盘。我需要它能够:

启动键盘后,允许滚动UIScrollView的内容以查看其他文本字段自动“跳转”(通过向上滚动)或缩短

我知道我需要一个UIScrollView。我已经尝试将UIView的类更改为UIScrollView,但仍然无法上下滚动文本框。

我需要UIView和UIScrollView吗?一个在另一个里面吗?

要自动滚动到活动文本字段,需要执行哪些操作?

理想情况下,尽可能多的组件设置将在Interface Builder中完成。我只想编写需要的代码。

注意:我使用的UIView(或UIScrollView)是由一个选项卡(UITabBar)启动的,它需要正常工作。


我正在添加滚动条,只为键盘出现时使用。尽管不需要它,但我觉得它提供了一个更好的界面,例如,用户可以滚动和更改文本框。

当键盘上下移动时,我可以改变UIScrollView的框架大小。我只是在使用:

-(void)textFieldDidBeginEditing:(UITextField *)textField {
    //Keyboard becomes visible
    scrollView.frame = CGRectMake(scrollView.frame.origin.x,
                                  scrollView.frame.origin.y,
    scrollView.frame.size.width,
    scrollView.frame.size.height - 215 + 50);   // Resize
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
    // Keyboard will hide
    scrollView.frame = CGRectMake(scrollView.frame.origin.x,
                                  scrollView.frame.origin.y,
                                  scrollView.frame.size.width,
                                  scrollView.frame.size.height + 215 - 50); // Resize
}

然而,这不会自动“向上移动”或将可见区域中的下部文本字段居中,这是我真正想要的。


当前回答

使用IQKeyboardManager,出现键盘时,UITextField和UITextView会自动滚动。Git链接:https://github.com/hackiftekhar/IQKeyboardManager.

豆荚:pod“IQKeyboardManager”#iOS8及更高版本

吊舱“IQKeyboardManager”,“3.3.7”#iOS7

其他回答

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

ODScrollView GitHub

ODScrollView中等

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

特征

当键盘出现/消失时,自动向上/向下移动采用UITextInput协议的第一响应者UIView,例如UITextField、UITextView、UISearchTextField或任何采用UITextOutput协议的自定义UIView。注意,如果UITextInput的框架不适合ODScrollView和键盘之间的剩余区域,则ODScrollView将根据光标位置而不是框架调整UITextInput。在这种情况下,可以使用“trackTextInputCursor”功能。实例可以分别为每个UITextInput应用调整裕度,用于.顶部和.底部调整方向设置。默认情况下为20 CGFloat。可以分别为每个UITextInput启用/禁用调整。默认情况下为true。调整方向-顶部、中心、底部-可分别应用于每个UITextInput。默认情况下为底部。实例调整选项决定ODScrollView如何调整。始终默认。始终:无论UITextInput是否与显示的键盘重叠,ODScrollView始终调整放置在ODScrollView中任何位置的UITextInput。实例.IfNeedd:ODScrollView仅在UITextInput与显示的键盘重叠时调整UITextInput。实例除了UIScrollView.keyboardDismissModes之外,还可以通过点击ODScrollViewDelegate提供的UIView来关闭键盘。键盘关闭后,ODScrollView可以返回其原始位置。默认情况下为nil和false。实例

用法

1-您需要做的第一件事是正确设置ODScrollView及其内容视图。由于ODScrollView只是一个UIScrollView,所以您可以像对UIScroll View一样实现ODScroll视图。您可以使用故事板或编程方式创建ODScrollView。

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

在情节提要中创建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-在Storyboard上的身份检查器中将scrollView的类从UIScrollView更改为ODScrollView。

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

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

override func viewDidLoad() {
    super.viewDidLoad()

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

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-采用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-可选:当在多行UITextInput中键入时光标与键盘重叠时,可以调整ODScrollView。trackTextInputCursor(用于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
}

对于通用解决方案,这是我实现IQKeyboardManager的方法。

步骤1:-我在单例类中添加了UITextField、UITextView和UIKeyboard的全局通知。我叫它IQKeyboardManager。

步骤2:-如果找到UIKeyboardWillShowNotification、UITextFieldTextDidBegginEditingNotification或UITextViewTextDidBedginEditingNotice通知,我尝试从UIWindow.rootViewController层次结构获取topMostViewController实例。为了正确显示UITextField/UITextView,需要调整topMostViewController.view的框架。

步骤3:-我计算了topMostViewController.view相对于第一个响应的UITextField/UITextView的预期移动距离。

步骤4:-我根据预期的移动距离向上/向下移动topMostViewController.view.frame。

步骤5:-如果找到UIKeyboardWillHideNotification、UITextFieldTextDidEndEditingNotification或UITextViewTextDidEndEditingNotification通知,我再次尝试从UIWindow.rootViewController层次结构获取topMostViewController实例。

步骤6:-我计算了topMostViewController.view的干扰距离,需要将其恢复到原始位置。

第7步:-我根据干扰距离恢复了topMostViewController.view.frame。

步骤8:-我在应用程序加载时实例化了单例IQKeyboardManager类实例,因此应用程序中的每个UITextField/UUITextView都将根据预期的移动距离自动调整。

这就是IQKeyboardManager在没有代码行的情况下为您所做的一切!!只需将相关的源文件拖放到项目即可。IQKeyboardManager还支持设备定向、自动UIToolbar管理、KeybkeyboardDistanceFromTextField等功能,远远超出您的想象。

扩展UIViewController的简单解决方案

https://github.com/damienromito/VisibleFormViewController

在视图中设置滚动视图

  - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
     CGPoint point;
    if(textField == txtEmail){
      // -90 is for my you can change as per your postion
      point = CGPointMake(0, textField.frame.origin.y - 90);
    }
    else if (textField == txtContact){
      point = CGPointMake(0, textField.frame.origin.y - 90);
    }
      [scrollV setContentOffset:point animated:YES];
    }

您不需要为一个简单的任务编写这么多代码。有一个名为“IQKeyboardManager”的CocoaPod将为您完成任务:

pod 'IQKeyboardManager'

然后在从didFinishLaunchingWithOptions返回之前,在AppDelegate中使用以下代码:

IQKeyboardManager.shared().isEnabled = true
IQKeyboardManager.shared().shouldResignOnTouchOutside = true
IQKeyboardManager.shared().isEnableAutoToolbar = false