编辑第一个 UITextField 时,如何将 UITableView 滚动到第二个 UITextField?

Posted

技术标签:

【中文标题】编辑第一个 UITextField 时,如何将 UITableView 滚动到第二个 UITextField?【英文标题】:How may I scroll a UITableView to the second UITextField when the first UITextField is being edited? 【发布时间】:2013-08-02 18:08:05 【问题描述】:

假设我们有一个应用程序的登录屏幕。登录屏幕实现了一个UITableViewController,其中包含一个UITableViewUITableView 有 1 个部分,该部分包含两个单元格(参见下面的故事板)。

当前行为

当用户开始编辑电子邮件字段时 - 使用占位符 ENTER YOUR EMAIL - 键盘与密码字段重叠 - 使用占位符 ENTER YOUR PASSWORD。

期望的行为:

当用户开始编辑电子邮件字段时,键盘应该与两个字段重叠,并且键盘应该位于两个字段下方

尝试的解决方案

我试图在我的LoginFormController : UITableViewController 中使用以下内容来强制UITableView 滚动到适当的位置,但无济于事:

-(BOOL) textFieldSHouldBeginEditing:(RCTextField *)textField

    [[self.view viewWithTag:textField.tag+1] becomeFirstResponder];

    // get the scroll index path of the last row in the first section
    NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:1 inSection:0];

    // scroll the view there
    [[self tableView] scrollToRowAtIndexPath:scrollIndexPath
                            atScrollPosition:UITableViewScrollPositionBottom animated:YES];

    return YES;

我的LoginFormController : UITableViewController界面:

//
//  LoginFormController.h
//  Zealoushacker
//
//  Created by Alex Notov on 7/31/13.
//  Copyright (c) 2013 Zealoushacker, Inc. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface LoginFormController : UITableViewController <UITextFieldDelegate>

@end

LoginFormController 当然引用了tableView

【问题讨论】:

以下解决方案中的任何一种方法都不能解决其余内容滚动与故障到位的问题。该线程中的解决方案似乎比以下答案中的任何解决方案都更优雅,但也不能按预期工作:***.com/questions/16547549/… 【参考方案1】:

您可以尝试将TPKeyboardAvoiding 添加到您的项目中

TPKeyboardAvoiding - 在 ios 中将文本字段移出键盘的嵌入式通用解决方案。

要与UITableViewController classes 一起使用,请将TPKeyboardAvoidingTableView.mTPKeyboardAvoidingTableView.h 拖放到您的项目中,并将您的 UITableView 设置为 xib 中的 TPKeyboardAvoidingTableView。

查看Sample

【讨论】:

嗯,所以我的代码中没有UIScrollView...我使用UITableView,正是因为它应该为我处理所有滚动:(跨度> 虽然您的解决方案可能有效,但它并不能真正回答我的问题,因为我真的想完全了解如何获得我必须工作的东西,而不是寻找替代解决方案。跨度> TPKeyboardAvoiding 也有一个 UITableView 解决方案...更新我的答案 谢谢,我会试试这个替代解决方案。与此同时,我想看看我是否能得到我提出的确切问题的答案。 我尝试在我的用例中使用它是独一无二的,因为我有 3 个非常大的静态表格视图单元格。 TableView 没有正确滚动到它们,TPKeyboardAvoiding 也没有,所以看起来我要构建自己的解决方案。【参考方案2】:

scrollToRowAtIndexPath 不起作用的原因是键盘此时没有占用任何空间,因此当您告诉表格视图使这些单元格可见时,它们已经是。

您要做的是调用setContentOffset 并传入文本字段的原点减去偏移量(将字段向下移动一点),如下所示(尽管您可能希望使用setContentOffset:animated: 对其进行动画处理):

-(BOOL) textFieldSHouldBeginEditing:(RCTextField *)textField

    CGRect frame = [textField frame];
    [[self tableView] setContentOffset:CGPointMake(frame.origin.x, frame.origin.y - 5.0f)];
    return MAYBE;

【讨论】:

是的,Apple 的 Moving Content That Is Under the Keyboard 示例代码使用内容偏移和滚动视图。 我看到您已将其更新为 - 5.0f,而不是 + 5.0f... 出于某种原因,它们都不适合我。 :( 休息一下再试一次。 是的,我最初输入了 +5,但这会将文本字段向上推而不是向下推。这只是为了使该字段不位于屏幕边缘,没有它它仍应重新定位。 其他一些问题表明 setContentOffset 仅适用于表视图,如果 animate 是 YES - 我已经使用滚动视图完成此操作,并假设它与表视图相同,因为它们是子类,但是我猜不会。动画版本应该仍然适合您,因为我假设您希望滚动动画。 这似乎不起作用...而且我不认为MAYBE 被定义为常量。【参考方案3】:

这很难看,因为我没有花时间像@Turch 那样精炼……我只是粗略地使用了100 这个数字,但可以随意对其进行精炼……总的来说它有效。

-(BOOL) textFieldShouldBeginEditing:(RCTextField *)textField

    // ***HACK*** here part 1
    if (textField == self.email) 
        CGRect frame = self.tableView.frame;
        float moveUpTo = self.tableView.frame.origin.y - 100.0f;
        if (self.tableView.frame.origin.y == 0.0f) 
            frame.origin.y = moveUpTo;
            self.tableView.frame = frame;
        
    
    return YES;


-(BOOL) textFieldShouldReturn:(UITextField *)textField 
    ...
        [textField resignFirstResponder];

        // ***HACK*** here part 2
        CGRect frame = self.tableView.frame;
        float moveDownTo = self.tableView.frame.origin.y + 100.0f;
        if (self.tableView.frame.origin.y != 0.0f) 
            frame.origin.y = moveDownTo;
            self.tableView.frame = frame;
        

        return YES;
    

【讨论】:

你可以用self.email.frame.size.height * 2代替100 :)【参考方案4】:

在考虑了所有答案之后,我根据下面的答案提出了自己的答案,我觉得很干净。

我已经实现了一个类别LoginFormController+Scrolling.h

//
//  LoginFormController+Scrolling.h
//  Zealoushacker
//
//  Created by Alex Notov on 8/2/13.
//  Copyright (c) 2013 Zealoushacker, Inc. All rights reserved.
//

#import "LoginFormController.h"

typedef enum 
    UITableViewBottom = 0,
    UITableViewTop = 1
 UITableViewPosition ;

@interface LoginFormController (Scrolling)
-(void)moveLoginFormToTableView:(UITableViewPosition)p;
@end

及其实现LoginFormController+Scrolling.m:

//
//  LoginFormController+Scrolling.m
//  Zealoushacker
//
//  Created by Alex Notov on 8/2/13.
//  Copyright (c) 2013 Zealoushacker, Inc. All rights reserved.
//

#import "LoginFormController+Scrolling.h"

@implementation LoginFormController (Scrolling)
- (float)heightOfAllCells 
    float height = 0;
    for (UIView *subview in self.tableView.subviews)
    
        if ([subview isKindOfClass:[UITableViewCell self]])
        
            height += subview.frame.size.height;
        
    
    return height;


-(void)moveLoginFormToTableView:(UITableViewPosition)p

    // this is adapted from:
    // http://***.com/questions/18023457/how-may-i-scroll-a-uitableview-to-the-second-uitextfield-when-the-first-uitextfi/18023825
    CGRect frame = self.tableView.frame;

    if (p == UITableViewBottom && self.tableView.frame.origin.y == 0.0f) 
        frame.origin.y -= [self heightOfAllCells];
     else if (p == UITableViewTop && self.tableView.frame.origin.y != 0.0f) 
        frame.origin.y += [self heightOfAllCells];

    
    self.tableView.frame = frame;

@end

然后,在我的LoginFormController.m 中,我可以简单地调用[self moveLoginFormToTableView:UITableViewBottom]; 滚动到UITableView 的底部,而不管它有多少UITableViewCell 组件,然后反过来调用[self moveLoginFormToTableView:UITableViewTop]; 来滚动它回到原来的位置。

【讨论】:

以上是关于编辑第一个 UITextField 时,如何将 UITableView 滚动到第二个 UITextField?的主要内容,如果未能解决你的问题,请参考以下文章

UITextField获取当前编辑的单词

UITextField 在编辑时剪切文本

编辑时如何更改 UITextField

在uitextfield中编辑文本时如何调用函数

当表格进入“编辑”模式时,如何使表格单元格 UITextField 可编辑?

编辑时如何更改 UITextField