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

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


当前回答

这是我为特定布局想出的破解方案。此解决方案与Matt Gallagher的解决方案相似,即将一个部分滚动到视图中。我还是iPhone开发的新手,不熟悉布局的工作原理。因此,这个黑客。

我的实现需要支持在字段中单击时滚动,以及用户在键盘上选择下一个时滚动。

我有一个UIView,身高775。控件基本上以3人一组的方式分布在一个大的空间中。我最终得到了以下IB布局。

UIView -> UIScrollView -> [UI Components]

黑客来了

我将UIScrollView的高度设置为比实际布局(1250)大500个单位。然后,我创建了一个数组,其中包含我需要滚动到的绝对位置,以及一个基于IB标记号获取它们的简单函数。

static NSInteger stepRange[] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};

NSInteger getScrollPos(NSInteger i) {
    if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
        return 0 ;
    return stepRange[i] ;
}

现在,您需要做的就是在textFieldDidBeginEditing和textFieldShouldReturn中使用以下两行代码(如果要创建下一个字段导航,则使用后者)

CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;

一个例子。

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
    [self.scrollView setContentOffset:point animated:YES] ;
}


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

    NSInteger nextTag = textField.tag + 1;
    UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];

    if (nextResponder) {
        [nextResponder becomeFirstResponder];
        CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
        [self.scrollView setContentOffset:point animated:YES] ;
    }
    else{
        [textField resignFirstResponder];
    }

    return YES ;
}

此方法不像其他方法那样“向后滚动”。这不是必需的。同样,这是一个相当“高大”的UIView,我没有时间学习内部布局引擎。

其他回答

一种更简单但通用的方法,就像苹果的做法一样,将键盘的高度考虑在内,这在我们使用键盘顶部的自定义工具栏时非常有用。尽管苹果在这方面的做法没有什么问题。

这是我的方法(略微修改了苹果的方法)-

// UIKeyboardDidShowNotification
- (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);
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}

// UIKeyboardWillHideNotification
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}

Swift 3.0版本的苹果键盘管理代码如下:以下代码中使用的FloatingTF是iOS中基于材质设计的文本字段。

import UIKit
class SignupViewController: UIViewController, UITextFieldDelegate {

    //MARK: - IBOutlet:
@IBOutlet weak var emailTF: FloatingTF!
@IBOutlet weak var passwordTF: FloatingTF!
@IBOutlet weak var dobTF: FloatingTF!

@IBOutlet weak var scrollView: UIScrollView!

//MARK: - Variable:
var activeTextField: UITextField!

//MARK: - ViewController Lifecycle:
override func viewDidLoad() {
    super.viewDidLoad()        
    emailTF.delegate = self
    passwordTF.delegate = self
    dobTF.delegate = self 
}
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

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

   deRegisterKeyboardNotifications()
}

//MARK: - Keyboard notification observer Methods
fileprivate func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
fileprivate func deRegisterKeyboardNotifications() {
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: self.view.window)
}
func keyboardWillShow(notification: NSNotification) {

    let info: NSDictionary = notification.userInfo! as NSDictionary
    let value: NSValue = info.value(forKey: UIKeyboardFrameBeginUserInfoKey) as! NSValue
    let keyboardSize: CGSize = value.cgRectValue.size
    let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your app might not need or want this behavior.
    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardSize.height
    let activeTextFieldRect: CGRect? = activeTextField?.frame
    let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin
    if (!aRect.contains(activeTextFieldOrigin!)) {
        scrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
    }    }

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

//MARK: - UITextField Delegate Methods
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if textField == emailTF {
        passwordTF.becomeFirstResponder()
    }
    else if textField == passwordTF {
        dobTF.becomeFirstResponder()
    }
    else {
        self.view.endEditing(true)
    }
    return true
}

func textFieldDidBeginEditing(_ textField: UITextField) {
    activeTextField = textField
    scrollView.isScrollEnabled = true
}

func textFieldDidEndEditing(_ textField: UITextField) {
    activeTextField = nil
    scrollView.isScrollEnabled = false
}
}

首先,我为您的页面推荐一个更好的设计,这样就不需要滚动视图。如果您有许多文本字段,您仍然不必使用ScrollView,这只会使事情变得复杂。您只需在控制器原始视图的顶部添加一个容器UIView,然后将这些文本字段放在该视图上。当键盘显示或消失时,只需使用动画移动此容器视图。

在(BOOL)textFieldShouldBeginEditing:(UITextField*)textField中

if (textField.frame.origin.y > self.view.frame.size.height - 216)
    {
        if (screenHeight>500)
            scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 100);
        else
            scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 216);
        CGPoint scrollPoint = CGPointMake(0.0,(textField.frame.origin.y - (self.view.frame.size.height - 216 - textField.frame.size.height - 20)));
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
    [scrollView setScrollEnabled:YES];

辞职时,你需要写以下代码

scrollView.contentSize = CGSizeMake(0.0, 640);
CGPoint scrollPoint = CGPointMake(0.0,0.0);
[scrollView setContentOffset:scrollPoint animated:YES]; 

雨燕5

在viewDidLoad或viewDidAppear中添加addKeyboardObserver方法。

fileprivate func addKeyboardObservers(){
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

fileprivate func removeKeyboardObservers(){
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}


@objc fileprivate func keyboardWillHide(_ notification: Notification){
    if (window == nil) {return}
    guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}

   scrollView.contentInset.bottom = .zero
}


@objc fileprivate func keyboardWillShow(_ notification: Notification){
    if (window == nil) {return}
    if UIApplication.shared.applicationState != .active { return }

    // keyboard height
    guard let height = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height else {return}
    // keyboard present animation duration
    guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}

   scrollView.contentInset.bottom = height
}

不要忘记删除或消失观察者

    self.removeKeyboardObservers()