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

其他回答

Shiun表示:“事实证明,我相信UIScrollView实际上隐式地将当前编辑的UITextField带入可视窗口。”这似乎适用于iOS 3.1.3,但不适用于3.2、4.0或4.1。为了使UITextField在iOS上可见,我必须添加一个显式的scrollRectToVisible。

我发现@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)-视图

一个更为优雅的解决方案是使用UIView子类(虽然这并不总是合适的),并在父帧更改时重新计算所有子视图(并且要聪明:只有在新帧大小发生更改时才重新计算它们,即在重写setFrame和调用[super setFrame:frame_]之前使用CGRectEqualToRect来比较新帧)。唯一的缺点是,您打算使用的UIViewController可能应该监听键盘事件(或者,您可以在UIView本身中进行监听,以方便封装)。但只有UIKeyboardWillShowNotification和UIKeyboard WillHideNotification。这只是为了让它看起来平滑(如果你等待CG调用它,你会得到一个波涛汹涌的时刻)。

无论如何,这有一个优点,那就是构建一个做正确事情的UIView子类。

天真的实现是重写drawRect:(不要),更好的方法是只使用layoutSubviews(然后在UIViewController中,或者在为显示或隐藏调用的SINGLE方法中调用[view setNeedsLayout])。

此解决方案摆脱了硬编码键盘偏移(如果它们不在拆分等中,则会发生变化),还意味着您的视图可以是许多其他视图的子视图,并且仍然可以正确响应。

除非没有其他解决方案,否则不要硬编码这样的东西。如果你做得对,操作系统会给你足够的信息,你只需要智能地重新绘制(基于你的新帧大小)。这要干净得多,而且是你应该做的事情。(不过,可能还有更好的方法。)

干杯

有这么多的解决方案,但我花了几个小时才开始工作。因此,我将此代码放在这里(只需粘贴到项目中,无需进行任何修改):

@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{
    UITextField* activeField;
    UIScrollView *scrollView;
}
@end

- (void)viewDidLoad
{
    [super viewDidLoad];

    scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];

    //scrool view must be under main view - swap it
    UIView* natView = self.view;
    [self setView:scrollView];
    [self.view addSubview:natView];

    CGSize scrollViewContentSize = self.view.frame.size;
    [scrollView setContentSize:scrollViewContentSize];

    [self registerForKeyboardNotifications];
}

- (void)viewDidUnload {
    activeField = nil;
    scrollView = nil;
    [self unregisterForKeyboardNotifications];
    [super viewDidUnload];
}

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShown:)
                                                 name:UIKeyboardWillShowNotification object:nil];

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

}

-(void)unregisterForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillShowNotification
                                                  object:nil];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];
}

- (void)keyboardWillShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGRect frame = self.view.frame;
    frame.size.height -= kbSize.height;
    CGPoint fOrigin = activeField.frame.origin;
    fOrigin.y -= scrollView.contentOffset.y;
    fOrigin.y += activeField.frame.size.height;
    if (!CGRectContainsPoint(frame, fOrigin) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y + activeField.frame.size.height - frame.size.height);
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
     [scrollView setContentOffset:CGPointZero animated:YES];
}

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

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

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

P.S:我希望这段代码能帮助某人快速达到预期效果。(Xcode 4.5)

我把所有的东西都放在一节课上。加载视图控制器时,只需调用以下代码行:

- (void)viewDidLoad {
    [super viewDidLoad];
    KeyboardInsetScrollView *injectView = [[KeyboardInsetScrollView alloc] init];
    [injectView injectToView:self.view withRootView:self.view];
}

以下是示例项目的链接:https://github.com/caohuuloc/KeyboardInsetScrollView