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

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


当前回答

这是使用Swift的解决方案。

import UIKit

class ExampleViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var scrollView: UIScrollView!

    @IBOutlet var textField1: UITextField!
    @IBOutlet var textField2: UITextField!
    @IBOutlet var textField3: UITextField!
    @IBOutlet var textField4: UITextField!
    @IBOutlet var textField5: UITextField!

    var activeTextField: UITextField!

    // MARK: - View
    override func viewDidLoad() {
        super.viewDidLoad()
        self.textField1.delegate = self
        self.textField2.delegate = self
        self.textField3.delegate = self
        self.textField4.delegate = self
        self.textField5.delegate = self
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.registerForKeyboardNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        self.unregisterFromKeyboardNotifications()
    }

    // MARK: - Keyboard

    // Call this method somewhere in your view controller setup code.
    func registerForKeyboardNotifications() {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
        center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
    }

    func unregisterFromKeyboardNotifications () {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil)
        center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }

    // Called when the UIKeyboardDidShowNotification is sent.
    func keyboardWasShown (notification: NSNotification) {
        let info : NSDictionary = notification.userInfo!
        let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size

        let contentInsets: UIEdgeInsets = 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 app might not need or want this behavior.
        var aRect = self.view.frame
        aRect.size.height -= kbSize.height;
        if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) {
            self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
        }
    }

    // Called when the UIKeyboardWillHideNotification is sent
    func keyboardWillBeHidden (notification: NSNotification) {
        let contentInsets = UIEdgeInsetsZero;
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // MARK: -  Text Field

    func textFieldDidBeginEditing(textField: UITextField) {
        self.activeTextField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        self.activeTextField = nil
    }

}

其他回答

一直在为初学者寻找关于这个主题的好教程,在这里找到了最好的教程。

在教程底部的MIScrollView.h示例中,确保在

@property (nonatomic, retain) id backgroundTapDelegate;

如您所见。

这对我有用:

func setupKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWasShown:"), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillBeHidden:"), name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWasShown(aNotification:NSNotification) {
    let info = aNotification.userInfo
    let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
    let kbSize = infoNSValue.CGRectValue().size
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.3)
    var rect : CGRect = self.view.frame
    rect.size.height -= kbSize.height

    self.view.frame = rect
    UIView.commitAnimations()
}

func keyboardWillBeHidden(aNotification:NSNotification) {
    let info = aNotification.userInfo
    let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
    let kbSize = infoNSValue.CGRectValue().size
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.3)
    var rect : CGRect = self.view.frame
    rect.size.height += kbSize.height
    self.view.frame = rect
    UIView.commitAnimations()
}

刚找到这个类:

https://github.com/OliverLetterer/SLScrollViewKeyboardSupport

到目前为止,它在iPhone上运行得很好,包括动画和正确的偏移。

要使用它,只需添加到viewDidLoad:

self.support = [[SLScrollViewKeyboardSupport alloc] initWithScrollView:self.scrollView];

这是我为特定布局想出的破解方案。此解决方案与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,我没有时间学习内部布局引擎。

这里是我创建的UITextfield(和其他类似的字段)类别,它将使文本字段避开键盘,您应该能够将其按原样放置在视图控制器中,它应该可以工作。它将整个屏幕向上移动,使当前文本字段位于带有动画的键盘上方

#import "UIView+avoidKeyboard.h"
#import "AppDelegate.h"

@implementation UIView (avoidKeyboard)

- (void) becomeFirstResponder {

if(self.isFirstResponder)
    return;

[super becomeFirstResponder];

if ([self isKindOfClass:[UISearchBar class]] ||
    [self isKindOfClass:[UITextField class]] ||
    [self isKindOfClass:[UITextView class]])
{
    AppDelegate *appDelegate    = [UIApplication sharedApplication].delegate;

    CGRect screenBounds         = appDelegate.window.frame;

    CGFloat keyboardHeight;
    CGFloat keyboardY;
    CGFloat viewsLowestY;
    CGPoint origin              = [self.superview convertPoint:self.frame.origin toView:appDelegate.window]; //get this views origin in terms of the main screens bounds

    if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){ //the window.frame doesnt take its orientation into account so if its sideways we must use the x value of the origin instead of the y
        keyboardHeight          = 216;
        keyboardY               = screenBounds.size.height  - keyboardHeight; //find the keyboards y coord relative to how much the main window has moved up
        viewsLowestY            = origin.y + self.frame.size.height; //find the lowest point of this view
    }
    else {
        keyboardHeight          = 162;
        keyboardY               = screenBounds.size.width  - keyboardHeight;
        viewsLowestY            = origin.x + self.frame.size.height;
    }

    CGFloat difference          = viewsLowestY - keyboardY + 20; //find if this view overlaps with the keyboard with some padding

    if (difference > 0){ //move screen up if there is an overlap

        [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{

            CGRect frame = appDelegate.window.frame;

            if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){
                frame.origin.y -= difference;
            }
            else {
                frame.origin.x -= difference;
            }
            appDelegate.window.frame = frame;
        }
        completion:nil];
    }
}
}

//look at appDelegate to see when the keyboard is hidden

@end

在appDelegate中添加此函数

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHides:) name:UIKeyboardWillHideNotification object:nil]; //add in didFinishLaunchingWithOptions

...

- (void)keyboardHides:(NSNotification *)notification
{
    [UIView animateWithDuration:0.3 animations:^{
        [window setFrame: CGRectMake(0, 0, window.frame.size.width, window.frame.size.height)];
    } completion:nil];
}