Caranya nonaktifkan Copy, Cut, Select, Select All di UITextView


110

The UITextView's Copy, Cut, Pilih, Pilih Semua fungsi ditampilkan secara default ketika saya menekan ke bawah pada layar. Tapi, dalam proyek saya, UITextFieldhanya baca saja. Saya tidak membutuhkan fungsi ini. Tolong beri tahu saya cara menonaktifkan fitur ini.


3
tempat [UIMenuController sharedMenuController] .menuVisible = NO; di - (BOOL) canPerformAction: (SEL) tindakan denganSender: (id) metode pengirim.
ravoorinandan

Jawaban:


108

Cara termudah untuk menonaktifkan operasi papan tempel adalah dengan membuat subkelas UITextViewyang menggantikan canPerformAction:withSender:metode untuk mengembalikan NOtindakan yang tidak ingin Anda izinkan:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(paste:))
        return NO;
    return [super canPerformAction:action withSender:sender];
}

Lihat juga UIResponder


1
@rpetrichm, saya menggunakan solusi Anda, salin / tempel / potong / pilih / pilihSemua opsi dinonaktifkan tetapi masih akan datang Ganti ... | BIU | Tentukan opsi. Saya ingin menonaktifkan menu lengkap itu.
Ameet Dhas

3
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; }- untuk memblokir semua opsi
Islam Q.

Itu bagus, namun saya tidak tahu bagaimana melakukan ini untuk UISearchBar - karena ada juga bidang teks di dalamnya, saya pikir saya dapat menimpa metode subkelas UISearchBar tetapi sayangnya itu tidak berhasil. Ada ide untuk ini?
borchero

saya memiliki banyak kendali. bagaimana cara mengizinkan salin tempel hanya pada satu kontrol?
Gaucho

Ini tidak berfungsi untuk UITextView, meskipun saya telah melihat solusi ini disarankan di sejumlah tempat di SO. Adakah yang tahu bagaimana melakukan ini?
Pigpocket

67

Subclass UITextView dan timpa canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
    return NO;
}

Perhatikan, ini hanya berlaku untuk UITextView yang tidak dapat diedit! Belum mengujinya pada yang dapat diedit ...


Saya pikir return NO;pada - (BOOL)canPerformAction:(SEL)action withSender:(id)sendermetode adalah pilihan yang lebih baik.
Islam Q.

29

Jika Anda ingin menonaktifkan potong / salin / tempel pada semua UITextView aplikasi Anda, Anda dapat menggunakan kategori dengan:

@implementation UITextView (DisableCopyPaste)

- (BOOL)canBecomeFirstResponder
{
    return NO;
}

@end

Ini menyimpan subclass ... :-)


3
Anda juga dapat meletakkan ini hanya di /, file Anda di mana Anda membutuhkan perilaku ini.
markus_p

4
Ini hanya bekerja sebagai efek samping dan mencegah UITextViewdari berperilaku seperti yang diharapkan ketika, misalnya, dapat diedit dan disentuh. Ini banyak yang harus dikesampingkan canPerformAction:withSender:; untuk itulah protokolnya.
jdc

16
Anda tidak dapat mengganti metode dengan aman menggunakan kategori. Ini adalah perilaku yang tidak terdefinisi. Anda harus membuat subkelas untuk mengganti metode dengan aman.
Rob Napier

2
Catatan: Ini akan berlaku untuk semua UITextView dalam aplikasi Anda. Tidak ideal di sebagian besar waktu.
bbrame

2
Perhatikan juga bahwa Apple tidak menyarankan hal ini : "Jika nama metode yang dideklarasikan dalam kategori sama dengan metode di kelas asli, atau metode di kategori lain di kelas yang sama (atau bahkan superclass), perilakunya adalah undefined tentang penerapan metode mana yang digunakan pada waktu proses ... [dan] dapat menyebabkan masalah saat menggunakan kategori untuk menambahkan metode ke kelas Cocoa atau Cocoa Touch standar. "
Rob

29

Ini adalah solusi kerja terbaik untuk saya:

UIView *overlay = [[UIView alloc] init];  
[overlay setFrame:CGRectMake(0, 0, myTextView.contentSize.width, myTextView.contentSize.height)];  
[myTextView addSubview:overlay];  
[overlay release];

dari: https://stackoverflow.com/a/5704584/1293949


3
bagus, tidak ada subclassing di sini!
Martin Reichl

7
Saya suka pendekatan lakban dan kawat baling di sini. Saya berharap saya dapat memberi Anda +1 lagi :) Sebagai gantinya, ini adalah bintang emas: i.imgur.com/EXLFt1Z.jpg
jdc

22

Jawaban @rpetrich berhasil untuk saya. Saya memposting kode yang diperluas seandainya itu menghemat waktu seseorang.

Dalam kasus saya, saya tidak menginginkan popup apa pun, tetapi saya ingin UITextField dapat menjadi penanggap pertama.

Sayangnya, Anda masih mendapatkan munculan kaca pembesar saat mengetuk dan menahan bidang teks.

@interface NoSelectTextField : UITextField

@end

@implementation NoSelectTextField

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if (action == @selector(paste:) ||
        action == @selector(cut:) ||
        action == @selector(copy:) ||
        action == @selector(select:) ||
        action == @selector(selectAll:) ||
        action == @selector(delete:) ||
        action == @selector(makeTextWritingDirectionLeftToRight:) ||
        action == @selector(makeTextWritingDirectionRightToLeft:) ||
        action == @selector(toggleBoldface:) ||
        action == @selector(toggleItalics:) ||
        action == @selector(toggleUnderline:)
        ) {
            return NO;
    }
    return [super canPerformAction:action withSender:sender];
}

@end

Cepat 4

class NoSelectTextField: UITextField {

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(paste(_:)) ||
            action == #selector(cut(_:)) ||
            action == #selector(copy(_:)) ||
            action == #selector(select(_:)) ||
            action == #selector(selectAll(_:)) ||
            action == #selector(delete(_:)) ||
            action == #selector(makeTextWritingDirectionLeftToRight(_:)) ||
            action == #selector(makeTextWritingDirectionRightToLeft(_:)) ||
            action == #selector(toggleBoldface(_:)) ||
            action == #selector(toggleItalics(_:)) ||
            action == #selector(toggleUnderline(_:)) {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
    }

}

1
Silakan posting versi cepat untuk ini juga. Terima kasih.
Salman Khakwani

@pinch: tnx. Masih memegang air di iOS 12.1.3.
YvesLeBorg

20

Jika Anda tidak memerlukan UITextView untuk menggulir, solusi paling sederhana yang tidak melibatkan sub-pengelompokan adalah dengan menonaktifkan interaksi pengguna untuk tampilan teks:

textField.userInteractionEnabled = NO;

2
Ini menghilangkan penyadapan pada link dll jika itu yang ada di textview. Perlu dicatat bahwa ini bukan solusi yang baik untuk menyembunyikan pilih / salin / tempel, tetapi juga tetap mengaktifkan beberapa tingkat interaksi.
barfoon

3
Yah, saya pikir itu sudah jelas.
Luke Redpath

Saya menggunakan bidang teks sebagai label untuk gambar dalam permainan dan saya tidak ingin kaca pembesar muncul dan tidak ada alasan untuk menyalin teks. Ini sangat bagus untuk saya. Saya menggunakan teks bergaya di UIWebView dan baris yang sama juga berfungsi di sana.
JScarry

15

Cara termudah adalah membuat subclass UITextView yang menggantikan canPerformAction: withSender:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender    
{    
     [UIMenuController sharedMenuController].menuVisible = NO;  //do not display the menu
     [self resignFirstResponder];                      //do not allow the user to selected anything
     return NO;
}

Ini adalah solusi terbaik untuk dapat mengetik teks tetapi tidak ada yang lain, dan memungkinkan ketukan pada bidang teks untuk tidak lagi 'dicegat'. Ini melakukan apa yang diinginkan OP, dan banyak lagi.
hlfcoding

13

Ketika saya mengembalikan NO di canPerformAction di iOS 7, saya akan mendapatkan banyak kesalahan seperti ini:

<Error>: CGContextSetFillColorWithColor: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.

Solusi saya adalah sebagai berikut:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
    }];
    return [super canPerformAction:action withSender:sender];
}

Triknya adalah menyembunyikan pengontrol menu di siklus berikutnya di antrean utama (tepat setelah ditampilkan).


benar-benar bagus. satu-satunya masalah adalah saya memiliki 2 tampilan teks dan satu bidang teks dan saya ingin menghindari salin-tempel hanya pada bidang textView. bagaimana identitas yang disebut canPerformAction? variabel pengirim adalah UIMenuController
Gaucho

1
Ia bekerja pada subclass UITextField (atau UITextView). Jika Anda tidak menggunakan subclass yang Anda buat, itu tidak akan berpengaruh. Misalnya saya membuat TextFieldWithoutCopyPaste dan menggunakannya di mana saya tidak ingin memiliki fungsi copy paste.
Adam Wallner

ok, kamu benar. Tapi dalam kasus saya, textView membutuhkan subclass untuk menggunakan canPerformAction dan textField membutuhkan subclass untuk menggunakan textFieldDidBeginEditing untuk menganimasikan jendela saat keyboard ditampilkan. animasi menggerakkan jendela dengan keyboard. Saya menggunakan metode ini untuk menghindari keyboard menutupi bidang teks.
Gaucho

10

Ini adalah cara termudah untuk menonaktifkan seluruh Menu Pilih / Salin / Tempel dalam UITextView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{    
    [UIMenuController sharedMenuController].menuVisible = NO;
    return NO;    
}

Bekerja untuk UITextField juga. Terima kasih telah berbagi.
Gaurav Srivastava

1
Saya menggunakan kode di atas masih saya mendapatkan menu cara menonaktifkan itu tolong bantu saya.
Bittoo

4

Sejak iOS 7, ada properti di UITextView:

 @property(nonatomic,getter=isSelectable) BOOL selectable;

Ini membuat tampilan tidak mengizinkan pemilihan teks. Bekerja dengan baik untuk saya.


4

Jika Anda ingin mengganti keyboard dengan, katakanlah, UIPickersebagai inputView(dengan tentu saja toolbar sebagai inputAccesotyView), maka solusi ini mungkin membantu ...

  • Melaksanakan textFieldShouldBeginEditing:
  • bagian dalam textField.userInteractionEnabled = NO;
  • Kemudian saat Anda akan menutup UIPickerView, setel ke YES.

Dengan melakukan ini, Anda akan dapat mengetuk UITextFielddan menampilkan opsi untuk memilih dari UIPickerView, pada saat ini Anda UITextFieldmemang tidak akan bereaksi terhadap peristiwa sentuh apa pun (ini termasuk sentuh dan tahan untuk memotong, menyalin, dan menempel). Namun, Anda harus ingat untuk mengaturnya kembali ke YA ketika Anda menutup Anda, UIPickerViewnamun Anda tidak akan dapat mengakses UIPickerViewlagi.

Satu-satunya momen ketika gagal adalah ketika pengguna memulai dengan mengetuk dan menahan UITextView, maka Anda akan melihat potong salin dan tempel lagi untuk pertama kalinya. Inilah sebabnya mengapa Anda harus selalu memvalidasi masukan Anda. Ini yang paling mudah yang bisa saya pikirkan. Opsi lainnya adalah menggunakan UILabelteks untuk baca-saja tetapi Anda kehilangan banyak fungsi hebat dari UITextView.


4

Subclass UITextView - swift 4.0

     override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }

Aneh sekali? itu masih menunjukkan opsi "Tempel" tetapi jangan lakukan jika ditekan ...
iOS Flow

4

Jika Anda ingin menonaktifkan popup untuk UITextFieldkemudian coba UITextFieldDelegatemetode ini untuk beralih isUserInteractionEnabled.

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    textField.isUserInteractionEnabled = false
    return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
    textField.isUserInteractionEnabled = true
    return true
}

3

Ini dapat dilakukan dengan mudah di storyboard (Xcode 6). Hapus centang Editable dan Selectable di Attributes Inspector. Anda masih dapat menggulir tampilan teks.masukkan deskripsi gambar di sini


3

Ini berhasil untuk saya. Pastikan Anda memanggil resignFirstResponder di textView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
  [self.textView resignFirstResponder];
  return NO;
}

2

Saya memberikan jawaban yang berfungsi di sini untuk menonaktifkan pemilihan teks + kaca pembesar, tetap mengaktifkan tautan yang dapat diglik. Harapan yang membantu:

Setelah cukup lama mencoba, saya berhasil menghentikan pemilihan teks, memperbesar, dan menjaga deteksi data (tautan dapat diklik dll) dengan mengganti addGestureRecognizer pada subkelas UITextView yang hanya mengizinkan UILongPressGestureRecognizer yang menunda akhir sentuhan:

UIUnselectableTextView.m

-(void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
    if([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] && gestureRecognizer.delaysTouchesEnded)
    {
        [super addGestureRecognizer:gestureRecognizer];
    }
}

2

Untuk Swift 3 , ini diubah menjadi:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
}

2

Anda dapat memperbaikinya di papan cerita Anda dengan menghapus centang pada kotak berikut:

masukkan deskripsi gambar di sini

Atau Anda dapat mengatur secara terprogram seperti ini:

textView.selectable = false
textView.editable = false

1

Saya telah selesai melakukannya. Pada UITextViewopsi saya, saya telah menonaktifkan potong, salin, pilih, dll dengan sangat mudah.

Saya menempatkan UIViewdi tempat yang sama di mana saya telah menempatkan UITextView, tetapi self.viewdan menambahkan touchDelegatemetode sebagai berikut:

(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *scrollTouch=[touches anyObject];
    if(scrollTouch.view.tag==1)
    {
        NSLog(@"viewTouched");
        if(scrollTouch.tapCount==1)
            [textView1 becomeFirstResponder];
        else if(scrollTouch.tapCount==2)
        {
            NSLog(@"double touch");
            return;
        }

    }
}

dan itu berhasil untuk saya. Terima kasih.


1

Cepat

textView.selectable = false // disable text selection (and thus copy/paste/etc)

Terkait

textView.editable = false // text cannot be changed but can still be selected and copied
textView.userInteractionEnabled = false // disables all interaction, including scrolling, clicking on links, etc.

1

Jika Anda ingin menambahkan opsi kustom ke UITextView tetapi menonaktifkan fungsi yang ada, berikut ini cara melakukannya di Swift 3 :

Untuk menonaktifkan fungsi salin, tempel, potong, buat subkelas dan timpa yang berikut ini:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
} 

Di ViewController Anda memiliki CustomTextView menambahkan berikut ini untuk menambahkan opsi Anda:

  let selectText = UIMenuItem(title: "Select", action: #selector(ViewController.selected))

    func selected() {

    if let selectedRange = textView.selectedTextRange, let 
     selectedText = textView.text(in: selectedRange) {

     }


    print("User selected text: \(selectedText)")

    }

1

Metode ini akan menonaktifkan sepenuhnya menu Select, Select All, Paste. Jika Anda masih mendapatkan tindakan lain, maka tambahkan saja ke kondisi if seperti di bawah ini.

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender // This is to disable select / copy / select all / paste menu
    {
        if (action == @selector(copy:) || action == @selector(selectAll:) || action == @selector(select:) || action == @selector(paste:))
            return NO;
        return [super canPerformAction:action withSender:sender];
    }

0

Anda bisa membuat kategori seperti ini:

UITextView + Selectable. H

@interface UITextView (Selectable)

@property (nonatomic, assign, getter = isTextSelectable) bool textSelectable;

@end

UITextView + Selectable.m

#import "UITextView+Selectable.h"

#import <objc/runtime.h>

#define TEXT_SELECTABLE_PROPERTY_KEY @"textSelectablePropertyKey"

@implementation UITextView (Selectable)

@dynamic textSelectable;

-(void)setTextSelectable:(bool)textSelectable {
    objc_setAssociatedObject(self, TEXT_SELECTABLE_PROPERTY_KEY, [NSNumber numberWithBool:textSelectable], OBJC_ASSOCIATION_ASSIGN);
}

-(bool)isTextSelectable {
    return [objc_getAssociatedObject(self, TEXT_SELECTABLE_PROPERTY_KEY) boolValue];
}

-(bool)canBecomeFirstResponder {
    return [self isTextSelectable];
}

@end

1
Ini bukanlah cara yang baik untuk menyelesaikannya. Pertama, itu mempengaruhi segalanya, karena itu ada dalam kategori. Kedua, menggunakan objek terkait untuk tugas yang agak mudah dapat menimbulkan lebih banyak masalah nanti dengan debugging (mengapa itu bekerja seperti ini ketika Anda lupa apa yang Anda lakukan) daripada memberikan keuntungan. Sebaiknya hindari jika memungkinkan menurut saya. Membuat kode menjadi kurang mudah ditemukan & debug dan dipahami oleh programmer baru dalam proyek.
Vive

0

Subclassing UITextViewdan overriding - (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizeradalah kemungkinan lain untuk menonaktifkan tindakan yang tidak diinginkan.

Gunakan kelas gestureRecognizer-object untuk memutuskan apakah tindakan harus ditambahkan atau tidak.


0

(SWIFT) Jika Anda hanya menginginkan bidang teks dasar tanpa opsi menu atau kaca pembesar, buat subkelas UITextField yang mengembalikan false ke gestureRecognizerShouldBegin:

class TextFieldBasic: UITextField {
    override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {

        return false
    }
}

Ini akan melewati semua fungsionalitas sentuh pada bidang teks tetapi tetap memungkinkan Anda menggunakan keyboard popup untuk menambah / menghapus karakter.

Jika Anda menggunakan storyboard, cukup tetapkan kelas yang baru dibuat ke kolom teks atau jika Anda membuat kolom teks secara terprogram:

var basicTextField = TextFieldBasic()
basic = basicTextField(frame: CGRectMake(10, 100, 100,35))
basic.backgroundColor = UIColor.redColor()
self.view.addSubview(basic)

basic.becomeFirstResponder()

0
override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool 
{
    NSOperationQueue .mainQueue().addOperationWithBlock({ () -> Void in   

        [UIMenuController .sharedMenuController() .setMenuVisible(false, animated: true)]

    })
    return super.canPerformAction(action, withSender: sender)}

0

Cepat 3

Untuk melakukan ini, Anda perlu membuat subclass UITextView Anda dan menggunakan metode ini.

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if (action == #selector(copy(_:))) {
            return false
        }

        if (action == #selector(cut(_:))) {
            return false
        }

        if (action == #selector(paste(_:))) {
            return false
        }

        return super.canPerformAction(action, withSender: sender)
    }

0

UITextView memiliki dua properti yang akan melakukan apa yang Anda butuhkan: isSelectable dan isEditable .

Setting isEditable to false Anda akan menghindari pengguna untuk mengedit teks dan pengaturan isSelectable to false Anda akan menghindari pengguna untuk memilih teks di dalam textView Anda sehingga ini akan mencegah menu tindakan ditampilkan.


0

Silakan temukan kode contoh untuk referensi:

 override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(copy(_:)) || action == #selector(paste(_:)) || action == #selector(UIResponderStandardEditActions.paste(_:)) ||
            action == #selector(replace(_:withText:)) ||
            action == #selector(UIResponderStandardEditActions.cut(_:)) ||
        action == #selector(UIResponderStandardEditActions.select(_:)) ||
        action == #selector(UIResponderStandardEditActions.selectAll(_:)) ||
        action == #selector(UIResponderStandardEditActions.delete(_:)) ||
        action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionLeftToRight(_:)) ||
        action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionRightToLeft(_:)) ||
        action == #selector(UIResponderStandardEditActions.toggleBoldface(_:)) ||
        action == #selector(UIResponderStandardEditActions.toggleItalics(_:)) ||
        action == #selector(UIResponderStandardEditActions.toggleUnderline(_:)) ||
        action == #selector(UIResponderStandardEditActions.increaseSize(_:)) ||
        action == #selector(UIResponderStandardEditActions.decreaseSize(_:))

       {
            return false
        }

        return true
    }

-1

Gunakan func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool }di tempat textFieldShouldBeginEditing.

class ViewController: UIViewController , UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        //Show date picker
        let datePicker = UIDatePicker()
        datePicker.datePickerMode = UIDatePickerMode.date
        textField.tag = 1
        textField.inputView = datePicker
    }

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        if textField.tag == 1 {
            textField.text = ""
            return false
        }

        return true
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if textField.tag == 1 {
            textField.text = ""
            return false
        }

        return true
    }
}

Buat kelas baru dengan nama StopPasteAction.swift

import UIKit

class StopPasteAction: UITextField {

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }
}

Tambahkan kelas kelas baru dengan Anda TextField saat ini

masukkan deskripsi gambar di sini

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.