วิธีการนำทางผ่านฟิลด์ข้อความ (ปุ่มถัดไป / เสร็จสิ้น)


487

ฉันจะนำทางไปยังทุกฟิลด์ข้อความด้วยปุ่ม "ถัดไป" บนคีย์บอร์ด iPhone ได้อย่างไร

ช่องข้อความสุดท้ายควรปิดคีย์บอร์ด

ฉันได้ติดตั้งปุ่ม IB แล้ว (ถัดไป / เสร็จสิ้น) แต่ตอนนี้ฉันติดขัดแล้ว

ฉันใช้ textFieldShouldReturn แล้ว แต่ตอนนี้ปุ่ม Next และ Done เสร็จแล้วปิดคีย์บอร์ด


โปรดดูคำตอบของฉันด้านล่าง จากประสบการณ์ของฉันมันเป็นวิธีแก้ปัญหาที่ดีกว่าสมบูรณ์กว่ามากกว่าคำตอบปกติ ฉันไม่รู้เลยว่าทำไมไม่มีใครให้คะแนนลบ
memmons

ฉันมีปัญหาที่คล้ายกัน แต่ด้วย Cordova, Phonegap มีวิธีใดบ้างที่จะแก้ไขได้?

คำตอบ:


578

ใน Cocoa สำหรับ Mac OS X คุณจะมีเครือข่ายการตอบกลับถัดไปซึ่งคุณสามารถถามช่องข้อความที่ตัวควบคุมควรมีโฟกัสต่อไป นี่คือสิ่งที่ทำให้การแท็บระหว่างฟิลด์ข้อความทำงาน แต่เนื่องจากอุปกรณ์ iOS ไม่มีแป้นพิมพ์เพียงสัมผัสแนวคิดนี้จึงไม่สามารถเปลี่ยนมาใช้ Cocoa Touch ได้

คุณสามารถทำได้อย่างง่ายดายด้วยข้อสันนิษฐานสองข้อ:

  1. "tabbable" UITextFieldทั้งหมดอยู่ในมุมมองพาเรนต์เดียวกัน
  2. คำสั่ง "tab-order" ถูกกำหนดโดยคุณสมบัติแท็ก

สมมติว่าคุณสามารถแทนที่ textFieldShouldReturn: เช่นนี้

-(BOOL)textFieldShouldReturn:(UITextField*)textField
{
  NSInteger nextTag = textField.tag + 1;
  // Try to find next responder
  UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
  if (nextResponder) {
    // Found next responder, so set it.
    [nextResponder becomeFirstResponder];
  } else {
    // Not found, so remove keyboard.
    [textField resignFirstResponder];
  }
  return NO; // We do not want UITextField to insert line-breaks.
}

เพิ่มรหัสเพิ่มเติมและสามารถละเว้นสมมติฐานได้เช่นกัน

Swift 4.0

 func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    let nextTag = textField.tag + 1
    // Try to find next responder
    let nextResponder = textField.superview?.viewWithTag(nextTag) as UIResponder!

    if nextResponder != nil {
        // Found next responder, so set it
        nextResponder?.becomeFirstResponder()
    } else {
        // Not found, so remove keyboard
        textField.resignFirstResponder()
    }

    return false
}

หากผู้ดูแลของฟิลด์ข้อความจะเป็น UITableViewCell การตอบกลับครั้งต่อไปจะเป็น

let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!

6
บางครั้งมีปุ่ม "ถัดไป" และ "ก่อนหน้า" ที่ด้านบนของแป้นพิมพ์ อย่างน้อยในเบราว์เซอร์
ทิมBüthe

31
เพื่อจะอวดผมอยากจะล้างข้อมูลที่ผิดในโพสต์นี้ บน OS X ลำดับแท็บตั้งค่าผ่านวิธี setNextKeyView ของ NSView: (ไม่ใช่ setNextResponder :) สายการตอบกลับแยกออกจากสิ่งนี้: มันเป็นลำดับชั้นของวัตถุตอบกลับที่จัดการการกระทำที่ "ไม่ได้กำหนดเป้าหมาย" เช่นการกระทำที่ส่งไปยังผู้ตอบกลับคนแรกแทนที่จะไปยังวัตถุตัวควบคุมโดยตรง เชนผู้ตอบกลับมักตามลำดับชั้นการดูจนถึงหน้าต่างและตัวควบคุมแล้วตัวแทนแอป Google "responder chain" สำหรับข้อมูลมากมาย
davehayden

SuperView UITableViewCellของช่องข้อความจะเป็น คุณจะต้องเข้าถึงที่เกี่ยวข้องUITableViewและรับเซลล์ที่มีช่องข้อความที่คุณต้องการ
Michael Mior

13
อย่าลืมเพิ่มUITextFieldDelegateและตั้งค่าผู้รับมอบสิทธิ์ฟิลด์ข้อความ
Sal

1
การเตือนที่เป็นมิตรเพื่อตั้งค่าตัวเลือก TAG จากกระดานเรื่องราว (ในกรณีของฉัน) คุณต้องตั้งค่าแท็ก TextFields ด้วยตนเองจากน้อยไปหามาก (แรกคือ 0, ที่สองคือ 1 ฯลฯ ) สำหรับวิธีแก้ปัญหานี้ในการทำงาน
Joakim

170

มีความเป็นมากทางออกที่สวยงามมากขึ้นซึ่ง blew ฉันไปครั้งแรกที่ผมเห็นมัน ประโยชน์ที่ได้รับ:

  • การนำ OSX ไปใช้กับ Textfield Text ซึ่ง Textfield รู้ว่าโฟกัสควรไปที่ใด
  • ไม่พึ่งพาการตั้งค่าหรือใช้แท็ก - ซึ่งก็คือ IMO ที่บอบบางสำหรับกรณีการใช้งานนี้
  • สามารถขยายให้ทำงานร่วมกับทั้งUITextFieldและUITextViewควบคุม - หรือการควบคุม UI รายการแป้นพิมพ์
  • ไม่เกะกะตัวควบคุมมุมมองของคุณด้วยรหัสตัวแทน UITextField สำเร็จรูป
  • ผสานรวมกับ IB ได้อย่างดีและสามารถกำหนดค่าผ่านทางตัวเลือกแบบลากแล้ววางเพื่อเชื่อมต่อกับเต้าเสียบ

สร้างคลาสย่อย UITextField ซึ่งมีIBOutletคุณสมบัติชื่อ nextField นี่คือส่วนหัว:

@interface SOTextField : UITextField

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

@end

และนี่คือการดำเนินการ:

@implementation SOTextField

@end

ในตัวควบคุมมุมมองของคุณคุณจะสร้าง-textFieldShouldReturn:วิธีมอบสิทธิ์:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if ([textField isKindOfClass:[SOTextField class]]) {
        UITextField *nextField = [(SOTextField *)textField nextField];

        if (nextField) {
            dispatch_async(dispatch_get_current_queue(), ^{
                [nextField becomeFirstResponder];
            });
        }
        else {
            [textField resignFirstResponder];
        }
    }

    return YES;
}

ใน IB เปลี่ยน UITextFields ของคุณเพื่อใช้SOTextFieldคลาส ถัดไปใน IB ให้ตั้งค่าผู้รับมอบสิทธิ์สำหรับ 'SOTextFields'to' เจ้าของไฟล์ 'แต่ละอัน (ซึ่งอยู่ตรงที่คุณใส่รหัสสำหรับวิธีการมอบสิทธิ์ - textFieldShouldReturn) ความสวยงามของการออกแบบนี้คือตอนนี้คุณสามารถคลิกขวาที่ textField ใด ๆ และกำหนดเต้าเสียบต่อไปให้กับSOTextFieldวัตถุถัดไปที่คุณต้องการเป็นผู้ตอบกลับคนต่อไป

การกำหนดฟิลด์ถัดไปใน IB

ยิ่งไปกว่านั้นคุณสามารถทำสิ่งที่ยอดเยี่ยมเช่นวนรอบ textFields เพื่อให้หลังจากที่สุดท้ายสูญเสียโฟกัสคนแรกจะได้รับโฟกัสอีกครั้ง

นี้สามารถขยายไปยังกำหนดโดยอัตโนมัติreturnKeyTypeของSOTextFieldไปUIReturnKeyNextถ้ามีการมอบหมาย nextField - หนึ่งน้อยสิ่งที่กำหนดด้วยตนเอง


3
ฉันชอบการบูรณาการ IB มากกว่าการใช้แท็กโดยเฉพาะอย่างยิ่งกับ Xcode เวอร์ชันใหม่ซึ่งรวม IB ไว้กับ IDE ที่เหลืออยู่ของเขา - และไม่ต้องวุ่นวายกับคอนโทรลเลอร์ของฉันอีกต่อไป
memmons

4
แท็กง่ายขึ้น แต่วิธีนี้ดีกว่าและเหมาะสมกับการออกแบบ OO ที่ดีขึ้น
Brain2000

1
ผมชอบวิธีการแก้ปัญหานี้ UITableViewแต่ฉันใช้ฟิลด์ข้อความในแต่ละมุมมองมือถือที่แยกต่างหากใน แม้ว่าฉันจะมีIBOutletคุณสมบัติในตัวควบคุมมุมมองสำหรับแต่ละฟิลด์ข้อความ แต่ก็ไม่ให้ฉันเชื่อมโยงnextFieldคุณสมบัติกับคุณสมบัติเหล่านั้นในเจ้าของไฟล์ คำแนะนำใด ๆ ที่ฉันสามารถทำให้มันใช้ได้ในสถานการณ์นี้
Jay Imerman

1
@JayImerman IB จะไม่อนุญาตให้คุณเชื่อมต่อช่องระหว่างเซลล์ ดังนั้น IB จะไม่ต้องทำในสถานการณ์นี้ อย่างไรก็ตามคุณสามารถเชื่อมโยงคุณสมบัติของฟิลด์ถัดไปโดยใช้รหัส textField1.nextField = textField2; textField2.nextField = textField3;ฯลฯ
memmons

2
มีโอกาสใดที่คำตอบนี้จะได้รับการอัปเดตสำหรับ xcode และ iOS เวอร์ชันใหม่
แปลสูญหาย

82

นี่คือหนึ่งที่ไม่มีการมอบหมาย:

tf1.addTarget(tf2, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
tf2.addTarget(tf3, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)

ObjC:

[tf1 addTarget:tf2 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
[tf2 addTarget:tf3 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];

การทำงานโดยใช้ (ส่วนใหญ่ไม่ทราบ) UIControlEventEditingDidEndOnExit UITextFieldการดำเนินการ

คุณสามารถเชื่อมโยงเรื่องนี้กับกระดานเรื่องราวได้อย่างง่ายดายดังนั้นจึงไม่จำเป็นต้องมีการมอบหมายหรือรหัส

แก้ไข: จริง ๆ แล้วฉันไม่สามารถคิดออกว่าจะขอสิ่งนี้ในกระดานเรื่องราวได้อย่างไร becomeFirstResponderดูเหมือนจะไม่เป็นการกระทำที่เสนอสำหรับเหตุการณ์ควบคุมนี้ซึ่งน่าเสียดาย ยังคงคุณสามารถขอกรอบข้อความของคุณทั้งหมดขึ้นอยู่กับการกระทำเดียวใน ViewController ของคุณซึ่งจากนั้นจะกำหนด TextField จะbecomeFirstResponderขึ้นอยู่กับผู้ส่ง ( แต่แล้วมันไม่ได้เป็นสง่างามเป็นวิธีการแก้ปัญหาดังกล่าวข้างต้นการเขียนโปรแกรมเพื่อ IMO ทำมันด้วยรหัสข้างต้นviewDidLoad)


18
โซลูชันที่ง่ายและมีประสิทธิภาพมาก [tfN addTarget:self action:@selector(loginButtonTapped:) forControlEvents:UIControlEventEditingDidEndOnExit];คนสุดท้ายในห่วงโซ่ยังสามารถเรียกเช่น ขอบคุณ @mxcl
msrdjan

คุณจะทำสิ่งนี้ในกระดานเรื่องราวได้อย่างไร
Pedro Borges

นี่อาจเป็นคำตอบที่ดีที่สุดที่นี่
daspianist

สิ่งนี้ใช้ได้ผลกับฉันอย่างสมบูรณ์แม้ใน Swift 2 นี่เป็นวิธีที่ง่ายและรวดเร็วกว่าการเพิ่มผู้แทน
ตัน

2
สวิฟต์ 4: txtFirstname.addTarget (txtLastname, action: #selector (กลายเป็นเฟิร์สตอบกลับ), สำหรับ: UIControlEvents.editingDidEndOnExit)
เรียลไทม์

78

นี่คือทางออกสำหรับปัญหานี้ของฉัน

เพื่อแก้ปัญหานี้ (และเพราะฉันเกลียดการพึ่งพาแท็กในการทำสิ่งต่าง ๆ ) ฉันตัดสินใจที่จะเพิ่มคุณสมบัติที่กำหนดเองให้กับวัตถุ UITextField ในคำอื่น ๆ ฉันสร้างหมวดหมู่ใน UITextField เช่นนี้

UITextField + Extended.h

@interface UITextField (Extended)

@property(retain, nonatomic)UITextField* nextTextField;

@end

UITextField + Extended.m

#import "UITextField+Extended.h"
#import <objc/runtime.h>

static char defaultHashKey;

@implementation UITextField (Extended)

- (UITextField*) nextTextField { 
    return objc_getAssociatedObject(self, &defaultHashKey); 
}

- (void) setNextTextField:(UITextField *)nextTextField{
    objc_setAssociatedObject(self, &defaultHashKey, nextTextField, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

@end

ตอนนี้นี่คือวิธีที่ฉันใช้:

UITextField *textField1 = ...init your textfield
UITextField *textField2 = ...init your textfield
UITextField *textField3 = ...init your textfield

textField1.nextTextField = textField2;
textField2.nextTextField = textField3;
textField3.nextTextField = nil;

และใช้วิธีการ textFieldShouldReturn:

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {

    UITextField *next = theTextField.nextTextField;
    if (next) {
        [next becomeFirstResponder];
    } else {
        [theTextField resignFirstResponder];
    }

    return NO; 
}

ตอนนี้ฉันมีรายการที่เชื่อมโยงของ UITextField ซึ่งแต่ละคนรู้ว่าใครต่อไปในสาย

หวังว่ามันจะช่วย


11
นี่เป็นทางออกที่ดีที่สุดและควรเลือกเป็นคำตอบ
Giovanni

4
วิธีนี้ใช้ได้ผลกับฉันสิ่งเดียวที่ฉันเปลี่ยนคือการสร้างถัดไป TextField และ IBOutlet เพื่อให้ฉันสามารถตั้งค่าการผูกมัดจากภายในกระดานเรื่องราวของฉัน
zachzurn

ถ้าฉันสามารถบันทึกคำตอบที่ชื่นชอบนี่จะเป็นหนึ่งในนั้น ขอบคุณสำหรับการแก้ปัญหาที่สะอาด!
Matt Becker

1
โปรดทราบว่าหาก IB เป็นสิ่งที่คุณต้องการคุณสามารถตั้งค่าคุณสมบัติเหล่านี้เป็น IBOutlets ได้ . ระวังการชนชื่อ - ในที่สุด Apple อาจเพิ่มสิ่งนี้ใน UIResponder
Jasper Blues

โซลูชันนี้ใช้งานร่วมกับเครื่องมือสร้างส่วนต่อประสานได้หรือไม่ ฉันหมายถึงสามารถใช้ IBOutlets และการอ้างอิงกระดานเรื่องราวแทนการตั้งค่าฟิลด์ข้อความถัดไปโดยทางโปรแกรมได้หรือไม่ IB ดูเหมือนจะไม่อนุญาตให้คุณตั้งค่าคลาส UITextField เป็นหมวดหมู่
Pedro Borges

46

ส่วนขยายที่รวดเร็วที่ใช้คำตอบของ mxcl เพื่อทำให้เป็นเรื่องง่ายโดยเฉพาะอย่างยิ่ง (ปรับให้เข้ากับ swift 2.3 โดย Traveler):

extension UITextField {
    class func connectFields(fields:[UITextField]) -> Void {
        guard let last = fields.last else {
            return
        }
        for i in 0 ..< fields.count - 1 {
            fields[i].returnKeyType = .Next
            fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
        }
        last.returnKeyType = .Done
        last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), forControlEvents: .EditingDidEndOnExit)
    }
}

ใช้งานง่าย:

UITextField.connectFields([field1, field2, field3])

ส่วนขยายจะตั้งค่าปุ่มย้อนกลับเป็น "ถัดไป" สำหรับทุกคนยกเว้นฟิลด์สุดท้ายและไปที่ "เสร็จสิ้น" สำหรับฟิลด์สุดท้ายและเลื่อนโฟกัส / ยกเลิกคีย์บอร์ดเมื่อแตะ

สวิฟท์ <2.3

extension UITextField {
    class func connectFields(fields:[UITextField]) -> Void {
        guard let last = fields.last else {
            return
        }
        for var i = 0; i < fields.count - 1; i += 1 {
            fields[i].returnKeyType = .Next
            fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
        }
        last.returnKeyType = .Done
        last.addTarget(last, action: "resignFirstResponder", forControlEvents: .EditingDidEndOnExit)
    }
}

SWIFT 3: ใช้แบบนี้ -

UITextField.connectFields(fields: [field1, field2])

Extension:
    extension UITextField {
        class func connectFields(fields:[UITextField]) -> Void {
            guard let last = fields.last else {
                return
            }
            for i in 0 ..< fields.count - 1 {
                fields[i].returnKeyType = .next
                fields[i].addTarget(fields[i+1], action: #selector(UIResponder.becomeFirstResponder), for: .editingDidEndOnExit)
            }
            last.returnKeyType = .go
            last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), for: .editingDidEndOnExit)
        }
    }

5
BTW ถ้าคุณต้องการที่จะเสร็จสิ้นแล้วได้ดำเนินการคุณสามารถเพียงแค่มีคุณดูตัวควบคุมเป็นไปตามและดำเนินการUITextFieldDelegate เพียงแค่กลับออกมาจากต้นถ้าfunc textFieldDidEndEditing(textField: UITextField) textField != field3
Ryan

25

วิธีที่สอดคล้องกันมากขึ้นและมีประสิทธิภาพคือการใช้NextResponderTextFieldview.tagคุณสามารถกำหนดค่ามันทั้งหมดจากผู้สร้างอินเตอร์เฟซที่มีความจำเป็นในการตั้งค่าผู้ร่วมประชุมหรือการใช้

สิ่งที่คุณต้องทำคือ

  1. ตั้งค่าประเภทคลาสของคุณUITextFieldเป็นNextResponderTextField ป้อนคำอธิบายรูปภาพที่นี่
  2. จากนั้นตั้งค่าเต้าเสียบของnextResponderFieldให้ชี้ไปที่การตอบกลับครั้งต่อไปว่าสามารถเป็นอะไรก็ได้UITextFieldหรือUIResponderคลาสย่อยใด ๆ มันอาจเป็น UIButton และไลบรารีนั้นฉลาดพอที่จะทริกเกอร์TouchUpInsideเหตุการณ์ของปุ่มเฉพาะเมื่อเปิดใช้งาน ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

นี่คือห้องสมุดที่ใช้งานจริง:

ป้อนคำอธิบายรูปภาพที่นี่


ใช่. ใช้งานได้ดีกับ Swift 3.1 ซึ่งเป็นโซลูชันที่สง่างามมากเพียงใดที่ IB ควรทำงานนอกกรอบ
Richard

ขออภัยฉันไม่ได้รับคำถาม
mohamede1945

1
ถัดไปข้อความตอบกลับฟิลด์ใช้งานได้สำหรับฉัน มันรวดเร็วและใช้งานง่ายเพียงไฟล์เดียวที่รวดเร็วและทำสิ่งที่ฉันต้องการโดยไม่ต้องยุ่งยาก
Pat McG

มันใช้งานได้ดี! หมายเหตุ: ฉันต้องเปลี่ยนคีย์ส่งคืนด้วยตนเองเพื่อให้แสดงเป็น "ถัดไป" และ "เสร็จสิ้น" ในตัวอย่าง
Mike Miller

14

ฉันชอบโซลูชัน OO ที่ได้รับการแนะนำโดย Anth0 และ Answerbot อย่างไรก็ตามฉันกำลังทำงานกับ POC ที่รวดเร็วและเล็กดังนั้นฉันจึงไม่ต้องการที่จะยุ่งเหยิงกับคลาสย่อยและหมวดหมู่

อีกวิธีง่ายๆคือการสร้าง NSArray ของเขตข้อมูลและค้นหาเขตข้อมูลถัดไปเมื่อคุณกดถัดไป ไม่ใช่โซลูชัน OO แต่ใช้ง่ายรวดเร็วและใช้งานง่าย นอกจากนี้คุณสามารถดูและแก้ไขการสั่งซื้อได้อย่างรวดเร็ว

นี่คือรหัสของฉัน (สร้างขึ้นตามคำตอบอื่น ๆ ในกระทู้นี้):

@property (nonatomic) NSArray *fieldArray;

- (void)viewDidLoad {
    [super viewDidLoad];

    fieldArray = [NSArray arrayWithObjects: firstField, secondField, thirdField, nil];
}

- (BOOL) textFieldShouldReturn:(UITextField *) textField {
    BOOL didResign = [textField resignFirstResponder];
    if (!didResign) return NO;

    NSUInteger index = [self.fieldArray indexOfObject:textField];
    if (index == NSNotFound || index + 1 == fieldArray.count) return NO;

    id nextField = [fieldArray objectAtIndex:index + 1];
    activeField = nextField;
    [nextField becomeFirstResponder];

    return NO;
}
  • ฉันกลับไม่เสมอเพราะฉันไม่ต้องการแทรกตัวแบ่งบรรทัด แค่คิดว่าฉันจะชี้ให้เห็นตั้งแต่เมื่อฉันกลับ YES มันจะออกจากฟิลด์ที่ตามมาโดยอัตโนมัติหรือแทรกตัวแบ่งบรรทัดใน TextView ของฉัน ฉันใช้เวลาสักครู่เพื่อคิดออก
  • activeField ติดตามเขตข้อมูลที่ใช้งานอยู่ในกรณีที่จำเป็นต้องเลื่อนดูข้อมูลจากแป้นพิมพ์ หากคุณมีรหัสที่คล้ายกันตรวจสอบให้แน่ใจว่าคุณกำหนด activeField ก่อนเปลี่ยนการตอบกลับครั้งแรก การเปลี่ยนผู้ตอบคำถามแรกทันทีและจะดำเนินการเหตุการณ์ KeyboardWasShown ทันที

ดี! ง่ายและรหัสทั้งหมดในรุ่นเดียว AnthO นั้นดีมากเช่นกัน
เชมัส

โปรดทราบว่าคุณกำลังเสี่ยงต่อการวนรอบด้วยรหัสนี้ FieldArray ของคุณกำลังแปลงการอ้างอิงที่อ่อนแอที่ใช้ใน IBOutlet ทั้งหมดของคุณเป็นการอ้างอิงที่คาดเดายากในอาเรย์เอง
Michael Long

11

นี่คือการใช้งานแท็บโดยใช้หมวดหมู่บน UIControl วิธีนี้มีข้อดีทั้งหมดของวิธีการจาก Michael และ Anth0 แต่ใช้ได้กับ UIControls ทั้งหมดไม่ใช่แค่UITextFields มันยังทำงานร่วมกับตัวสร้างส่วนต่อประสานและกระดานเรื่องราวได้อย่างราบรื่น

แอปที่มาและตัวอย่าง: ที่เก็บ GitHub สำหรับ UIControlsWithTabbing

การใช้งาน:

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField transferFirstResponderToNextControl];
    return NO;
}

การกำหนด nextControl ในเครื่องมือสร้างอินเตอร์เฟส

หัวข้อ:

//
// UIControl+NextControl.h
// UIControlsWithTabbing
//

#import <UIKit/UIKit.h>

@interface UIControl (NextControl)

@property (nonatomic, weak) IBOutlet UIControl *nextControl;

- (BOOL)transferFirstResponderToNextControl;

@end

การดำเนินงาน:

#import "UIControl+NextControl.h"
#import <objc/runtime.h>

static char defaultHashKey;

@implementation UIControl (NextControl)

- (UIControl *)nextControl
{
    return objc_getAssociatedObject(self, &defaultHashKey);
}

- (void)setNextControl:(UIControl *)nextControl
{
    objc_setAssociatedObject(self, &defaultHashKey, nextControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)transferFirstResponderToNextControl
{
    if (self.nextControl)
    {
        [self.nextControl becomeFirstResponder];

        return YES;
    }

    [self resignFirstResponder];

    return NO;
}

@end

1
บางครั้งวิดเจ็ตถัดไปไม่ใช่ตัวควบคุมเช่น UITextView และคุณอาจต้องการแท็บด้วย พิจารณาเปลี่ยนประเภทจาก UITextField เป็น UIResponder
Pedro Borges

1
ใช้งานได้ดีและมีเอกสารที่ยอดเยี่ยม ฉันหวังว่าฉันจะเลื่อนลงไปที่คำถามนี้เมื่อหลายชั่วโมงก่อน :)
Javier Cadiz

10

ฉันได้ลองใช้รหัสจำนวนมากและในที่สุดก็ใช้งานได้กับฉันในSwift 3.0 ล่าสุด [มีนาคม 2017]

ViewControllerชั้นควรจะสืบทอดUITextFieldDelegateการทำทำงานรหัสนี้

class ViewController: UIViewController,UITextFieldDelegate  

เพิ่มฟิลด์ข้อความที่มีหมายเลขแท็กที่เหมาะสมและหมายเลขแท็กนี้จะใช้ในการควบคุมไปยังฟิลด์ข้อความที่เหมาะสมตามจำนวนแท็กส่วนเพิ่มที่กำหนดให้กับมัน

override func viewDidLoad() {
    userNameTextField.delegate = self
    userNameTextField.tag = 0
    userNameTextField.returnKeyType = UIReturnKeyType.next
    passwordTextField.delegate = self
    passwordTextField.tag = 1
    passwordTextField.returnKeyType = UIReturnKeyType.go
}

ในโค้ดด้านบนreturnKeyType = UIReturnKeyType.nextตำแหน่งที่จะทำให้ปุ่มส่งคืนคีย์แพดเพื่อแสดงในขณะที่Nextคุณมีตัวเลือกอื่นเช่นJoin/Goฯลฯ โดยขึ้นอยู่กับแอปพลิเคชันของคุณเปลี่ยนค่า

นี่ textFieldShouldReturnเป็นวิธีการควบคุม UITextFieldDelegate และที่นี่เรามีการเลือกฟิลด์ต่อไปโดยยึดตามการเพิ่มค่าแท็ก

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
        nextField.becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
        return true;
    }
    return false
 }

UITextViewงานนี้ยกเว้นถ้าช่องใส่คือ มีความคิดวิธีการทำเช่นนี้ในการรวมกัน?
T9b

@ T9b สิ่งที่คุณต้องการอย่างแน่นอน? คุณใช้การควบคุมประเภทใดในแอปของคุณ
BHUVANESH MOHANKUMAR

การป้อนข้อความมีสองประเภทส่วนแรกคือUITextField(ป้อนข้อความบรรทัดเดียว) ส่วนที่สองคือUITextView(ป้อนข้อความหลายบรรทัด) UITextViewเห็นได้ชัดว่าไม่ตอบสนองต่อรหัสนี้ แต่สามารถนำมาใช้ในรูปแบบ
T9b

ใช่ส่วนของรหัสนี้สำหรับ UITextField เท่านั้นและคุณได้ลองแก้ไขเหตุการณ์สำหรับ UITextView หรือไม่
BHUVANESH MOHANKUMAR

9

หลังจากที่คุณออกจากฟิลด์ข้อความหนึ่งคุณเรียก [otherTextField กลายเป็น FirstFirstResponder] และฟิลด์ถัดไปจะได้รับโฟกัส

นี่อาจเป็นปัญหาที่ยุ่งยากในการจัดการเนื่องจากบ่อยครั้งที่คุณต้องการเลื่อนหน้าจอหรือปรับตำแหน่งของช่องข้อความเพื่อให้มองเห็นได้ง่ายเมื่อแก้ไข เพียงตรวจสอบให้แน่ใจว่าได้ทำการทดสอบจำนวนมากโดยการเข้าและออกจากช่องข้อความด้วยวิธีที่แตกต่างกันและออกไปก่อน (ให้ผู้ใช้มีตัวเลือกเพื่อยกเลิกคีย์บอร์ดแทนการไปที่ฟิลด์ถัดไปโดยปกติด้วย "Done" แถบนำทาง)


9
 -(BOOL)textFieldShouldReturn:(UITextField *)textField
{
   [[self.view viewWithTag:textField.tag+1] becomeFirstResponder];
   return YES;
}

คุณไม่ควรใช้แท็กเพื่อจุดประสงค์นี้
Christian Schnorr

7

วิธีที่ง่ายมากสำหรับการยกเลิกคีย์บอร์ดเมื่อกดปุ่ม 'Done' คือ:

สร้าง IBAction ใหม่ในส่วนหัว

- (IBAction)textFieldDoneEditing:(id)sender;

ในไฟล์การนำไปใช้ (ไฟล์. m) ให้เพิ่มวิธีต่อไปนี้:

- (IBAction)textFieldDoneEditing:(id)sender 
{ 
  [sender resignFirstResponder];
}

จากนั้นเมื่อคุณมาเชื่อมโยง IBAction กับฟิลด์ข้อความ - ลิงก์ไปยังเหตุการณ์ 'Did End On Exit'


1
คุณยินดีต้อนรับมันไม่ได้นำทางผ่านเขตข้อมูลข้อความ แต่จะปิดแป้นพิมพ์และอนุญาตให้คุณเลือกเขตข้อมูลอื่น
jcrowson

7

ตั้งค่าแป้นส่งคืนแป้นพิมพ์เป็นครั้งแรกใน xib มิฉะนั้นคุณสามารถเขียนรหัสในviewdidload:

passWord.returnKeyType = UIReturnKeyNext;

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if(textField == eMail) {
        [textField resignFirstResponder];
        [userName becomeFirstResponder];
    }
    if (textField==userName) {
        [textField resignFirstResponder];
        [passWord becomeFirstResponder];
    }
    if (textField==passWord) {
        [textField resignFirstResponder];
        [country becomeFirstResponder];
    }
    if (textField==country) {
        [textField resignFirstResponder];
    }
    return YES;
}

7

ฉันรู้สึกประหลาดใจกับจำนวนคำตอบที่นี่ที่ล้มเหลวในการทำความเข้าใจแนวคิดง่ายๆอย่างหนึ่ง: การนำทางผ่านการควบคุมในแอปของคุณไม่ใช่สิ่งที่มุมมองที่ควรทำ เป็นหน้าที่ของผู้ควบคุมในการตัดสินใจว่าจะใช้ตัวควบคุมแบบใดในการตอบกลับครั้งแรกครั้งต่อไป

คำตอบส่วนใหญ่จะใช้กับการนำทางไปข้างหน้าเท่านั้น แต่ผู้ใช้อาจต้องการย้อนกลับ

ดังนั้นนี่คือสิ่งที่ฉันเกิดขึ้น แบบฟอร์มของคุณควรได้รับการจัดการโดยตัวควบคุมมุมมองและตัวควบคุมมุมมองเป็นส่วนหนึ่งของห่วงโซ่การตอบกลับ ดังนั้นคุณสามารถใช้วิธีการดังต่อไปนี้:

#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];
}

อาจใช้ตรรกะเพิ่มเติมสำหรับการเลื่อนผู้ตอบคำถามที่มองเห็นหน้าจอล่วงหน้า

ข้อดีอีกประการของวิธีการนี้คือคุณไม่จำเป็นต้อง subclass การควบคุมทุกประเภทที่คุณอาจต้องการแสดง (เช่นUITextFields) แต่สามารถจัดการตรรกะในระดับตัวควบคุมแทนซึ่งตรงไปตรงมาเป็นสถานที่ที่เหมาะสมในการทำเช่นนั้น .


ฉันพบคำตอบที่เกี่ยวข้องมากที่สุด แต่ฉันสังเกตเห็นสิ่งที่ตลกที่บางทีคุณอาจจะเคลียร์ เมื่อใช้ UITextFields ที่ไม่ได้ถูกจัดการโดย UIViewController การกดปุ่มแท็บจะทำให้ UITextField ถัดไปเป็นผู้ตอบกลับคนแรกตามค่าเริ่มต้น อย่างไรก็ตามเมื่อ VC แต่ละตัวได้รับการจัดการสิ่งนี้ไม่เป็นความจริง VC ของฉันไม่ได้ทำอะไร แต่ฟังก์ชั่นการแท็บในตัวหายไป ฉันสังเกตเห็นว่า keyCommands ของ VC จบลงด้วยการเพิ่มลงในห่วงโซ่การตอบกลับของมุมมอง สิ่งนี้ทำให้ฉันเชื่อว่าถ้าคุณกำลังใช้ VC มันเป็นสิ่งจำเป็นที่จะใช้ keyCommands
Joey Carson

4

ฉันได้เพิ่มคำตอบของ PeyloW ในกรณีที่คุณต้องการใช้ฟังก์ชันการทำงานของปุ่มก่อนหน้า / ถัดไป:

- (IBAction)moveThroughTextFields:(UIBarButtonItem *)sender 
{
    NSInteger nextTag;
    UITextView *currentTextField = [self.view findFirstResponderAndReturn];

    if (currentTextField != nil) {
        // I assigned tags to the buttons.  0 represent prev & 1 represents next
        if (sender.tag == 0) {
            nextTag = currentTextField.tag - 1;

        } else if (sender.tag == 1) {
            nextTag = currentTextField.tag + 1;
        }
    }
    // Try to find next responder
    UIResponder* nextResponder = [self.view viewWithTag:nextTag];
    if (nextResponder) {
        // Found next responder, so set it.
        // I added the resign here in case there's different keyboards in place.
        [currentTextField resignFirstResponder];
        [nextResponder becomeFirstResponder];
    } else {
        // Not found, so remove keyboard.
        [currentTextField resignFirstResponder];

    }
}

ที่คุณ subclass UIView เช่นนี้:

@implementation UIView (FindAndReturnFirstResponder)
- (UITextView *)findFirstResponderAndReturn
{
    for (UITextView *subView in self.subviews) {
        if (subView.isFirstResponder){
            return subView;
        }
    }
    return nil;
}
@end

4

สวัสดีทุกคนโปรดดูอันนี้

- (void)nextPrevious:(id)sender
{

  UIView *responder = [self.view findFirstResponder];   

  if (nil == responder || ![responder isKindOfClass:[GroupTextField class]]) {
    return;
  }

  switch([(UISegmentedControl *)sender selectedSegmentIndex]) {
    case 0:
      // previous
      if (nil != ((GroupTextField *)responder).previousControl) {
        [((GroupTextField *)responder).previousControl becomeFirstResponder];
        DebugLog(@"currentControl: %i previousControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).previousControl.tag);
      }
      break;
    case 1:
      // next
      if (nil != ((GroupTextField *)responder).nextControl) {
        [((GroupTextField *)responder).nextControl becomeFirstResponder];
        DebugLog(@"currentControl: %i nextControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).nextControl.tag);
      }     
      break;    
  }
}

แทนที่จะใช้ UIView * ให้คำตอบมันจะแม่นยำยิ่งขึ้นในการใช้ UIRespoder * Responder
Pedro Borges

4

ฉันพยายามที่จะแก้ปัญหานี้โดยใช้วิธีการที่ซับซ้อนมากขึ้นตามการกำหนดแต่ละเซลล์ (หรือUITextField) ในUITableViewค่าแท็กที่ไม่ซ้ำกันซึ่งสามารถเรียกคืนได้ในภายหลัง: activ-next-uitextfield-in-uitableview-ios

ฉันหวังว่านี่จะช่วยได้!


4

ฉันเพิ่งสร้างขึ้นใหม่ Pod เมื่อต้องรับมือกับสิ่งนี้GNTextFieldsCollectionManager มันจัดการปัญหาฟิลด์ข้อความถัดไป / สุดท้ายโดยอัตโนมัติและใช้งานง่าย

[[GNTextFieldsCollectionManager alloc] initWithView:self.view];

คว้าฟิลด์ข้อความทั้งหมดที่เรียงลำดับโดยปรากฏในลำดับชั้นการดู (หรือตามแท็ก) หรือคุณสามารถระบุอาเรย์ของฟิลด์ข้อความของคุณเอง


4

โซลูชันใน Swift 3.1, หลังจากเชื่อมต่อฟิลด์ข้อความของคุณ IBOutlets ตั้งค่าฟิลด์ข้อความของคุณในการมอบหมายดูวิวโหลดแล้วนำทางการกระทำของคุณในฟิลด์ข้อความ

class YourViewController: UIViewController,UITextFieldDelegate {

        @IBOutlet weak var passwordTextField: UITextField!
        @IBOutlet weak var phoneTextField: UITextField!

        override func viewDidLoad() {
            super.viewDidLoad()
            self.passwordTextField.delegate = self
            self.phoneTextField.delegate = self
            // Set your return type
            self.phoneTextField.returnKeyType = .next
            self.passwordTextField.returnKeyType = .done
        }

        func textFieldShouldReturn(_ textField: UITextField) -> Bool{
            if textField == self.phoneTextField {
                self.passwordTextField.becomeFirstResponder()
            }else if textField == self.passwordTextField{
                // Call login api
                self.login()
            }
            return true
        }

    }

4

ถ้ามีคนต้องการเช่นนี้ ฉันคิดว่านี่ใกล้เคียงที่สุดกับข้อกำหนดที่ถามมา

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือวิธีที่ฉันใช้งาน

เพิ่มมุมมองอุปกรณ์เสริมสำหรับแต่ละฟิลด์ข้อความที่คุณต้องการตั้งค่าโดยใช้

func setAccessoryViewFor(textField : UITextField)    {
    let toolBar = UIToolbar()
    toolBar.barStyle = .default
    toolBar.isTranslucent = true
    toolBar.sizeToFit()

    // Adds the buttons

    // Add previousButton
    let prevButton = UIBarButtonItem(title: "<", style: .plain, target: self, action: #selector(previousPressed(sender:)))
    prevButton.tag = textField.tag
    if getPreviousResponderFor(tag: textField.tag) == nil {
        prevButton.isEnabled = false
    }

    // Add nextButton
    let nextButton = UIBarButtonItem(title: ">", style: .plain, target: self, action: #selector(nextPressed(sender:)))
    nextButton.tag = textField.tag
    if getNextResponderFor(tag: textField.tag) == nil {
        nextButton.title = "Done"
    }

    let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    toolBar.setItems([prevButton,spaceButton,nextButton], animated: false)
    toolBar.isUserInteractionEnabled = true
    textField.inputAccessoryView = toolBar
}

ใช้ฟังก์ชั่นต่อไปนี้เพื่อจัดการกับก๊อกน้ำ

func nextPressed(sender : UIBarButtonItem) {
    if let nextResponder = getNextResponderFor(tag: sender.tag) {
        nextResponder.becomeFirstResponder()
    } else {
        self.view.endEditing(true)
    }

}

func previousPressed(sender : UIBarButtonItem) {
    if let previousResponder = getPreviousResponderFor(tag : sender.tag)  {
        previousResponder.becomeFirstResponder()
    }
}

func getNextResponderFor(tag : Int) -> UITextField? {
    return self.view.viewWithTag(tag + 1) as? UITextField
}

func getPreviousResponderFor(tag : Int) -> UITextField? {
    return self.view.viewWithTag(tag - 1) as? UITextField
}

คุณจะต้องให้แท็ก textFields ตามลำดับที่คุณต้องการให้ปุ่มถัดไป / ก่อนหน้าตอบกลับ


3

ฉันชอบที่จะ:

@interface MyViewController : UIViewController
@property (nonatomic, retain) IBOutletCollection(UIView) NSArray *inputFields;
@end

ในไฟล์ NIB ฉันขอเกี่ยว textFields ในลำดับที่ต้องการลงในอาร์เรย์ inputFields นี้ หลังจากนั้นฉันทำการทดสอบอย่างง่าย ๆ สำหรับดัชนีของ UITextField ที่รายงานว่าผู้ใช้แตะที่ return return:

// for UITextField
-(BOOL)textFieldShouldReturn:(UITextField*)textField {
    NSUInteger index = [_inputFields indexOfObject:textField];
    index++;
    if (index < _inputFields.count) {
        UIView *v = [_inputFields objectAtIndex:index];
        [v becomeFirstResponder];
    }
    return NO;
}

// for UITextView
-(BOOL)textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
    if ([@"\n" isEqualToString:text]) {
        NSUInteger index = [_inputFields indexOfObject:textView];
        index++;
        if (index < _inputFields.count) {
            UIView *v = [_inputFields objectAtIndex:index];
            [v becomeFirstResponder];
        } else {
            [self.view endEditing:YES];
        }
        return NO;
    }
    return YES;
}

3
if (cell == nil)
{
    cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier กลับมาใช้ใหม่: cellIdentifier];
    txt_Input = [[UITextField alloc] initWithFrame: CGRectMake (0, 10, 150, 30)];
    txt_Input.tag = indexPath.row + 1;
    [self.array_Textfields addObject: txt_Input]; // เริ่มต้นอาร์เรย์ที่ไม่แน่นอนใน ViewDidLoad
}

- (BOOL) textFieldShouldReturn: (UITextField *) textField
{

    int tag = (int) textField.tag;
    UITextField * txt = [self.array_Textfields objectAtIndex: tag];
    [txt กลายเป็น FirstResponder];
    กลับมาใช่;
}

3

ฉันมี UITextField ประมาณ 10+ ตัวในกระดานเรื่องราวของฉันและวิธีที่ฉันเปิดใช้งานฟังก์ชั่นต่อไปคือการสร้างอาร์เรย์ของ UITextField และทำให้ UITextField ถัดไปเป็น firstResponder นี่คือไฟล์การใช้งาน:

#import "RegistrationTableViewController.h"

@interface RegistrationTableViewController ()
@property (weak, nonatomic) IBOutlet UITextField *fullNameTextField;
@property (weak, nonatomic) IBOutlet UITextField *addressTextField;
@property (weak, nonatomic) IBOutlet UITextField *address2TextField;
@property (weak, nonatomic) IBOutlet UITextField *cityTextField;
@property (weak, nonatomic) IBOutlet UITextField *zipCodeTextField;
@property (weak, nonatomic) IBOutlet UITextField *urlTextField;
@property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
@property (weak, nonatomic) IBOutlet UITextField *emailTextField;
@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
@property (weak, nonatomic) IBOutlet UITextField *confirmPWTextField;

@end
NSArray *uiTextFieldArray;
@implementation RegistrationTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"view did load");
    uiTextFieldArray = @[self.fullNameTextField,self.addressTextField,self.address2TextField,self.cityTextField,self.zipCodeTextField,self.urlTextField,self.usernameTextField,self.emailTextField,self.passwordTextField,self.confirmPWTextField];
    for(UITextField *myField in uiTextFieldArray){
        myField.delegate = self;
    }


}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    long index = [uiTextFieldArray indexOfObject:textField];
    NSLog(@"%ld",index);
    if(index < (uiTextFieldArray.count - 1)){
        [uiTextFieldArray[++index] becomeFirstResponder];
    }else{
        [uiTextFieldArray[index] resignFirstResponder];
    }
    return YES;
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

3

สิ่งนี้ใช้ได้กับฉันใน Xamarin.iOS / Monotouch เปลี่ยนปุ่มคีย์บอร์ดเป็นถัดไปผ่านการควบคุมไปยัง UITextField ถัดไปและซ่อนคีย์บอร์ดหลัง UITextField ล่าสุด

private void SetShouldReturnDelegates(IEnumerable<UIView> subViewsToScout )
{
  foreach (var item in subViewsToScout.Where(item => item.GetType() == typeof (UITextField)))
  {
    (item as UITextField).ReturnKeyType = UIReturnKeyType.Next;
    (item as UITextField).ShouldReturn += (textField) =>
    {
        nint nextTag = textField.Tag + 1;
        var nextResponder = textField.Superview.ViewWithTag(nextTag);
        if (null != nextResponder)
            nextResponder.BecomeFirstResponder();
        else
            textField.Superview.EndEditing(true); 
            //You could also use textField.ResignFirstResponder(); 

        return false; // We do not want UITextField to insert line-breaks.
    };
  }
}

ภายในViewDidLoadคุณจะมี:

หากฟิลด์ข้อความของคุณไม่มีแท็กให้ตั้งค่าตอนนี้:

txtField1.Tag = 0;
txtField2.Tag = 1;
txtField3.Tag = 2;
//...

และเพียงแค่โทร

SetShouldReturnDelegates(yourViewWithTxtFields.Subviews.ToList());
//If you are not sure of which view contains your fields you can also call it in a safer way:
SetShouldReturnDelegates(txtField1.Superview.Subviews.ToList());
//You can also reuse the same method with different containerViews in case your UITextField are under different views.

3

นี่คือทางออกที่ง่ายในรวดเร็วโดยไม่ต้องใช้แท็กไม่มีเทคนิคกระดานเรื่องราว ...

เพียงใช้ส่วนขยายนี้:

extension UITextField{

    func nextTextFieldField() -> UITextField?{
        //field to return
        var returnField : UITextField?
        if self.superview != nil{
            //for each view in superview
            for (_, view) in self.superview!.subviews.enumerate(){
                //if subview is a text's field
                if view.isKindOfClass(UITextField){
                    //cast curent view as text field
                    let currentTextField = view as! UITextField
                    //if text field is after the current one
                    if currentTextField.frame.origin.y > self.frame.origin.y{
                        //if there is no text field to return already
                        if returnField == nil {
                            //set as default return
                            returnField = currentTextField
                        }
                            //else if this this less far than the other
                        else if currentTextField.frame.origin.y < returnField!.frame.origin.y{
                            //this is the field to return
                            returnField = currentTextField
                        }
                    }
                }
            }
        }
        //end of the mdethod
        return returnField
    }

}

และเรียกมันว่าสิ่งนี้ (ตัวอย่าง) กับตัวแทนข้อความของคุณ:

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    textField.nextTextFieldField()?.becomeFirstResponder()
    return true
}

ความคิดเห็นหนึ่งเกี่ยวกับสิ่งนี้คือวิธีการของคุณสมมติว่าเขตข้อมูลทั้งหมดจะถูกซ้อนกันในแนวตั้งในการกำกับดูแลเดียว ไม่อนุญาตสำหรับเขตข้อมูลที่จัดกลุ่มและไม่ทำงานเมื่อฟิลด์ข้อความอาจอยู่เคียงข้างกัน ต่อมามีความสำคัญอย่างยิ่งในทุกวันนี้เมื่อเราใช้คลาสขนาดเพื่อจัดเรียงแบบฟอร์มสำหรับมุมมองแนวนอนและเมื่อแสดงแบบฟอร์มบนแท็บเล็ต
Michael Long

3

วิธีที่ปลอดภัยและตรงไปตรงมามากขึ้นโดยถือว่า:

  • ผู้รับมอบสิทธิ์เขตข้อมูลข้อความถูกตั้งค่าเป็นตัวควบคุมมุมมองของคุณ
  • ฟิลด์ข้อความทั้งหมดเป็นมุมมองย่อยของมุมมองเดียวกัน
  • ช่องข้อความมีแท็กตามลำดับที่คุณต้องการดำเนินการ (เช่น textField2.tag = 2, textField3.tag = 3, ฯลฯ )
  • จะย้ายไปอยู่ช่องข้อความต่อไปจะเกิดขึ้นเมื่อคุณแตะที่ผลตอบแทนจากปุ่มบนแป้นพิมพ์ (คุณสามารถเปลี่ยนนี้ต่อไป , ทำฯลฯ )
  • คุณต้องการให้คีย์บอร์ดยกเลิกหลังจากฟิลด์ข้อความสุดท้าย

สวิฟท์ 4.1:

extension ViewController: UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        let nextTag = textField.tag + 1
        guard let nextTextField = textField.superview?.viewWithTag(nextTag) else {
            textField.resignFirstResponder()
            return false
        }

    nextTextField.becomeFirstResponder()

    return false

    }
}

2

ใน textFieldShouldReturn คุณควรตรวจสอบว่า textfield ที่คุณใช้อยู่นั้นไม่ใช่อันสุดท้ายเมื่อพวกเขาคลิกถัดไปและถ้า n ot ไม่เลิกใช้คีย์บอร์ด


เฮ้โอเคใช้งานได้ แต่ฉันจะข้ามไปยังฟิลด์ข้อความถัดไปด้วยปุ่ม "ถัดไป" ได้อย่างไร
phx

2

นี่คือโพสต์เก่า แต่มีอันดับหน้าสูงดังนั้นฉันจะพูดสอดกับโซลูชันของฉัน

ฉันมีปัญหาที่คล้ายกันและจบลงด้วยการสร้างคลาสย่อยของUIToolbarเพื่อจัดการฟังก์ชั่นถัดไป / ก่อนหน้า / ที่ทำในไดนามิก tableView ที่มีส่วน: https://github.com/jday001/DataEntryToolbar

คุณตั้งค่าแถบเครื่องมือเป็น inputAccessoryView ของฟิลด์ข้อความของคุณและเพิ่มลงในพจนานุกรม สิ่งนี้ช่วยให้คุณสามารถวนไปข้างหน้าและถอยหลังได้แม้จะมีเนื้อหาแบบไดนามิก มีวิธีการมอบหมายหากคุณต้องการเปิดใช้งานฟังก์ชั่นของคุณเองเมื่อมีการนำทาง textField เกิดขึ้น แต่คุณไม่ต้องจัดการกับแท็กหรือสถานะการตอบกลับครั้งแรก

มีตัวอย่างโค้ดและแอปตัวอย่างที่ลิงก์ GitHub เพื่อช่วยในรายละเอียดการใช้งาน คุณจะต้องการตัวแบบข้อมูลของคุณเองเพื่อติดตามค่าภายในเขตข้อมูล


2

โดยไม่ต้องใช้แท็กและโดยไม่ต้องเพิ่มคุณสมบัติสำหรับ nextField / nextTextField คุณสามารถลองทำสิ่งนี้เพื่อเลียนแบบ TAB โดยที่ "testInput" เป็นฟิลด์ที่ใช้งานอยู่ในปัจจุบันของคุณ:

if ([textInput isFirstResponder])
    [textInput.superview.subviews enumerateObjectsAtIndexes:
     [NSIndexSet indexSetWithIndexesInRange:
      NSMakeRange([textInput.superview.subviews indexOfObject:textInput]+1,
                  [textInput.superview.subviews count]-[textInput.superview.subviews indexOfObject:textInput]-1)]
                                                    options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
                                                        *stop = !obj.hidden && [obj becomeFirstResponder];
                                                    }];
if ([textInput isFirstResponder])
    [textInput.superview.subviews enumerateObjectsAtIndexes:
     [NSIndexSet indexSetWithIndexesInRange:
      NSMakeRange(0,
                  [textInput.superview.subviews indexOfObject:textInput])]
                                                    options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
                                                        *stop = !obj.hidden && [obj becomeFirstResponder];
                                                    }];

2

ฉันใช้คำตอบของ Michael G. Emmons มาประมาณหนึ่งปีแล้วใช้งานได้ดี ฉันสังเกตเห็นเมื่อเร็ว ๆ นี้ว่าการโทรไปที่ลาออกการตอบกลับแรกและจากนั้นกลายเป็นครั้งแรกการตอบกลับทันทีอาจทำให้แป้นพิมพ์ "ผิดพลาด" หายไปจากนั้นปรากฏขึ้นทันที ฉันเปลี่ยนเวอร์ชันของเขาเล็กน้อยเพื่อข้ามลาออกการตอบกลับแรกหากฟิลด์ถัดไปว่าง

- (BOOL) textFieldShouldReturn: (UITextField *) textField
{ 

    ถ้า ([textField isKindOfClass: [คลาส NRTextField]])
    {
        NRTextField * nText = (NRTextField *) textField;
        if ([nText nextField]! = nil) {
            dispatch_async (dispatch_get_main_queue ()
                           ^ {[[ถัดไปถัดไปสนามกีฬา] });

        }
        อื่น{
            [ฟิลด์ข้อความลาออกการตอบกลับแรก];
        }
    }
    อื่น{
        [ฟิลด์ข้อความลาออกการตอบกลับแรก];
    }

    กลับจริง

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.