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.

Aishwarya
sumber
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

rpetrich.dll
sumber
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 ...

iCoder
sumber
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 ... :-)

Damien Debin
sumber
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

Saraiva Alcides
sumber
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)
    }

}
Devin Pitcher
sumber
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;
Luke Redpath
sumber
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;
}
haiLong
sumber
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).

Adam Wallner
sumber
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;    
}
GL777
sumber
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.

Epaga
sumber
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.

rn3sto
sumber
4

Subclass UITextView - swift 4.0

     override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }
Manee ios
sumber
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
}
Jayesh Thanki
sumber
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

Hari Kunwar
sumber
3

Ini berhasil untuk saya. Pastikan Anda memanggil resignFirstResponder di textView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
  [self.textView resignFirstResponder];
  return NO;
}
verma
sumber
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];
    }
}
Thibaud David
sumber
2

Untuk Swift 3 , ini diubah menjadi:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
}
Andrey Gordeev
sumber
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
Khuong
sumber
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.

Bill the Lizard
sumber
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.
Suragch
sumber
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)")

    }
Sam Bing
sumber
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];
    }
Sivrish Thangamani
sumber
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
pengguna2091319
sumber
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.

RhodanV5500
sumber
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()
Krivvenz
sumber
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)}
Nirav Ghori
sumber
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)
    }
Zaldy
sumber
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.

L. Davì
sumber
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
    }
Sameen Ahmad
sumber
-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

anson
sumber