Interface Builder Tab 键顺序输入

发布于 2024-09-24 08:14:06 字数 174 浏览 3 评论 0原文

我注意到,在 iPad 应用程序的一个视图中,我正在键盘上构建下一个按钮,该按钮会从左到右遍历屏幕上的所有 UITextField。

是否有可能以某种方式使其从上到下,然后向右,从上到下?

所以说我必须有两列长的文本字段,我想从上到下而不是从左到右,有意义吗?

任何帮助表示赞赏,谢谢。

I have noticed, in one of my views in an iPad app I am building the next button on the keyboard goes through all the UITextFields from left to right down the screen.

Is it possible somehow to make it go top to bottom then right, top to bottom?

So say I have to two long columns of text fields, I wan to go top to bottom not left to right, make sense?

Any help appreciated, thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

野心澎湃 2024-10-01 08:14:06

我不认为有办法通过IB,但你可以在代码中做到这一点。您实际上并没有按 Tab 键,而是使用了返回键。

将其放入 UITextField 的委托中:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
  BOOL shouldChangeText = YES;

  if ([text isEqualToString:@"\n"]) {
    // Find the next entry field
    BOOL isLastField = YES;
    for (UIView *view in [self entryFields]) {
      if (view.tag == (textView.tag + 1)) {
        [view becomeFirstResponder];
        isLastField = NO;
        break;
      }
    }
    if (isLastField) {
      [textView resignFirstResponder];
    }

    shouldChangeText = NO;
  }

  return shouldChangeText;
} 

在这里找到: http://iphoneincubator.com/blog/tag/uitextfield< /a>

I don't think there is a way through IB, but you can do this way in code. You're not actually tabbing, you'd be using the return key.

Put this in your UITextField's delegate:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
  BOOL shouldChangeText = YES;

  if ([text isEqualToString:@"\n"]) {
    // Find the next entry field
    BOOL isLastField = YES;
    for (UIView *view in [self entryFields]) {
      if (view.tag == (textView.tag + 1)) {
        [view becomeFirstResponder];
        isLastField = NO;
        break;
      }
    }
    if (isLastField) {
      [textView resignFirstResponder];
    }

    shouldChangeText = NO;
  }

  return shouldChangeText;
} 

Found here: http://iphoneincubator.com/blog/tag/uitextfield

旧人九事 2024-10-01 08:14:06

您需要实现 UITextFieldDelegate 的 - (BOOL)textFieldShouldReturn:(UITextField *)textField 方法。如何使用此方法控制顺序的示例位于

You'll want to implement UITextFieldDelegate's - (BOOL)textFieldShouldReturn:(UITextField *)textField method. An example of how to use this method to control the order is in this question.

地狱即天堂 2024-10-01 08:14:06

我想详细说明 @sprocket 的回答解决同一问题。仅仅因为某些东西开箱即用并不意味着您应该停止思考更好的方法 - 甚至正确的方法 - 做某事。正如他注意到的那样,这种行为没有记录,但大多数时候符合我们的需求。

但这对我来说还不够。想想 RTL 语言,选项卡仍然会从左到右选项卡,更不用说模拟器和设备之间的行为完全不同(设备不会将第一个输入集中在选项卡上)。最重要的是,Apple 未记录的实现似乎只考虑当前安装在视图层次结构中的视图。

想象一下表格视图(没有双关语)形式的表单。每个单元格包含一个控件,因此并非所有表单元素同时可见。一旦您到达最底部(屏幕上!)控件,Apple 就会循环返回,而不是进一步向下滚动。这种行为绝对不是我们想要的。

这就是我的想法。您的表单应该由视图控制器管理,并且视图控制器是响应者链的一部分。因此,您可以完全自由地实现以下方法:

#pragma mark - Key Commands

- (NSArray *)keyCommands
{
    static NSArray *commands;

    static dispatch_once_t once;
    dispatch_once(&once, ^{
        UIKeyCommand *const forward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:0 action:@selector(tabForward:)];
        UIKeyCommand *const backward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:UIKeyModifierShift action:@selector(tabBackward:)];

        commands = @[forward, backward];
    });

    return commands;
}

- (void)tabForward:(UIKeyCommand *)command
{
    NSArray *const controls = self.controls;
    UIResponder *firstResponder = nil;

    for (UIResponder *const responder in controls) {
        if (firstResponder != nil && responder.canBecomeFirstResponder) {
            [responder becomeFirstResponder]; return;
        }
        else if (responder.isFirstResponder) {
            firstResponder = responder;
        }
    }

    [controls.firstObject becomeFirstResponder];
}

- (void)tabBackward:(UIKeyCommand *)command
{
    NSArray *const controls = self.controls;
    UIResponder *firstResponder = nil;

    for (UIResponder *const responder in controls.reverseObjectEnumerator) {
        if (firstResponder != nil && responder.canBecomeFirstResponder) {
            [responder becomeFirstResponder]; return;
        }
        else if (responder.isFirstResponder) {
            firstResponder = responder;
        }
    }

    [controls.lastObject becomeFirstResponder];
}

可能适用用于滚动预先可见的屏幕外响应程序的附加逻辑。

这种方法的另一个优点是,您不需要子类化您可能想要显示的所有类型的控件(例如 UITextFields),而是可以在控制器级别管理逻辑,老实说,是这样做的正确的地方

I would like to elaborate on @sprocket's answer addressing the same issue. Just because something works out of the box doesn't mean you should stop thinking about a better way -- or even the right way -- of doing something. As he noticed the behavior is undocumented but fits our needs most of the time.

This wasn't enough for me though. Think of a RTL language and tabs would still tab left-to-right, not to mention the behavior is entirely different from simulator to device (device doesn't focus the first input upon tab). Most importantly though, Apple's undocumented implementation seems to only consider views currently installed in the view hierarchy.

Think of a form in form of (no pun intended) a table view. Each cell holds a single control, hence not all form elements may be visible at the same time. Apple would just cycle back up once you reached the bottommost (on screen!) control, instead of scrolling further down. This behavior is most definitely not what we desire.

So here's what I've come up with. Your form should be managed by a view controller, and view controllers are part of the responder chain. So you're perfectly free to implement the following methods:

#pragma mark - Key Commands

- (NSArray *)keyCommands
{
    static NSArray *commands;

    static dispatch_once_t once;
    dispatch_once(&once, ^{
        UIKeyCommand *const forward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:0 action:@selector(tabForward:)];
        UIKeyCommand *const backward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:UIKeyModifierShift action:@selector(tabBackward:)];

        commands = @[forward, backward];
    });

    return commands;
}

- (void)tabForward:(UIKeyCommand *)command
{
    NSArray *const controls = self.controls;
    UIResponder *firstResponder = nil;

    for (UIResponder *const responder in controls) {
        if (firstResponder != nil && responder.canBecomeFirstResponder) {
            [responder becomeFirstResponder]; return;
        }
        else if (responder.isFirstResponder) {
            firstResponder = responder;
        }
    }

    [controls.firstObject becomeFirstResponder];
}

- (void)tabBackward:(UIKeyCommand *)command
{
    NSArray *const controls = self.controls;
    UIResponder *firstResponder = nil;

    for (UIResponder *const responder in controls.reverseObjectEnumerator) {
        if (firstResponder != nil && responder.canBecomeFirstResponder) {
            [responder becomeFirstResponder]; return;
        }
        else if (responder.isFirstResponder) {
            firstResponder = responder;
        }
    }

    [controls.lastObject becomeFirstResponder];
}

Additional logic for scrolling offscreen responders visible beforehand may apply.

Another advantage of this approach is that you don't need to subclass all kinds of controls you may want to display (like UITextFields) but can instead manage the logic at controller level, where, let's be honest, is the right place to do so.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文