2012-05-10 16 views
5

Sto cercando di creare un widget codice PIN personalizzato per Android come alternativa all'utilizzo di un EditText con un attributo inputType password. Quello che mi piacerebbe mostrare è una fila di scatole, e ogni casella deve essere riempita mentre l'utente digita il suo pin.Widget inserimento codice PIN Android personalizzato

qualcun altro ha fatto qualcosa di simile, ma si è rivelato essere un numero fisso di EditText di vista e c'era un sacco di codice brutto per lo swapping messa a fuoco come i personaggi sono stati digitati o eliminati. Questo NON è l'approccio che voglio prendere; piuttosto, sto progettando il mio per avere la lunghezza personalizzabile (facile) e comportarsi come una vista singola messa a fuoco (non così facile).

Il mio concetto finora è una sorta di ibrido tra uno LinearLayout (per contenere le "caselle") e uno EditText (per memorizzare l'input dell'utente).

Questo è il codice finora ...

public class PinCodeView extends LinearLayout { 
    protected static final int MAX_PIN_LENGTH = 10; 
    protected static final int MIN_PIN_LENGTH = 1; 

    protected int pinLength; 
    protected EditText mText; 

    public PinCodeView(Context context, AttributeSet attrs) { 
     super(context, attrs); 

     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PinCodeView); 
     try { 
      pinLength = a.getInt(R.styleable.PinCodeView_pinLength, 0); 
     } finally { 
      a.recycle(); 
     } 

     pinLength = Math.min(pinLength, MAX_PIN_LENGTH); 
     pinLength = Math.max(pinLength, MIN_PIN_LENGTH); 

     setupViews(); 

     Log.d(TAG, "PinCodeView initialized with pinLength = " + pinLength); 
    } 

    private void setupViews() { 
     LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
       Context.LAYOUT_INFLATER_SERVICE); 
     for (int i = 0; i < pinLength; i++) { 
      // inflate an ImageView and add it 
      View child = inflater.inflate(R.layout.pin_box, null, false); 
      addView(child); 
     } 
    } 

    public CharSequence getText() { 
     // TODO return pin code text instead 
     return null; 
    } 

    public int length() { 
     // TODO return length of typed pin instead 
     return pinLength; 
    } 

    @Override 
    public boolean onCheckIsTextEditor() { 
     return true; 
    } 

    @Override 
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 
     // TODO return an InputConnection 
     return null; 
    } 
} 

di quelle sostituzioni: onCheckIsTextEditor() dovrebbe restituire vero e onCreateInputConnection(EditorInfo outAttrs) dovrebbe restituire un nuovo oggetto InputConnection per interagire con un InputMethod (una tastiera), ma questo è tutto quello che ho conoscere.

Qualcuno sa se sono sulla strada giusta? Qualcuno ha già lavorato con InputConnection prima o ha creato le proprie viste modificabili in grado di fornire una guida?

(Modifica 1) Dopo aver guardato questo un po ', sembra che io dovrei sottoclasse BaseInputConnection e fornire una TextView o EditText come il suo obiettivo:

@Override 
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 
     if (!onCheckIsTextEditor()) { 
      return null; 
     } 
     return new BaseInputConnection(mText, true); 
    } 

Supponendo che questo non memorizzare il testo in quanto viene digitato, Ho ancora bisogno di un modo per aggiornare le viste per riflettere la modifica del contenuto ...

(Modifica 2) Così ho aggiunto questa visualizzazione personalizzata a uno schermo per il test. Mostra il numero di caselle e l'intera vista è focalizzabile, ma la tastiera non si apre mai. So che guadagna/perde messa a fuoco perché le caselle mostrano l'evidenziazione in modo appropriato e ho impostato un OnFocusChangedListener per scrivere su logcat.

Che cosa fa apparire una tastiera reale quando una vista modificabile viene messa a fuoco?

risposta

0

Ho fatto notevoli progressi su questo e non ho più bisogno di aiuto con InputConnection. In breve, estendi BaseInputConnection e sostituisci getEditable() per restituire un modificabile. In questo caso, restituisco un privato TextView utilizzato internamente dal numero PinCodeView. PinCodeView sovrascrive anche diversi metodi come onKey[foo]() e inoltra la chiamata al numero interno TextView. Il resto è solo utilizzando un TextWatcher per aggiornare uno dei bambini ImageView s ogni volta che il testo cambia.

Funziona davvero bene. Ci sono ancora alcuni problemi minori da chiarire, ma li affronterò come domande separate e chiuderò qui.

+5

Se ti senti generoso sarebbe bello se questo codice fosse fatto disponibile su github. Grazie per la pubblicazione! – saranicole

+0

Mi piacerebbe molto, ma è in uso nell'app della mia azienda, quindi non so che posso rilasciare il codice sorgente per esso. Fammi controllare con il mio manager. – Karakuri

+0

Qualche aggiornamento sul rilascio di questo su github o se qualcun altro ha già fatto questo progresso? Il codice mostrato qui sembra davvero promettente e un buon punto di partenza per gli altri, anche se apprezzerei davvero il pacchetto completo. Forse Android lo implementerà come un altro tipo di campo :) –

1

Mi sembra ok. Qualcosa che potresti voler fare è quando un utente digita un personaggio in una casella EditText, trova un riferimento alla successiva casella EditText e fa un requestFocus() su di esso. Ciò sposterà la voce di testo nella casella successiva. Molto semplice.

+0

Questo è il genere di cosa che sto cercando di evitare. L'intero widget dovrebbe essere focalizzabile, non le singole caselle. – Karakuri

+0

Le singole caselle dovranno essere focalizzate per inserirle. Inoltre, un EditText che è a fuoco avrà una linea blu attorno ad esso, mostrando all'utente che può prendere input. Senza quel segnale visivo l'utente non saprà dove stanno andando i suoi personaggi digitati. –

+0

Forse non era chiaro, ma NON sto usando una riga di EditTexts e NON voglio che ciascuna casella sia focalizzabile individualmente. Come ho detto, ho visto il codice per questo ed è disordinato, brutto e blech. Questo approccio sta gonfiando ImageViews per le caselle e queste avranno un selettore selezionabile come sfondo e hanno duplicateParentState = "true" in modo che mostrino uno stato attivo quando il widget è focalizzato. Bu la chiave è che il widget INTERO ottiene il fuoco, non le singole caselle. – Karakuri

4

Sembra che si stia tentando di creare una vista/widget di inserimento dei pin di iOS.

Ecco un codice di esempio che potresti trovare utile. Tuttavia, è una lunghezza fissa, ma forse utile per alcune persone.

https://github.com/chinloong/Android-PinView

http://madeveloper.blogspot.com/2013/02/android-ios-like-pin-entrychallenge.html

+0

Apprezzo il tuo contributo e potrebbe essere utile per gli altri, ma ho già risolto una soluzione da solo. Il mio è un 'View' personalizzato che incapsula l'intera fila di scatole, interagisce con la tastiera Android e gestisce l'intera logica stessa. Non richiede un'intera attività con un intero layout di pulsanti e visualizzazioni di testo. – Karakuri

+2

@Karakuri Dato che non hai fornito il codice sorgente né istruzioni dettagliate, questa risposta per l'immissione del codice pin è più rilevante per me. –

2

So che questo è già stato risposto, ma dal momento che la sua attuazione non è condivisa ho trovato una libreria open source simile. Sembra buono e per tutti coloro che vagare può dare prova

https://github.com/Philio/PinEntryView