UITextView'da Kopyala, Kes, Seç, Tümünü Seç devre dışı bırakma


110

UITextViewBireyin Kopyala, Kes, Seç, Tümünü Seç işlevselliği Ekranda bastırın varsayılan olarak gösterilir. Ama benim projemde UITextFieldsadece salt okunur. Bu işlevselliğe ihtiyacım yok. Lütfen bana bu özelliği nasıl devre dışı bırakacağımı söyle.


3
yer [UIMenuController sharedMenuController] .menuVisible = NO; in - (BOOL) canPerformAction: Gönderen: (id) gönderen yöntemiyle (SEL) eylem.
ravoorinandan

Yanıtlar:


108

Çalışma alanı işlemlerini devre dışı bırakmanın en kolay yolu , izin vermek istemediğiniz eylemler için geri dönmek UITextViewüzere canPerformAction:withSender:yöntemi geçersiz kılan bir alt sınıf oluşturmaktır NO:

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

Ayrıca UIResponder'a bakın


1
@rpetrichm, çözümünüzü kullandım, kopyala / yapıştır / kes / seç / seç Tüm seçenekler devre dışı ama hala geliyor Değiştir ... | BIU | Seçenekleri tanımla. Tam menüyü devre dışı bırakmak istiyorum.
Ameet Dhas

3
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; }- tüm seçenekleri engellemek için
İslam S.

Bu harika, ancak bunu UISearchBar için nasıl yapacağımı bilmiyorum - içinde bir metin alanı olduğu için UISearchBar'ın alt sınıfının yönteminin üzerine yazabileceğimi düşündüm ama bu maalesef işe yaramıyor. Bunun için herhangi bir fikir?
borchero

birçok kontrolüm var. sadece bir kontrolde kopyala yapıştırmaya nasıl izin verilir?
Gaucho

Bu, UITextView için çalışmıyor, ancak bu çözümün SO'da bir dizi yerde önerildiğini gördüm. Bunun nasıl yapılacağını çözen var mı?
Pigpocket

67

Subclass UITextGörüntüleyin ve üzerine yazın canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
    return NO;
}

Bunun yalnızca düzenlenemeyen UITextView'lar için geçerli olduğunu unutmayın! Düzenlenebilir olanlar üzerinde test etmedim ...


Bence return NO;üzerinde - (BOOL)canPerformAction:(SEL)action withSender:(id)senderyöntemle daha iyi bir seçenektir.
İslam S.

29

Tüm UITextView uygulamanızda kes / kopyala / yapıştır özelliğini devre dışı bırakmak istiyorsanız, aşağıdakileri içeren bir kategori kullanabilirsiniz :

@implementation UITextView (DisableCopyPaste)

- (BOOL)canBecomeFirstResponder
{
    return NO;
}

@end

Bir alt sınıflandırma kaydeder ... :-)


3
bunu sadece /, dosyanıza bu davranışa ihtiyaç duyduğunuz yere koyabilirsiniz.
markus_p

4
Bu yalnızca bir yan etki olarak çalışır ve UITextViewörneğin düzenlenebilir olduğunda ve dokunulduğunda beklendiği gibi davranmasını engeller . Geçersiz kılmak çok şey canPerformAction:withSender:; protokol bunun için.
jdc

16
Bir kategori kullanarak bir yöntemi güvenle geçersiz kılamazsınız. Bu tanımlanmamış bir davranıştır. Bir yöntemi güvenle geçersiz kılmak için alt sınıfa girmelisiniz.
Rob Napier

2
Not: Bu, uygulamanızdaki tüm UITextViews için geçerli olacaktır. Çoğu zaman ideal değil.
bbrame

2
Ayrıca Apple'ın buna karşı tavsiyede bulunduğuna dikkat edin : "Bir kategoride bildirilen bir yöntemin adı orijinal sınıftaki bir yöntemle veya aynı sınıftaki (veya hatta bir üst sınıf) başka bir kategorideki bir yöntemle aynıysa, davranış çalışma zamanında hangi yöntem uygulamasının kullanıldığına dair tanımsız ... [ve], standart Cocoa veya Cocoa Touch sınıflarına yöntemler eklemek için kategorileri kullanırken sorunlara neden olabilir. "
Rob

29

Bu benim için en iyi çalışan çözümdü:

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

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


3
güzel bir, burada alt sınıf yok!
Martin Reichl

7
Buradaki koli bandı ve balya teli yaklaşımını seviyorum. Keşke sizi tekrar + 1'leyebilseydim :) Bunun yerine, işte bir altın yıldız: i.imgur.com/EXLFt1Z.jpg
jdc

22

@rpetrich cevabı benim için çalıştı. Birisine biraz zaman kazandırması ihtimaline karşı genişletilmiş kodu gönderiyorum.

Benim durumumda herhangi bir açılır pencere istemiyorum, ancak UITextField'ın ilk yanıtlayıcı olmasını istiyorum.

Ne yazık ki, metin alanına dokunup basılı tuttuğunuzda hala büyüteç açılır penceresini görüyorsunuz.

@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

Swift 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
Lütfen bunun için hızlı bir sürüm gönderin. teşekkür ederim.
Salman Khakwani

@pinch: tnx. Hala iOS 12.1.3'te suyu tutar.
YvesLeBorg

20

Kaydırmak için UITextView'a ihtiyacınız yoksa, alt sınıflandırma içermeyen en basit çözüm, metin görünümü için kullanıcı etkileşimini devre dışı bırakmaktır:

textField.userInteractionEnabled = NO;

2
Bu, metin görünümündeyse bağlantılara vb. Dokunmayı ortadan kaldırır. Bunun seç / kopyala / yapıştır'ı gizlemek istemesi için iyi bir çözüm olmadığı, ancak aynı zamanda bazı etkileşim düzeylerini etkin tuttuğuna dikkat edilmelidir.
barfoon

3
Bunun açık olacağını düşünürdüm.
Luke Redpath

Metin alanlarını bir oyundaki resimler için etiket olarak kullanıyorum ve büyütecin görünmesini istemiyorum ve metni kopyalamak için bir neden yok. Bu benim için harika çalışıyor. Bir UIWebView'da stilli metin kullanıyorum ve aynı satır orada da çalışıyor.
JScarry

15

En kolay yol, canPerformAction: withSender'ı geçersiz kılan bir UITextView alt sınıfı oluşturmaktır:

- (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;
}

Bu, başka hiçbir şey yazmadan metin yazabilmek için en iyi çözümdür ve metin alanına dokunmaların artık "yakalanmamasına" izin verir. Bu, OP'nin istediğini ve daha fazlasını yapıyor.
hlfcoding

13

İOS 7'de canPerformAction'da NO değerini döndürdüğümde, bunun gibi birçok hata alacağım:

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

Benim çözümüm şudur:

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

İşin püf noktası, ana kuyruktaki bir sonraki döngüde menü denetleyicisini gizlemektir (görüntülendikten hemen sonra).


gerçekten hoş. tek sorun, 2 metin görünümüm ve bir textField'ım olması ve yalnızca textView alanlarında kopyalayıp yapıştırmaktan kaçınmak istiyorum. canPerformAction'ı kim çağırdı? gönderen değişkeni UIMenuController'dir
Gaucho

1
UITextField (veya UITextView) alt sınıfında çalışır. Yaptığınız alt sınıfı kullanmazsanız, herhangi bir etkisi olmayacaktır. Örneğin, bir TextFieldWithoutCopyPaste oluşturdum ve kopyala yapıştır işlevine sahip olmak istemediğim yerde bunu kullandım.
Adam Wallner

tamam sen haklısın. Ancak benim durumumda, textView canPerformAction'ı kullanmak için alt sınıfa ihtiyaç duyar ve textField, klavye gösterildiğinde pencereyi canlandırmak için textFieldDidBeginEditing'i kullanmak için alt sınıfa ihtiyaç duyar. animasyon, pencereyi klavye ile hareket ettirir. Klavyenin textField'ı kaplamasını önlemek için bu yöntemi kullanıyorum.
Gaucho

10

Bu, bir UITextView'daki Seç / Kopyala / Yapıştır Menüsünün tamamını devre dışı bırakmanın en kolay yoludur.

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

UITextField için de çalışıyor. Paylaşım için teşekkürler.
Gaurav Srivastava

1
Yukarıdaki kodu kullanıyorum hala menüyü alıyorum bunu nasıl devre dışı bırakacağım lütfen bana yardım edin.
Bittoo

4

İOS 7'den beri UITextView'da bir özellik vardır:

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

Bu, görünümün metin seçimlerine izin vermesini engeller. Benim için harika çalışıyor.


4

Eğer bir klavyeyi yerine arıyorsanız, diyelim UIPickerolarak inputView(bir kurs bir araç çubuğu ile inputAccesotyView), daha sonra bu geçici çözüm kudreti yardımı ...

  • uygulamak textFieldShouldBeginEditing:
  • içeriye koymak textField.userInteractionEnabled = NO;
  • Ardından kapatmak üzereyken UIPickerViewEVET olarak ayarlayın.

Bunu yaparak , şu anda herhangi bir dokunma olayına gerçekten tepki vermeyeceğiniz UITextFieldseçenekler arasından seçim yapabileceğiniz seçeneklere dokunabilir ve bunları gösterebilirsiniz (bu, kesme, kopyalama ve yapıştırma için dokunup basılı tutmayı içerir). Ancak, kapatırken tekrar EVET'e ayarlamayı hatırlamanız gerekir, ancak tekrar giriş yapamazsınız .UIPickerViewUITextFieldUIPickerViewUIPickerView

Başarısız olduğu tek an, kullanıcının simgesine dokunup basılı tutarak başlamasıdır UITextView, ardından ilk kez kes kopyalayıp yapıştırmayı görürsünüz. Bu nedenle girdilerinizi daima doğrulamalısınız. Bu aklıma gelen en kolay şey. Diğer seçenek, UILabelsalt okunur bir metin kullanmaktı, ancak birçok harika işlevi kaçırıyorsunuz UITextView.


4

Alt sınıf UITextView - hızlı 4.0

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

Ne kadar tuhaf? yine de "Yapıştır" seçeneğini gösteriyor, ancak basılırsa yapmayın ...
iOS Flow

4

Açılır pencereyi devre dışı bırakmak istiyorsanız , geçiş yapmak için UITextFieldbu UITextFieldDelegateyöntemi deneyin isUserInteractionEnabled.

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

3

Bu, film şeridinde (Xcode 6) kolayca yapılabilir. Attributes Inspector'da Düzenlenebilir ve Seçilebilir'in işaretini kaldırmanız yeterlidir. Yine de metin görünümünü kaydırabilirsiniz.görüntü açıklamasını buraya girin


3

Bu benim için çalıştı. TextView'da resignFirstResponder'ı aradığınızdan emin olun

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

2

Metin seçimini + büyüteci devre dışı bırakmak için burada çalışan bir yanıt verdim, etkin bağlantıları koruyarak yardımcı olur umuyoruz:

Oldukça uzun bir süre denedikten sonra, yalnızca UILongPressGestureRecognizer'ın dokunmayı geciktirmesine izin veren bir UITextView alt sınıfında addGestureRecognizer'ı geçersiz kılarak metin seçimini, büyütmeyi ve veri algılamayı (tıklanabilir bağlantılar vb.) Durdurmayı başardım:

UIUnselectableTextView.m

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

2

İçin Swift 3 o kadar değişti:

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

2

Bunu film şeridinizde şu kutuların işaretini kaldırarak düzeltebilirsiniz:

görüntü açıklamasını buraya girin

Veya programatik olarak şu şekilde ayarlayabilirsiniz:

textView.selectable = false
textView.editable = false

1

Ben yaptım Benim UITextViewüzerimde kes, kopyala, seç vb. Seçeneğini çok kolay devre dışı bıraktım.

A'yı yerleştirdiğim UIViewyere UITextViewama üzerine yerleştirdim ve aşağıdaki gibi self.viewbir touchDelegateyöntem ekledim :

(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;
        }

    }
}

ve benim için çalıştı. Teşekkür ederim.


1

hızlı

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

İlişkili

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

UITextView'unuza özel bir seçenek eklemek, ancak mevcut işlevleri devre dışı bırakmak istiyorsanız, bunu Swift 3'te şu şekilde yaparsınız :

Kopyalama, yapıştırma, kesme işlevini devre dışı bırakmak için bir alt sınıf oluşturun ve aşağıdakileri geçersiz kılın:

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

ViewController'da, CustomTextView'ınız seçeneklerinizi eklemek için aşağıdakileri ekleyin:

  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

Bu yöntem Seç, Tümünü Seç, Yapıştır menüsünü tamamen devre dışı bırakacaktır. Hala başka bir işlem görüyorsanız, bunu aşağıdaki gibi if koşuluna ekleyin.

- (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

Bunun gibi kategori oluşturabilirsiniz:

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
Bu, onu çözmenin iyi bir yolu değil. Öncelikle kategoride olduğu gibi her şeyi etkiler. İkinci olarak, ilişkili nesneleri oldukça kolay bir görev için kullanmak, daha sonra hata ayıklamayla (ne yaptığınızı unuttuğunuzda neden böyle çalışıyor) kar vermekten daha fazla sorun çıkarabilir. Benim görüşüme göre, mümkün olduğunda bundan kaçınmak iyidir. Projedeki yeni programcı tarafından kodun bulunmasını, hata ayıklamasını ve anlaşılmasını daha az kolaylaştırır.
Vive

0

Alt sınıflandırma UITextViewve geçersiz kılma - (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer, istenmeyen eylemleri devre dışı bırakmak için başka bir olasılıktır.

gestureRecognizerEylemin eklenip eklenmeyeceğine karar vermek için -nesne sınıfını kullanın .


0

(SWIFT) Menü seçeneklerinden veya büyüteçten hiçbirine sahip olmayan basit bir metin alanı istiyorsanız, JestRecognizerShouldBegin'e false döndüren bir UITextField alt sınıfı oluşturun:

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

        return false
    }
}

Bu, metin alanındaki tüm dokunma işlevlerini atlar ancak yine de karakter eklemek / kaldırmak için açılır klavyeyi kullanmanıza izin verir.

Film şeridi kullanıyorsanız, yeni oluşturulan sınıfı metin alanına atayın veya programatik olarak bir metin alanı oluşturuyorsanız:

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

Hızlı 3

Bunu yapmak için, UITextView'unuzu alt sınıflara ayırmanız ve bu yöntemi koymanız gerekir.

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 neye ihtiyacınız yapacak iki özelliği vardır isSelectable ve isEditable .

YANLıŞ olarak isEditable ayarlama Düzenlemeye kullanıcıya metin önlemek ve ayar isSelectable YANLıŞ olarak bu gösterilmesini işlem menüsüne önleyecektir böylece TextView'un içindeki metni seçmek için kullanıcı önleyecektir.


0

Lütfen referans için örnek kodu bulun:

 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

Kullanım func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool }yerine 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
    }
}

StopPasteAction.swift adıyla yeni bir sınıf oluşturun

import UIKit

class StopPasteAction: UITextField {

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

Sınıfı yeni sınıfı mevcut TextField ile ekleyin

görüntü açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.