UITextViewでコピー、切り取り、選択、すべて選択を無効にする方法


110

UITextView私は、画面を下に押したときのコピー、切り取り、選択、選択すべての機能はデフォルトで表示されます。しかし、私のプロジェクトでUITextFieldは、これは読み取り専用です。この機能は必要ありません。この機能を無効にする方法を教えてください。


3
place [UIMenuController sharedMenuController] .menuVisible = NO; in-(BOOL)canPerformAction:(SEL)action withSender:(id)senderメソッド。
ravoorinandan

回答:


108

ペーストボード操作を無効にする最も簡単な方法は、許可したくないアクションに対して返すメソッドをUITextViewオーバーライドするサブクラスを作成することです。canPerformAction:withSender:NO

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

UIResponderも参照してください


1
@rpetrichm、私はあなたに解決策を使用しました、コピー/貼り付け/カット/選択/ selectAllオプションは無効になっていますが、まだ置換... | BIU |オプションを定義しています。その完全なメニューを無効にしたいと思います。
Ameet Dhas 2014年

3
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; }-すべてのオプションをブロックする
Islam Q.

これはすばらしいことですが、UISearchBarでこれを行う方法がわかりません。内部にテキストフィールドがあり、UISearchBarのサブクラスのメソッドを上書きできると思ったので、残念ながら機能しません。このためのアイデアはありますか?
borchero

多くのコントロールがあります。1つのコントロールだけにコピーと貼り付けを許可する方法
ガウチョ

これはUITextViewでは機能しませんが、このソリューションがSOの多くの場所で提案されているのを見ました。誰かがこれを行う方法を理解しましたか?
Pigpocket 2018年

67

UITextViewをサブクラス化し、canBecomeFirstResponderを上書きします。

- (BOOL)canBecomeFirstResponder {
    return NO;
}

これは編集不可のUITextViewにのみ適用されることに注意してください!編集可能なものでテストしていません...


私が考えるreturn NO;- (BOOL)canPerformAction:(SEL)action withSender:(id)sender方法より良いオプションです。
Islam Q.

29

すべて UITextViewのアプリケーションで切り取り/コピー/貼り付けを無効にする場合は、次のようにカテゴリを使用できます。

@implementation UITextView (DisableCopyPaste)

- (BOOL)canBecomeFirstResponder
{
    return NO;
}

@end

それはサブクラス化を保存します... :-)


3
また、これを/にのみ配置して、この動作が必要な場所に置くこともできます。
markus_p

4
これは副作用としてのみ機能し、UITextViewたとえば編集可能でタッチしたときにが期待どおりに動作するのを防ぎます。オーバーライドすることはたくさんありますcanPerformAction:withSender:。それがプロトコルの目的です。
jdc 2013年

16
カテゴリを使用してメソッドを安全にオーバーライドすることはできません。これは未定義の動作です。メソッドを安全にオーバーライドするには、サブクラス化する必要があります。
Rob Napier

2
注:これは、アプリケーションのすべてのUITextViewsに適用されます。ほとんどの場合、理想的ではありません。
bbrame 2013

2
また、Apple はこれに対して助言することに注意してください。「カテゴリで宣言されたメソッドの名前が元のクラスのメソッドと同じか、同じクラス(またはスーパークラス)の別のカテゴリのメソッドと同じである場合、動作は実行時にどのメソッド実装が使用されるかについては定義されていません... [および]カテゴリを使用してメソッドを標準のCocoaまたはCocoa Touchクラスに追加するときに問題が発生する可能性があります。
ロブ

29

これは私にとって最高の作業ソリューションでした:

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

から:https : //stackoverflow.com/a/5704584/1293949


3
ここはサブクラス化されていません。
Martin Reichl、2013年

7
私はここでダクトテープと梱包ワイヤーのアプローチが大好きです。私はもう一度あなたに+1できたらいいのに:)代わりに、ここに金色の星があります:i.imgur.com/EXLFt1Z.jpg
jdc

22

@rpetrichの回答がうまくいきました。誰かが時間を節約できるように、拡張コードを投稿しています。

私の場合、ポップアップはまったく必要ありませんが、UITextFieldがファーストレスポンダーになることができるようにしたいです。

残念ながら、テキストフィールドを長押しすると拡大鏡ポップアップが表示されます。

@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

スウィフト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
このための迅速なバージョンも投稿してください。ありがとうございました。
Salman Khakwani

@pinch:tnx。iOS 12.1.3ではまだ水を保持しています。
YvesLeBorg

20

UITextViewをスクロールする必要がない場合、サブクラス化を含まない最も簡単なソリューションは、テキストビューのユーザー操作を無効にすることです。

textField.userInteractionEnabled = NO;

2
これにより、テキストビューにあるリンクなどをタップする必要がなくなります。これは、選択/コピー/貼り付けを非表示にするのに適したソリューションではなく、ある程度の対話を有効にしておくことに注意してください。
barfoon

3
まあ、それは明白だと思っただろう。
ルークレッドパス2012

ゲームの画像のラベルとしてテキストフィールドを使用しています。拡大鏡を表示したくないので、テキストをコピーする理由はありません。これは私にとってはうまくいきます。UIWebViewでスタイル付きテキストを使用していますが、同じ行でも同様に機能します。
JScarry 2013

15

最も簡単な方法は、canPerformAction:withSenderをオーバーライドするUITextViewのサブクラスを作成することです。

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

これは、テキストを入力して他に何も入力できないようにするための最良のソリューションであり、テキストフィールドをタップしても「代行受信」されなくなります。これは、OPが望んだことなどを行います。
hlfcoding

13

iOS 7のcanPerformActionでNOを返すと、次のような多くのエラーが発生します。

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

私の解決策は次のとおりです:

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

トリックは、メインキューの次のサイクルで(表示された直後に)メニューコントローラを非表示にすることです。


すごくいい。唯一の問題は、2つのtextviewsと1つのtextFieldがあり、textViewフィールドのみのコピーと貼り付けを避けたいことです。canPerformActionを呼び出したユーザーを識別する方法 送信者変数はUIMenuControllerです
Gaucho

1
UITextField(またはUITextView)のサブクラスで機能します。作成したサブクラスを使用しない場合、効果はありません。たとえば、TextFieldWithoutCopyPasteを作成し、コピーペースト機能を使用したくない場所でそれを使用しました。
Adam Wallner、2015年

はい、そうです。しかし、私の場合、キーボードが表示されているときにウィンドウをアニメーション化するために、textViewにはcanPerformActionを使用するためのサブクラスが必要であり、textFieldにはtextFieldDidBeginEditingを使用するためのサブクラスが必要です。アニメーションはキーボードでウィンドウを移動します。このメソッドを使用して、キーボードがtextFieldを覆うのを回避します。
ガウチョ

10

これは、UITextViewの選択/コピー/貼り付けメニュー全体を無効にする最も簡単な方法です。

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

UITextFieldでも機能します。共有いただきありがとうございます。
Gaurav Srivastava

1
上記のコードを使用していますが、メニューを無効にする方法を教えてください。
Bittoo 2016年

4

iOS 7以降、UITextViewにプロパティがあります:

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

これにより、ビューでテキストを選択できなくなります。私にとってはうまくいきます。


4

あなたがキーボードを交換するために探している場合は、のは言わせUIPickerようにinputView(もちろんとして、ツールバーのとinputAccesotyView)、その後、この回避策のかもしれないのヘルプ...

  • 実装する textFieldShouldBeginEditing:
  • 内入れ textField.userInteractionEnabled = NO;
  • 次に、を閉じるときにUIPickerView、YESに設定します。

これを行うことで、をタップしてUITextFieldから選択するオプションを表示できます。UIPickerView現時点でUITextFieldは、実際にはどのタッチイベントにも反応しません(これには、切り取り、コピー、貼り付けのための押し続けることが含まれます)。ただし、閉じるときに必ずYESに戻すUIPickerView必要がありますが、UIPickerView再度アクセスすることはできません。

失敗するのは、ユーザーがをタップして押し続けたときだけです。その場合、UITextView切り取りコピーと貼り付けが初めて表示されます。このため、常に入力を検証する必要があります。これは私が考えることができる最も簡単です。もう1つのオプションはUILabel、読み取り専用テキストにを使用することでしたが、の多くの優れた機能がありませんUITextView


4

サブクラスUITextView-swift 4.0

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

なんて変なの?それでもオプション「貼り付け」が表示されますが、押された場合は実行されません...
iOS Flow

4

のポップアップを無効にする場合はUITextField、このUITextFieldDelegateメソッドを切り替えてくださいisUserInteractionEnabled

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

3

これはストーリーボード(Xcode 6)で簡単に実行できます。属性インスペクターで編集可能と選択可能のチェックを外すだけです。テキストビューは引き続きスクロールできます。ここに画像の説明を入力してください


3

これでうまくいきました。textViewでresignFirstResponderを呼び出していることを確認してください

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

2

私はここでテキスト選択+拡大鏡を無効にし、有効なクリック可能なリンクを維持するための実用的な答えを提供しました

かなり長い間試した後、UILongPressGestureRecognizerのみがタッチ終了を遅らせることを許可するUITextViewサブクラスでaddGestureRecognizerをオーバーライドすることで、テキストの選択、拡大、データ検出(リンクをクリック可能など)を維持することに成功しました。

UIUnselectableTextView.m

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


2

これらのボックスをオフにすると、ストーリーボードでこれを修正できます。

ここに画像の説明を入力してください

または、次のようにプログラムで設定できます。

textView.selectable = false
textView.editable = false

1

私はそれをやった。私UITextViewでは、切り取り、コピー、選択などのオプションを非常に簡単に無効にしました。

私が置かれUIView、私が置かれていた同じ場所でUITextViewはなく、上self.view、コメントを追加しtouchDelegate、以下のような方法を:

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

    }
}

そしてそれは私のために働いた。ありがとうございました。


1

迅速

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

関連した

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にカスタムオプションを追加したいが既存の機能を無効にしたい場合は、Swift 3でこれを行う方法です

コピー、貼り付け、カット機能を無効にするには、サブクラスを作成し、以下をオーバーライドします。

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

ViewControllerで、CustomTextViewに以下を追加してオプションを追加します。

  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

このメソッドは、選択、すべて選択、貼り付けメニューを完全に無効にします。それでも他のアクションが発生する場合は、以下のようにそれをif条件に追加してください。

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

次のようなカテゴリを作成できます。

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
これはそれを解決する良い方法ではありません。まず、カテゴリに含まれるため、すべてに影響します。第2に、関連するオブジェクトをかなり簡単なタスクに使用すると、利益を得ることよりも、後でデバッグで問題が発生する可能性があります(何をしたかを忘れたときに、このように機能するのはなぜですか)。私の意見では、可能な限り回避することをお勧めします。プロジェクトの新しいプログラマがコードを見つけてデバッグし、理解するのを容易にしません。
Vive

0

サブクラス化UITextViewとオーバーライド- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizerは、不要なアクションを無効にするもう1つの可能性です。

gestureRecognizer-object のクラスを使用して、アクションを追加するかどうかを決定します。


0

(SWIFT)メニューオプションまたは拡大鏡のない基本的なテキストフィールドだけが必要な場合は、UITextFieldのサブクラスを作成して、gestureRecognizerShouldBeginにfalseを返します。

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

        return false
    }
}

これにより、テキストフィールドのすべてのタッチ機能がバイパスされますが、ポップアップキーボードを使用して文字を追加/削除できます。

ストーリーボードを使用している場合は、新しく作成したクラスをテキストフィールドに割り当てるか、プログラムでテキストフィールドを作成します。

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

スウィフト3

これを行うには、UITextViewをサブクラス化し、このメソッドを配置する必要があります。

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には、必要な処理を行う2つのプロパティがあります。isSelectableisEditableです。

isEditableをfalseに設定すると、ユーザーがテキストを編集できなくなり、isSelectableをfalseに設定すると、ユーザーがtextView内のテキストを選択できなくなり、アクションメニューが表示されなくなります。


0

参考のためにサンプルコードを見つけてください:

 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

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool }代わりに使用し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という名前の新しいクラスを作成します

import UIKit

class StopPasteAction: UITextField {

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

現在のTextFieldでクラスnew classを追加します

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.