วิธีปิดใช้งานการแก้ไข UITextField แต่ยังยอมรับการสัมผัส


108

ฉันกำลังสร้างUITextFieldที่มีUIPickerViewเป็นinputView. มันดีทั้งหมดยกเว้นว่าฉันสามารถแก้ไขโดยคัดลอกวางตัดและเลือกข้อความและฉันไม่ต้องการ เฉพาะตัวเลือกเท่านั้นที่ควรแก้ไขฟิลด์ข้อความ

ฉันได้เรียนรู้ว่าฉันสามารถปิดการใช้งานการแก้ไขโดยการตั้งค่าsetEnabledหรือการsetUserInteractionEnabled NOโอเค แต่ TextField หยุดตอบสนองต่อการสัมผัสและเครื่องมือเลือกไม่ปรากฏขึ้น

ฉันจะทำอย่างไรเพื่อให้บรรลุ

คำตอบ:


131

การใช้ตัวแทนฟิลด์ข้อความมีวิธีการ

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

ส่งคืน NO จากสิ่งนี้และความพยายามใด ๆ ของผู้ใช้ในการแก้ไขข้อความจะถูกปฏิเสธ

ด้วยวิธีนี้คุณสามารถเปิดใช้งานช่องนี้ได้ แต่ยังป้องกันไม่ให้ผู้อื่นวางข้อความลงในช่องนั้น


4
หากคุณยังคงต้องการตอบสนองต่อการสัมผัสให้ตอบกลับ "แตะลง" ไม่ใช่ "แตะด้านใน" มิฉะนั้นกิจกรรมของคุณจะไม่ถูกเรียก
radven

@NickLockwood มีวิธีใดบ้างที่เรายังสามารถอนุญาตให้ textField เป็นผู้ตอบกลับรายแรก แต่ปิดใช้งานการโต้ตอบกับผู้ใช้และซ่อนเครื่องหมายคาเร็ต?
onmyway133

1
@entropy ฉันสมมติว่าคุณต้องการเลือกเนื้อหาเพื่อให้ผู้ใช้สามารถคัดลอกได้หรือไม่? หากคุณซับคลาส UITextField คุณสามารถลบล้างพฤติกรรมใด ๆ ได้เช่นคุณสามารถบังคับให้ฟิลด์เลือกทั้งหมดเสมอเมื่อใดก็ตามที่ผู้ใช้สัมผัสซึ่งจะซ่อนคาเร็ตได้อย่างมีประสิทธิภาพ
Nick Lockwood

1
@LoryLory เหมือนกันเพียงแค่ใช้ Swift syntax สำหรับวิธี delegate แทน
Nick Lockwood

5
อย่างแม่นยำมากขึ้นเราสามารถใช้ "textFieldShouldBeginEditing" ได้หากจำเป็น
Naveen Shan

23

แปลคำตอบของNickให้รวดเร็ว:

P / S: Return false => ฟิลด์ข้อความไม่สามารถป้อนข้อมูลแก้ไขโดยแป้นพิมพ์ มันสามารถตั้งค่าข้อความด้วย code.EX: textField.text = "My String Here"

override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return false
}

3
สิ่งนี้ไม่ได้ผลสำหรับฉัน เพียงคลิกที่ช่องข้อความค้างไว้จนกระทั่งการซูมปรากฏขึ้นและเมนูตัด / คัดลอก / วาง iOS จะปรากฏขึ้นและฉันสามารถใช้สิ่งนั้นเพื่อแก้ไขข้อความได้
RowanPD

3
swift 4: `func textField (_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {return false}`
lionello

16

นี่จะเป็นวิธีที่ง่ายที่สุด:

ใน viewDidLoad: (ตั้งค่าผู้รับมอบสิทธิ์เฉพาะสำหรับฟิลด์ข้อความซึ่งไม่ควรแก้ไขได้

self.textfield.delegate=self;

และแทรกฟังก์ชันผู้รับมอบสิทธิ์นี้:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
return NO;
}

แค่นั้นแหละ!


27
สิ่งนี้ป้องกันไม่ให้ตัวเลือกถูกนำเสนอและไม่สามารถแก้ไขปัญหาที่อธิบายไว้ได้
Martin Lockett

6
@MartinLockett หากคุณทริกเกอร์UIPickerViewพฤติกรรมจากวิธีการมอบสิทธิ์นั้นจะทำงานได้ดี
Albert Bori


7

มันจะเป็นความสง่างามมากขึ้นเพื่อสร้างเป็น subclass กำหนดเองของUITextFieldผลตอบแทนที่NOสำหรับการโทรทั้งหมดไปcanPerformAction:withSender:(หรืออย่างน้อยที่actionเป็น@selector(cut)หรือ@selector(paste)) ตามที่อธิบายไว้ที่นี่

นอกจากนี้ฉันยังใช้ - (BOOL) textField: (UITextField *) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString *) string ตามคำแนะนำของ Nick เพื่อปิดใช้งานการป้อนข้อความจากคีย์บอร์ดบลูทู ธ


ตลอดชีวิตของฉันทำไม่ได้ว่าจะทำอย่างไร ไม่เคยมีการเรียกคลาสย่อยcanPerformActionและshouldChangeCharactersInRangeวิธีการ
Nestor

7

เพียงแค่วาง UIButton ลงบน UITextField ทั้งหมดโดยไม่มีข้อความป้ายกำกับซึ่งทำให้ "มองไม่เห็น" ปุ่มนี้สามารถรับและมอบหมายการสัมผัสแทน Textfield ได้และยังคงมองเห็นเนื้อหาของ TextField ได้



3

ฉันใช้โซลูชันที่ MrMage ให้มา สิ่งเดียวที่ฉันเพิ่มคือคุณควรลาออกจาก UITextView ในฐานะผู้ตอบกลับคนแรกมิฉะนั้นคุณจะติดขัดกับข้อความที่เลือก

นี่คือรหัสที่รวดเร็วของฉัน:

class TouchableTextView : UITextView {

    override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        self.resignFirstResponder()
        return false
    }

    override func shouldChangeTextInRange(range: UITextRange, replacementText text: String) -> Bool {
        self.resignFirstResponder()
        return false
    }

}

1

สำหรับทางเลือกอื่นที่จัดการ UIPickerView และ Action Sheets ให้ชำระเงิน ActionSheetPicker

https://github.com/TimCinel/ActionSheetPicker

มันเปิดใช้งาน cocoapods จัดการกับปุ่มยกเลิกและทำทั้งหมดบนแผ่นการดำเนินการ ตัวอย่างภายในโครงการตัวอย่างดีมาก ฉันเลือก ActionSheetStringPicker ซึ่งจัดการได้อย่างง่ายดายเพียงแค่ตัวเลือกที่ใช้ String แต่ API สามารถจัดการทุกอย่างที่ฉันคิดได้

เดิมทีฉันเริ่มต้นวิธีแก้ปัญหาเหมือนกับคำตอบที่ทำเครื่องหมายไว้ แต่สะดุดเข้ากับโครงการนี้และใช้เวลาประมาณ 20 นาทีในการรวมสิ่งต่าง ๆ เข้ากับแอปของฉันสำหรับการใช้งานรวมถึงการใช้ cocopods: ActionSheetPicker (~> 0.0)

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

ดาวน์โหลด git project และดูคลาสต่อไปนี้:

  • ActionSheetPickerViewController.m
  • ActionSheetPickerCustomPickerDelegate.h

นี่คือโค้ดส่วนใหญ่โดยประมาณที่ฉันเพิ่มรวมถึงการนำเข้า * .h

- (IBAction)gymTouched:(id)sender {
      NSLog(@"gym touched");

      [ActionSheetStringPicker showPickerWithTitle:@"Select a Gym" rows:self.locations initialSelection:self.selectedIndex target:self successAction:@selector(gymWasSelected:element:) cancelAction:@selector(actionPickerCancelled:) origin:sender];
 }


- (void)actionPickerCancelled:(id)sender {
    NSLog(@"Delegate has been informed that ActionSheetPicker was cancelled");
}


- (void)gymWasSelected:(NSNumber *)selectedIndex element:(id)element {
    self.selectedIndex = [selectedIndex intValue];

    //may have originated from textField or barButtonItem, use an IBOutlet instead of element
    self.txtGym.text = [self.locations objectAtIndex:self.selectedIndex];
}


-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    return NO;  // Hide both keyboard and blinking cursor.
}

พ็อดเวอร์ชันอัปเดตอยู่ที่นี่ github.com/skywinder/ActionSheetPicker-3.0
Nick N

1

ในการป้องกันการแก้ไข UITextField ในขณะที่ใช้ UIPickerView สำหรับการเลือกค่า (ใน Swift):

self.txtTransDate = self.makeTextField(self.transDate, placeHolder: "Specify Date")
self.txtTransDate?.addTarget(self, action: "txtTransDateEditing:", forControlEvents: UIControlEvents.EditingDidBegin)

func makeTextField(text: String?, placeHolder: String) -> UITextField {
    var textField = UITextField(frame: CGRect(x: 140, y: 0, width: 220.00, height: 40.00));
    textField.placeholder = placeHolder
    textField.text = text
    textField.borderStyle = UITextBorderStyle.Line
    textField.secureTextEntry = false;
    textField.delegate = self
    return textField
}


func txtTransDateEditing(sender: UITextField) {
    var datePickerView:UIDatePicker = UIDatePicker()
    datePickerView.datePickerMode = UIDatePickerMode.Date
    sender.inputView = datePickerView
    datePickerView.addTarget(self, action: Selector("datePickerValueChanged:"), forControlEvents: UIControlEvents.ValueChanged)
}

func datePickerValueChanged(sender: UIDatePicker) {
    var dateformatter = NSDateFormatter()
    dateformatter.dateStyle = NSDateFormatterStyle.MediumStyle
    self.txtTransDate!.text = dateformatter.stringFromDate(sender.date)
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool  {
    self.resignFirstResponder()
    return false
}

0

วิธีแก้ปัญหานี้ใช้ได้ผล วาง UIView แบบโปร่งใสเหนือช่องข้อความและใช้รหัสต่อไปนี้:

- (void)viewDidLoad
{
 [super viewDidLoad];

   UILongPressGestureRecognizer *press = [[UILongPressGestureRecognizer alloc]             initWithTarget:self action:@selector(longPress)];
[transparentView addGestureRecognizer:press];
 [press release];
  press = nil;
}

-(void)longPress
{
   txtField.userInteractionEnabled = NO;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   txtField.userInteractionEnabled = YES;
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
  [txtField becomeFirstResponder];
}

1
ฉันสับสนว่าทำไมคุณไม่ใช้ UIButton + touchUpInside แบบโปร่งใสธรรมดาและเลือกใช้ท่าทางสัมผัส UIView + แทน
Chen Li Yong

0

ทำให้ inputView ของคุณถูกนำเสนอโดยฟิลด์ข้อความที่ซ่อนอยู่ซึ่งจะเปลี่ยนข้อความของที่นำเสนอและปิดใช้งาน


0

ไม่แน่ใจว่าแฮ็กเป็นอย่างไร แต่สิ่งเดียวที่ทำให้เคล็ดลับในกรณีของฉันคือการเพิ่มการดำเนินการเป้าหมายและเรียก endEditing เนื่องจากเครื่องมือเลือกของฉันควบคุมค่า UITextField.text ของฉันฉันจึงสามารถปิดแป้นพิมพ์ได้ทันทีที่ผู้ใช้คลิกที่ฟิลด์ นี่คือรหัสบางส่วน:

uiTextFieldVariable.addTarget(self, action: #selector(dismissKeyboard), for: .editingDidBegin)

@objc private func dismissKeyboard() {
    endEditing(true)
}


-7

สิ่งนี้ได้ผลสำหรับฉัน [textview setEditable:NO]; คำตอบข้างต้นทำให้สถานการณ์ซับซ้อนเกินไป


1
OP เขียนว่า "ฉันได้เรียนรู้ว่าฉันสามารถปิดใช้งานการแก้ไขได้โดยการตั้งค่า setEnabled หรือ setUserInteractionEnabled: NO ถึง NO ตกลง แต่ TextField หยุดตอบสนองต่อการสัมผัสและตัวเลือกไม่แสดงขึ้น" คำตอบของคุณจะหยุดเหตุการณ์ทั้งหมดซึ่งไม่ต้องการผลลัพธ์
maninvan

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