Nasconde il cursore di un UITextField


137

Sto usando a UITextFieldcon a UIPickerViewper suo inputView, in modo che quando l'utente tocca il campo di testo, viene chiamato un selettore per loro di selezionare un'opzione.

Quasi tutto funziona, ma ho un problema: il cursore lampeggia ancora nel campo di testo quando è attivo, il che è brutto e inappropriato, dal momento che l'utente non deve digitare nel campo e non è presentato con una tastiera. So che potrei hackily risolvere questo problema impostando editingper NOil campo di testo e il monitoraggio tocchi su di esso, o sostituendolo con un pulsante personalizzato in stile, e chiamando il selettore tramite codice. Tuttavia, desidero utilizzare i UITextFieldDelegatemetodi per la gestione di tutti gli eventi nel campo di testo e gli hack come la sostituzione del campo di testo con un pulsante non consentono questo approccio.

Come posso semplicemente nascondere il cursore sul UITextFieldinvece?

Risposte:


277

Sottoclasse semplicemente UITextField e sovrascrivi caretRectForPosition

- (CGRect)caretRectForPosition:(UITextPosition *)position
{
    return CGRectZero;
}

2
Bellissimo! Funziona come un incanto per me.
Joe Strout,

1
@Joseph Chiu Funziona benissimo. Ma non con iOS 4.3. Potresti aiutarmi con questo?
Dinesh Raja,

l'approccio più pulito e più breve che merita un doppio voto =)
Ilker Baltaci

1
Solo una nota. Nella mia sottoclasse ho aggiunto un bool hideCaret quindi in questa sostituzione Se è vero -> return CGRectZero else restituisce il risultato di super.
WCByrne,

6
Basta essere consapevoli del fatto che gli utenti con una tastiera esterna possono modificare il valore del campo di testo anche se il cursore è nascosto e si utilizza una vista di selezione.
Segna il

156

A partire da iOS 7 ora puoi semplicemente impostare tintColor = [UIColor clearColor]il textField e il cursore scomparirà.


1
Funziona al momento, tuttavia sconsiglio di utilizzarlo poiché potrebbe cambiare in futuro. Piuttosto optare per la caretRectForPosition:soluzione di sostituzione.
lipka,

@lipka Vero, probabilmente è un modo migliore.
Jamone,

2
Abbastanza buono per ora. A volte hai solo bisogno di una soluzione rapida.
GoldenJoe,

Questa è di gran lunga la soluzione più semplice!
Jay Q.

1
Questa risposta dovrebbe essere approvata per iOS 7+
tryp

95

Puoi semplicemente cancellare il colorColor del campo di testo

self.textField.tintColor = [UIColor clearColor];

Swift 3.0

self.textField.tintColor = .clear

inserisci qui la descrizione dell'immagine


La migliore risposta più semplice.
Nik Kov,

2
Come accennato in precedenza, la cancellazione del colore della tinta non impedisce agli utenti con tastiere esterne (iPad Pro) di modificare il testo.
Michael Long,

@MichaelLong non si tratta di impedire all'utente di modificare il testo, è solo una scelta di stile.
JRam13

21

Potresti anche voler impedire all'utente di selezionare, copiare o incollare qualsiasi testo in modo che l'unico input di testo provenga dalla vista di selezione.

- (CGRect) caretRectForPosition:(UITextPosition*) position
{
    return CGRectZero;
}

- (NSArray *)selectionRectsForRange:(UITextRange *)range
{
    return nil;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(copy:) || action == @selector(selectAll:) || action == @selector(paste:))
    {
        returnNO;
    }

    return [super canPerformAction:action withSender:sender];
}

http://b2cloud.com.au/tutorial/disabling-the-caret-and-text-entry-in-uitextfields/


15

Controlla la proprietà selectedTextRange del protocollo UITextInput , a cui la classe è UITextField conforme. Pochi! Questa è una lezione di programmazione orientata agli oggetti proprio lì.

Nascondi cursore

Per nascondere il cursore, azzera l'intervallo di testo selezionato del campo di testo.

textField.selectedTextRange = nil; // hides caret

Scopri il cursore

Ecco due modi per scoprire il cursore.

  1. Imposta l'intervallo di testo selezionato del campo di testo alla fine del documento.

    UITextPosition *end = textField.endOfDocument;
    textField.selectedTextRange = [textField textRangeFromPosition:end
                                                        toPosition:end];
  2. Per mantenere il punto di inserimento nello stesso punto, innanzitutto, memorizzare l'intervallo di testo selezionato del campo di testo in una variabile di istanza.

    _textFieldSelectedTextRange = textField.selectedTextRange;
    textField.selectedTextRange = nil; // hides caret

    Quindi, quando si desidera scoprire il cursore, semplicemente impostare l'intervallo di testo selezionato del campo di testo su quello che era originariamente:

    textField.selectedTextRange     = _textFieldSelectedTextRange;
    _textFieldLastSelectedTextRange = nil;

3
Questa particolare soluzione non ha funzionato per la mia implementazione. Il cursore lampeggia ancora.
Art Geigel,

Bene, quindi, forse dovresti presentare un bug su bugreport.apple.com perché i documenti iOS dicono: "Se l'intervallo di testo ha una lunghezza, indica il testo attualmente selezionato. Se ha lunghezza zero, indica il punto di inserimento (inserimento punto). Se l'oggetto dell'intervallo di testo è zero, indica che non esiste alcuna selezione corrente. "
ma11hew28,

4
Non mi interessa abbastanza per presentare un rapporto. Se gli altri usano la tua "soluzione" e non la vedono funzionare, volevo che sapessero che non sono soli.
Art Geigel,

Nonostante i commenti di @ ArtGeigel, questo funziona perfettamente per me. Tuttavia, preferisco in qualche modo la soluzione che prevede l'override caretRectForPosition. È più esplicito ciò che sta facendo e i documenti che hai citato non chiariscono quale dovrebbe essere il comportamento del cursore quando non c'è "nessuna selezione corrente". Se l'affermazione di @ArtGeigel secondo cui questo non funziona fosse corretta (cosa che non lo è, almeno per quanto posso vedere) non sarebbe chiaro che si trattasse di un bug.
Mark Amery,

Neanche ha funzionato per me. Caret è ancora lì e lampeggia.
CW0007007,

11

Risposta fornita dal PO, copiata dall'organismo delle domande per aiutare a ripulire la coda sempre crescente di domande senza risposta.

Ho trovato un'altra soluzione: sottoclasse UIButtone sovrascrivere questi metodi

- (UIView *)inputView {
    return inputView_;
}

- (void)setInputView:(UIView *)anInputView {
    if (inputView_ != anInputView) {
        [inputView_ release];
        inputView_ = [anInputView retain];
    }
}

- (BOOL)canBecomeFirstResponder {
    return YES;
}

Ora il pulsante, come a UIResponder, ha un comportamento simile a quello UITextFielde un'implementazione piuttosto semplice.


5
Questa non è davvero un'ottima soluzione. Check out questa risposta qui sotto: stackoverflow.com/a/13660503/1103584
DiscDev

2
Perché questa non è un'ottima soluzione? Raggiunge l'effetto desiderato e fornisce anche funzionalità a una classe che in precedenza non lo aveva. Non è nemmeno un trucco. Penso che sia davvero bello. Quindi cosa c'è che non va?
BreadicalMD,

2
@BreadicalMD Il problema più grande che posso vedere è che non puoi usarlo UITextFieldDelegatecon questo per gestire gli eventi di modifica di inizio e fine. Invece - a meno che non ci sia un modo per gestire quegli eventi che non conosco - dovrai sovrascrivere becomeFirstRespondere resignFirstRespondernella sottoclasse dei pulsanti, e possibilmente creare il tuo protocollo delegato, aggiungere una delegateproprietà e chiamare il delegato dal suddetto metodi. Tutto questo è molto più lavoro che semplicemente ignorare caretRectForPositionin una UITextFieldsottoclasse.
Mark Amery,

1
@BreadicalMD Detto questo, nonostante la risposta di Joseph Chiu sia superiore da qualsiasi punto di vista pratico, sono ancora d'accordo con te sul fatto che sia piuttosto sexy. Non avevo mai esaminato attentamente il UIResponderriferimento alla classe prima e non avevo idea che fosse possibile un trucco come questo.
Mark Amery,

In ritardo per la festa, ma penso che questa sia un'ottima soluzione e sembra molto più appropriato e meno un hack che usare un UITextFielde nascondere il cursore, che è fondamentalmente un hack poiché allora stiamo usando il campo di testo come etichetta mentre non utilizzare nessuna delle funzionalità di UITextField.
Rupert,

7

Swift 5 versione del post di Net

  override func caretRect(for position: UITextPosition) -> CGRect {
    return .zero
  }
  
  override func selectionRects(for range: UITextRange) -> [UITextSelectionRect] {
    return []
  }
  
  override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
  }

Nel mio caso ha funzionato. Aggiunta una sottoclasse di UITextField con questi metodi usando Swift 4. Grazie!
J. Fdez,

3

imposta tintColor su Cancella colore

textfield.tintColor = [UIColor clearColor];

e puoi anche impostare dal builder dell'interfaccia


2
Hai appena copiato una risposta di oltre 2 anni fa.
Ashley Mills,

1
scusa amico mio, ma non ho copiato nulla.
Ahmad Al-Attal,

4
È interessante, "amico mio". La tua risposta è molto simile alla risposta di @ oldman del 1 maggio 15. Puoi dirmi come è diversa la tua?
Ashley Mills,

1
Come accennato in precedenza, la cancellazione del colore della tinta non impedisce agli utenti con tastiere esterne (iPad Pro) di modificare il testo.
Michael Long,

Gli utenti professionisti possono fare quello che vogliono. Sono dei professionisti: sanno cosa stanno facendo; ^)
Anton Tropashko,

2

Se vuoi nascondere il cursore, puoi facilmente usarlo! Ha funzionato per me ..

[[textField valueForKey:@"textInputTraits"] setValue:[UIColor clearColor] forKey:@"insertionPointColor"]

3
Questo non è documentato, per quanto ne so. È possibile che l'utilizzo di questa opzione venga rifiutata dalla tua app per la chiamata di API private se la invii all'app store, anche se non conosco alcun invio che la utilizzi per testare tale speculazione in un modo o nell'altro. È un peccato, perché sarebbe bello poter risolvere questo problema senza sottoclasse e questa risposta lo consente.
Mark Amery,

1

Risposta fornita dal PO, copiata dall'organismo delle domande per aiutare a ripulire la coda sempre crescente di domande senza risposta.

Penso di avere la soluzione corretta ma se può essere migliorato sarà il benvenuto :) Bene, ho creato una sottoclasse di UITextField e ho ignorato il metodo che restituisce il CGRect per i limiti

-(CGRect)textRectForBounds:(CGRect)bounds {
    return CGRectZero;
}

Il problema? Il testo non viene visualizzato perché il rettangolo è zero. Ma ho aggiunto un UILabel come sottoview del controllo e ho ignorato il metodo setText, quindi, quando inseriamo un testo come al solito, il campo di testo è zero ed è l'etichetta che mostra il testo

- (void)setText:(NSString *)aText {
    [super setText:nil];

    if (aText == nil) {
        textLabel_.text = nil;
    }

    if (![aText isEqualToString:@""]) {
        textLabel_.text = aText;
    }
}

Con questo la cosa funziona come previsto. Conosci un modo per migliorarlo?


Questa risposta è praticamente senza valore ora dato che l'approccio alternativo di Joseph Chiu è molto simile ma molto più semplice. Posso suggerire di cancellarlo?
Mark Amery,

1

Per disabilitare sia il cursore che il menu, utilizzo la sottoclasse con questi 2 metodi:

- (CGRect)caretRectForPosition:(UITextPosition *)position {
    return CGRectZero;
}

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

    return NO;
}

0

Ho semplicemente una sottoclasse UITextFielde ho la precedenza layoutSubviewscome segue:

- (void)layoutSubviews
{
    [super layoutSubviews];
    for (UIView *v in self.subviews)
    {
        if ([[[v class] description] rangeOfString:@"UITextSelectionView"].location != NSNotFound)
        {
            v.hidden = YES;
        }
    }
}

È un trucco sporco e potrebbe non riuscire in futuro (a quel punto il cursore sarà di nuovo visibile - la tua app non si arresta in modo anomalo), ma funziona.


-1

È possibile aggiungere una BOOL cursorlessproprietà a UITextFieldin una categoria tramite oggetti associati.

@interface UITextField (Cursorless)

@property (nonatomic, assign) BOOL cursorless;

@end

Quindi utilizzare il metodo swizzling per swizzle caretRectForPosition:con un metodo che passa da CGRectZeroe al suo valore predefinito usando cursorless.

Questo porta a una semplice interfaccia tramite una categoria drop-in. Questo è dimostrato nei seguenti file.

Inseriscili e ottieni il vantaggio di questa semplice interfaccia

UITextFieldcategoria: https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCursorless.h https://github.com/rexmas/RexDK/blob/master/RexDK/UI/UITextField%2BRXCursorless .m

Metodo Swizzling: https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject%2BRXRuntimeAdditions.h https://github.com/rexmas/RexDK/blob/master/RexDK/Foundation/NSObject% 2BRXRuntimeAdditions.m


una pessima soluzione su tanti livelli! per cominciare: non sovrascrivere mai i metodi nelle categorie. Evita il metodo Swizziling a meno che tu non ne abbia davvero bisogno (altri hanno escogitato buone soluzioni a questa domanda). Rende il tuo codice molto più complicato.
EsbenB,

Se davvero guardassi il codice, ti accorgeresti che nessun metodo è sovrascritto nella categoria e lo swizzling del metodo è implementato correttamente. Uso questa implementazione da anni senza fallo.
Fantastico-

Spiega inoltre cosa è complicato aggiungere una base di codice isolata di ~ 150 righe per risolvere in modo permanente un problema ricorrente? Non solo questo NON complicherà la tua base di codice, ma fornirà l'interfaccia più semplice possibile; un singolo booleano per dettare la funzionalità.
Fantastico-

dai un'occhiata a questa eccellente discussione sul metodo che sfrigola stackoverflow.com/questions/5339276/… Soprattutto sul debug. Lo scorrimento del metodo è una funzionalità straordinaria, ma IMHO dovrebbe essere usato solo quando necessario. Questo problema è facile da risolvere usando uno dei suggerimenti forniti qui e fornirà codice più facile da mantenere e leggere per altri programmatori.
EsbenB,

L'ho letto prima e ho seguito tutte le linee guida delineate nella mia implementazione per la correttezza. Probabilmente, questo è un solido esempio di quando vince il metodo swizzling. È un caso isolato, ma comune, in cui le librerie di base non riescono a implementare una funzionalità ampiamente necessaria su piattaforme in modo semplice. Gli altri esempi suggeriti non definiscono semanticamente un campo di testo senza cursore, ma lo eseguono solo attraverso l'offuscamento della cornice del cursore o del suo colore. Per un nuovo programmatore, questa interfaccia è la più facile da leggere e fa esattamente ciò che ci si aspetta da essa.
Fantastico-
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.