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

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


当前回答

根据文档,从iOS 3.0开始,当有文本字段的在线编辑时,UITableViewController类会自动调整其表视图的大小并重新定位。我认为将文本字段放在UITableViewCell中是不够的,正如一些人所指出的那样。

从文档中:

表视图控制器支持表视图行的内联编辑;例如,如果行在编辑模式下嵌入了文本字段滚动虚拟键盘上方正在编辑的行显示。

其他回答

我发现@DK_是我开始使用的解决方案。然而,假设scrollView覆盖了整个视图。我不是这样的。我只想要一个滚动视图,以防键盘覆盖了登录屏幕上的下文本字段。因此,我的内容视图与滚动视图大小相同,比主视图小。

它也没有考虑到景观,这是我开始遇到麻烦的地方。玩了几天后,这是我的键盘显示:方法。

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    // A lot of the inspiration for this code came from http://stackoverflow.com/a/4837510/594602
    CGFloat height = 0;
    NSDictionary* info = [aNotification userInfo];

    CGRect kbFrameRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect kbBoundsRect = [self.view convertRect:kbFrameRect fromView:nil]; // Convert frame from window to view coordinates.

    CGRect scrollRect = scrollView.frame;
    CGRect intersect = CGRectIntersection(kbBoundsRect, scrollRect);

    if (!CGRectIsNull(intersect))
    {
        height = intersect.size.height;
        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // Figure out what the view rectangle is for the scrollView
    CGPoint contentOffset = scrollView.contentOffset;
    CGRect visibleRect = CGRectOffset(scrollRect, contentOffset.x, contentOffset.y);    // I'm not 100% sure if this is needed/right. My scrollView was always at the top in testing.
    visibleRect.size.height -= height;
    CGRect activeRect = activeField.frame;

    if (!CGRectContainsRect(visibleRect, activeRect))
    {
        [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
    }
}

我在使用自动布局时也遇到了一些困难。如果我没有正确完成布局,我就没有得到预期的滚动效果。有一件事让生活变得更加简单,那就是将所有要滚动的项目放在一个视图中,并将其作为滚动视图中的唯一项目。我把这个单一视图称为“内容视图”。

我认为关键部分是内容视图有一个设定的宽度和高度。这使得滚动视图能够准确地知道需要处理多少内容。这与通常的布局有点不同。通常情况下,视图会尽量占据更多空间。对于滚动视图的内容,您试图使视图尽可能地限制自己。内容视图允许您停止此操作。所以我给了我248的高度,并使用320的标准屏幕宽度作为我的宽度。

最终对我有用的布局如下:

滚动视图到超级视图:基本上我给了顶部、左侧和右侧的约束。水平空间-视图-滚动视图(0)垂直空间-视图-滚动视图(0)水平空间-滚动视图-视图(0)滚动视图高度:我将滚动视图设置为恒定高度。我不知道这是否真的有必要,但它有滚动视图本身的界限。高度-(248)-滚动视图滚动视图的内容视图:我给了所有方面的常量,顶部、左侧、底部和右侧。垂直空间-视图-滚动视图(0)垂直空间-滚动视图-视图(0)水平空间-视图-滚动视图(0)水平空间-滚动视图-视图(0)内容视图的维度。高度-(248)-视图宽度-(320)-视图

@用户271753

要恢复原始视图,请添加:

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
   [textField resignFirstResponder];
   [self setViewMovedUp:NO];
   return YES;
}

如果您现在的内容不适合iPhone屏幕,您只需要一个ScrollView。(如果您添加ScrollView作为组件的超级视图,只是为了在键盘启动时使TextField向上滚动,那么就不需要了。)防止TextFields被键盘覆盖的标准方法是在显示键盘时向上/向下移动视图。

下面是一些示例代码:

#define kOFFSET_FOR_KEYBOARD 80.0

-(void)keyboardWillShow {
    // Animate the current view out of the way
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)keyboardWillHide {
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:mailTf])
    {
        //move the main view, so that the keyboard does not hide it.
        if  (self.view.frame.origin.y >= 0)
        {
            [self setViewMovedUp:YES];
        }
    }
}

//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3]; // if you want to slide up the view

    CGRect rect = self.view.frame;
    if (movedUp)
    {
        // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
        // 2. increase the size of the view so that the area behind the keyboard is covered up.
        rect.origin.y -= kOFFSET_FOR_KEYBOARD;
        rect.size.height += kOFFSET_FOR_KEYBOARD;
    }
    else
    {
        // revert back to the normal state.
        rect.origin.y += kOFFSET_FOR_KEYBOARD;
        rect.size.height -= kOFFSET_FOR_KEYBOARD;
    }
    self.view.frame = rect;

    [UIView commitAnimations];
}


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // register for keyboard notifications
    [[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];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

我在这里没有看到这种可能性,所以我添加了它,因为我尝试了答案中的方法,但几个小时后发现在iOS6/7中的XCode 5中有一种更简单的方法:使用NSLayoutConstraints。

请参见:自动布局约束-键盘

这是我的代码:

.m文件:

// Called when the UIKeyboardWillShowNotification is sent.
- (void)keyboardWillBeShown:(NSNotification*)aNotification
{
    NSLog(@"keyboardWillBeShown:");
    [self.PhoneNumberLabelOutlet setHidden:TRUE];
    CGFloat heightOfLabel = self.PhoneNumberLabelOutlet.frame.size.height;
    for( NSLayoutConstraint* thisConstraint in self.topElementsVerticalDistanceFromTopLayoutConstraint ) {
        thisConstraint.constant -= heightOfLabel;
    }

    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGFloat oldConstant = [self.SignInYConstraint constant];
    self.SignInYConstraint.constant = oldConstant + kbSize.height;
    [self.view setNeedsUpdateConstraints];

    NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration:duration animations:^{
        [self.view layoutIfNeeded];
    }];

}

.h文件:

#import <UIKit/UIKit.h>

@interface SignInViewController : UIViewController {

    UITextField* _activeField;
}




- (void)signInCallback:(NSObject*)object;


@property (weak, nonatomic) IBOutlet UILabel *PhoneNumberLabelOutlet;

@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicatorOutlet;

@property (weak, nonatomic) IBOutlet UITextField *UserIDTextfieldOutlet;

@property (weak, nonatomic) IBOutlet UITextField *PasswordTextfieldOutlet;

@property (weak, nonatomic) IBOutlet UIButton *SignInButton;

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *SignInYConstraint;

@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *topElementsVerticalDistanceFromTopLayoutConstraint;

@end

对于通用解决方案,这是我实现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等功能,远远超出您的想象。