Bagaimana cara menonaktifkan pengeditan UITextField tetapi masih menerima sentuhan?

107

Saya membuat UITextFieldyang memiliki UIPickerViewas inputView. Semuanya bagus, kecuali saya dapat mengedit dengan menyalin, menempel, memotong dan memilih teks, dan saya tidak menginginkannya. Hanya Picker yang harus mengubah bidang teks.

Saya telah belajar bahwa saya dapat menonaktifkan pengeditan dengan mengatur setEnabledatau setUserInteractionEnabledke NO. Oke, tapi BidangTeks berhenti merespons sentuhan dan alat pilih tidak muncul.

Apa yang dapat saya lakukan untuk mencapainya?

Luiz de Prá
sumber

Jawaban:

131

Menggunakan delegasi textfield, ada sebuah metode

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

Kembalikan NO dari ini, dan setiap upaya pengguna untuk mengedit teks akan ditolak.

Dengan cara itu Anda dapat membiarkan bidang diaktifkan tetapi tetap mencegah orang menempelkan teks ke dalamnya.

Nick Lockwood
sumber
4
Jika Anda masih ingin menanggapi sentuhan, tanggapi dengan "sentuhan ke bawah" dan bukan "sentuh di dalam". Jika tidak, acara Anda tidak akan pernah dipanggil.
radven
@NickLockwood adakah cara agar kita masih dapat mengizinkan textField untuk menjadi responden pertama, tetapi menonaktifkan interaksi pengguna dan menyembunyikan tanda sisipan?
onmyway133
1
@entropy Saya berasumsi Anda ingin dapat memilih konten sehingga pengguna dapat menyalinnya? Jika Anda membuat subkelas UITextField Anda dapat mengganti hampir semua perilaku - misalnya Anda dapat memaksa field untuk selalu memilih semua kapanpun pengguna menyentuh, yang secara efektif akan menyembunyikan tanda sisipan.
Nick Lockwood
1
@LoryLory itu sama, cukup gunakan sintaks Swift untuk metode delegasi sebagai gantinya.
Nick Lockwood
5
Lebih tepatnya kita dapat menggunakan "textFieldShouldBeginEditing" jika diperlukan
Naveen Shan
22

Terjemahkan jawaban Nick menjadi cepat:

P / S: Return false => bidang teks tidak dapat dimasukkan, diedit dengan keyboard. Itu hanya dapat mengatur teks dengan kode.EX: textField.text = "My String Here"

override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return false
}
lee
sumber
3
Ini tidak berhasil untuk saya. Cukup klik lama bidang teks sampai zoom muncul dan menu potong / salin / tempel iOS muncul dan saya dapat menggunakannya untuk mengubah teks.
RowanPD
2
swift 4: `func textField (_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {return false}`
lionello
16

Ini akan menjadi yang paling sederhana dari semuanya:

di viewDidLoad: (setel delegasi hanya untuk bidang teks yang seharusnya tidak dapat diedit.

self.textfield.delegate=self;

dan masukkan fungsi delegasi ini:

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

Itu dia!

Ankish Jain
sumber
27
Hal ini mencegah pemetik ditampilkan sehingga tidak memperbaiki masalah yang dijelaskan
Martin Lockett
6
@MartinLockett Jika Anda memicu UIPickerViewperilaku dari metode delegasi itu, itu bekerja dengan baik.
Albert Bori
9

Dalam 3+ cepat:

class MyViewController: UIViewController, UITextFieldDelegate {

   override func viewDidLoad() {
      self.myTextField.delegate     = self
   }

   func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
      if textField == myTextField {
         // code which you want to execute when the user touch myTextField
      }
      return false
   }
}
Nadeesha Lakmal
sumber
7

Akan lebih elegan untuk membuat subkelas khusus UITextFieldyang mengembalikan NOsemua panggilan ke canPerformAction:withSender:(atau setidaknya di mana actionada @selector(cut)atau @selector(paste)), seperti yang dijelaskan di sini .

Selain itu, saya juga mengimplementasikan - (BOOL) textField: (UITextField *) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString *) string sesuai saran Nick untuk menonaktifkan teks input dari keyboard Bluetooth.

MrMage
sumber
Tidak bisa seumur hidupku memikirkan bagaimana melakukan itu. Subclass canPerformActiondan shouldChangeCharactersInRangemetode tidak pernah dipanggil.
Nestor
7

Cukup tempatkan UIButton tepat di atas seluruh UITextField tanpa teks Label yang membuatnya "tidak terlihat". Tombol ini dapat menerima dan mendelegasikan sentuhan daripada Textfield dan konten TextField masih terlihat.

Timm Kent
sumber
7

Di Swift:

func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
    questionField.resignFirstResponder();
    // Additional code here
    return false
}
Saranya
sumber
3

Saya menggunakan solusi yang disediakan oleh MrMage. Satu-satunya hal yang saya tambahkan adalah Anda harus mengundurkan diri UITextView sebagai responden pertama, jika tidak Anda terjebak dengan teks yang dipilih.

Ini kode swift saya:

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
    }

}
Leedrick
sumber
1

Untuk alternatif yang menangani UIPickerView dan Action Sheets, periksa ActionSheetPicker

https://github.com/TimCinel/ActionSheetPicker

Ini cocoapods diaktifkan. Ini menangani semua tombol batal dan selesai pada Lembar Tindakan. Contoh dalam proyek sampel sangat bagus. Saya memilih ActionSheetStringPicker, yang menangani dengan mudah hanya opsi berbasis String, tetapi API dapat menangani hampir semua hal yang dapat saya pikirkan.

Saya awalnya memulai solusi seperti jawaban yang dicentang, tetapi tersandung ke proyek ini dan membutuhkan waktu sekitar 20 menit untuk mengintegrasikan hal-hal ke dalam aplikasi saya untuk digunakan termasuk menggunakan cocopods: ActionSheetPicker (~> 0.0)

Semoga ini membantu.

Unduh proyek git dan lihat kelas-kelas berikut:

  • ActionSheetPickerViewController.m
  • ActionSheetPickerCustomPickerDelegate.h

Berikut ini kira-kira sebagian besar kode yang saya tambahkan, ditambah impor * .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.
}
Nick N.
sumber
Versi terbaru dari pod ada di sini. github.com/skywinder/ActionSheetPicker-3.0
Nick N
1

Untuk mencegah pengeditan UITextField saat menggunakan UIPickerView untuk memilih nilai (di 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
}
Thiru
sumber
0

Solusi ini berhasil. Letakkan UIView transparan di atas bidang teks dan terapkan kode berikut:

- (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];
}
cocoakomali.dll
sumber
1
Saya bingung mengapa Anda tidak menggunakan UIButton + touchUpInside transparan sederhana, dan memilih gerakan UIView + sebagai gantinya.
Chen Li Yong
0

Buat inputView Anda disajikan oleh bidang teks tersembunyi yang juga mengubah teks yang disajikan dan yang dinonaktifkan.

Sandro Vezzali
sumber
-5

Saya menggunakan:

[self.textField setEnabled:NO];

dan bekerja dengan baik

Chris
sumber
-7

Ini berhasil bagi saya [textview setEditable:NO]; . Jawaban di atas terlalu memperumit situasi.

Tolgab
sumber
1
OP menulis "Saya belajar bahwa saya dapat menonaktifkan pengeditan dengan menyetel setEnabled atau setUserInteractionEnabled: NO ke NO. Oke, tetapi TextField berhenti merespons sentuhan dan alat pilih tidak muncul." Jawaban Anda akan menghentikan semua peristiwa, yang bukan merupakan hasil yang diinginkan.
maninvan
@Tolgab bukan solusi yang bahkan terkait untuk OP ini!
Anurag Sharma