Funkcje UITextView
Kopiuj, Wytnij, Wybierz, Zaznacz wszystko są wyświetlane domyślnie po naciśnięciu ekranu. Ale w moim projekcie UITextField
jest tylko do odczytu. Nie potrzebuję tej funkcjonalności. Powiedz mi, jak wyłączyć tę funkcję.
Funkcje UITextView
Kopiuj, Wytnij, Wybierz, Zaznacz wszystko są wyświetlane domyślnie po naciśnięciu ekranu. Ale w moim projekcie UITextField
jest tylko do odczytu. Nie potrzebuję tej funkcjonalności. Powiedz mi, jak wyłączyć tę funkcję.
Odpowiedzi:
Najłatwiejszym sposobem wyłączenia operacji wklejania jest utworzenie podklasy, UITextView
która przesłania canPerformAction:withSender:
metodę zwracania NO
działań, na które nie chcesz zezwolić:
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(paste:))
return NO;
return [super canPerformAction:action withSender:sender];
}
Zobacz także UIResponder
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; }
- zablokować wszystkie opcje
Podklasa UITextView i nadpisanie canBecomeFirstResponder:
- (BOOL)canBecomeFirstResponder {
return NO;
}
Zwróć uwagę, że dotyczy to tylko nieedytowalnych UITextViews! Nie testowałem tego na edytowalnych ...
return NO;
o - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
metodzie jest lepszym rozwiązaniem.
Jeśli chcesz wyłączyć wycinanie / kopiowanie / wklejanie we wszystkich UITextView
swoich aplikacjach, możesz użyć kategorii z:
@implementation UITextView (DisableCopyPaste)
- (BOOL)canBecomeFirstResponder
{
return NO;
}
@end
Zapisuje podklasę ... :-)
UITextView
zachowywaniu się zgodnie z oczekiwaniami, na przykład, gdy można go edytować i można go dotknąć. To dużo do przesłonięcia canPerformAction:withSender:
; do tego służy protokół.
To było dla mnie najlepsze działające rozwiązanie:
UIView *overlay = [[UIView alloc] init];
[overlay setFrame:CGRectMake(0, 0, myTextView.contentSize.width, myTextView.contentSize.height)];
[myTextView addSubview:overlay];
[overlay release];
@rpetrich answer zadziałało dla mnie. Wysyłam rozszerzony kod na wypadek, gdyby zaoszczędził komuś trochę czasu.
W moim przypadku nie chcę żadnego wyskakującego okienka, ale chcę, aby UITextField mógł zostać pierwszym respondentem.
Niestety, po dotknięciu i przytrzymaniu pola tekstowego nadal pojawia się wyskakujące okienko lupy.
@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
Szybki 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)
}
}
Jeśli nie potrzebujesz UITextView do przewijania, najprostszym rozwiązaniem, które nie obejmuje podklas, jest po prostu wyłączenie interakcji użytkownika dla widoku tekstu:
textField.userInteractionEnabled = NO;
Najłatwiejszym sposobem jest utworzenie podklasy UITextView, która przesłania 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;
}
Kiedy zwrócę NIE w canPerformAction na iOS 7, otrzymam wiele błędów takich jak ten:
<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.
Moje rozwiązanie jest następujące:
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
}];
return [super canPerformAction:action withSender:sender];
}
Sztuczka polega na tym, aby w kolejnym cyklu w głównej kolejce ukryć kontroler menu (tuż po jego wyświetleniu).
Jest to najłatwiejszy sposób na wyłączenie całego menu Wybierz / Kopiuj / Wklej w UITextView
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
[UIMenuController sharedMenuController].menuVisible = NO;
return NO;
}
Jeśli chcesz zastąpić klawiaturę, powiedzmy, UIPicker
jako inputView
(oczywiście z paskiem narzędzi jako inputAccesotyView
), to obejście może pomóc ...
textFieldShouldBeginEditing:
textField.userInteractionEnabled = NO;
UIPickerView
, ustaw go na TAK.W ten sposób będziesz mógł dotknąć UITextField
i wyświetlić opcje do wyboru UIPickerView
, w tym momencie UITextField
rzeczywiście nie zareagowałbyś na żadne zdarzenie dotykowe (obejmuje to dotknięcie i przytrzymanie do wycinania, kopiowania i wklejania). Musisz jednak pamiętać, aby ustawić go z powrotem na TAK podczas zamykania konta, UIPickerView
ale nie będziesz mieć dostępu do swojegoUIPickerView
ponownie.
Jedynym momentem, w którym to się nie powiedzie, jest to, że użytkownik zaczyna od dotknięcia i przytrzymania przycisku UITextView
, a następnie po raz pierwszy zobaczysz wycinanie, kopiowanie i wklejanie. Dlatego zawsze należy sprawdzać poprawność wprowadzonych danych. To najłatwiejsza rzecz, jaką przychodzi mi do głowy. Inną opcją było użycie UILabel
tekstu tylko do odczytu, ale brakuje Ci wielu wspaniałych funkcji z UITextView
.
Jeśli chcesz wyłączyć wyskakujące okienko, UITextField
wypróbuj tę UITextFieldDelegate
metodę, aby przełączyć isUserInteractionEnabled
.
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
textField.isUserInteractionEnabled = false
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
textField.isUserInteractionEnabled = true
return true
}
Podałem tutaj działającą odpowiedź , aby wyłączyć zaznaczanie tekstu + lupę, zachowując włączone klikalne linki. Mam nadzieję, że to pomoże:
Po dość długich próbach udało mi się zatrzymać zaznaczanie tekstu, powiększanie i utrzymywanie wykrywania danych (klikalne linki itp.), Zastępując addGestureRecognizer w podklasie UITextView, pozwalając tylko UILongPressGestureRecognizer opóźniać zakończenie dotyku:
UIUnselectableTextView.m
-(void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
if([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] && gestureRecognizer.delaysTouchesEnded)
{
[super addGestureRecognizer:gestureRecognizer];
}
}
W przypadku Swift 3 zmieniono na:
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
Zrobiłem to. Na moim UITextView
bardzo łatwo wyłączyłem opcję wycinania, kopiowania, zaznaczania itp.
Umieściłem UIView
w tym samym miejscu, w którym umieściłem UITextView
, ale na self.view
i dodałem touchDelegate
metodę w następujący sposób:
(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;
}
}
}
i to zadziałało dla mnie. Dziękuję Ci.
Szybki
textView.selectable = false // disable text selection (and thus copy/paste/etc)
Związane z
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.
Jeśli chcesz dodać niestandardową opcję do swojego UITextView, ale wyłączyć istniejące funkcje, oto jak to zrobić w Swift 3 :
Aby wyłączyć kopiowanie, wklejanie, wycinanie, utwórz podklasę i nadpisz następujące elementy:
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
W kontrolerze ViewController masz swój CustomTextView dodaj następujące elementy, aby dodać opcje:
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)")
}
Ta metoda całkowicie wyłączy menu Wybierz, Zaznacz wszystko, Wklej. Jeśli nadal otrzymujesz inną akcję, po prostu dodaj ją do warunku if, jak poniżej.
- (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];
}
Możesz po prostu utworzyć taką kategorię:
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
Podklasy UITextView
i nadpisywanie - (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
to kolejna możliwość wyłączenia niechcianych działań.
Użyj klasy obiektu gestureRecognizer
-object, aby zdecydować, czy akcja powinna zostać dodana, czy nie.
(SWIFT) Jeśli chcesz mieć tylko podstawowe pole tekstowe bez opcji menu ani szkła powiększającego, utwórz podklasę UITextField zwracającą false do gestRecognizerShouldBegin:
class TextFieldBasic: UITextField {
override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
return false
}
}
Spowoduje to pominięcie wszystkich funkcji dotykowych w polu tekstowym, ale nadal umożliwi używanie wyskakującej klawiatury do dodawania / usuwania znaków.
Jeśli używasz scenorysu, po prostu przypisz nowo utworzoną klasę do pola tekstowego lub jeśli programowo tworzysz pole tekstowe:
var basicTextField = TextFieldBasic()
basic = basicTextField(frame: CGRectMake(10, 100, 100,35))
basic.backgroundColor = UIColor.redColor()
self.view.addSubview(basic)
basic.becomeFirstResponder()
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)}
Szybki 3
Aby to zrobić, musisz utworzyć podklasę swojego UITextView i umieścić tę metodę.
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)
}
UITextView ma dwie właściwości, które zrobią to, czego potrzebujesz: isSelectable i isEditable .
Ustawienie isEditable na false pozwoli uniknąć użytkownikowi edycji tekstu, a ustawienie isSelectable na false pozwoli uniknąć użytkownikowi wybierania tekstu w Twoim textView, co zapobiegnie wyświetlaniu menu akcji.
Proszę znaleźć przykładowy kod w celach informacyjnych:
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
}
Użyj func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool }
zamiast 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
}
}
Utwórz nową klasę o nazwie StopPasteAction.swift
import UIKit
class StopPasteAction: UITextField {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
}
Dodaj klasę nową klasę z bieżącym TextField