2012-05-10 10 views
5

Estoy tratando de crear un widget de código PIN personalizado para Android como alternativa a simplemente usar un EditText con un atributo de entrada de tipo de contraseña. Lo que me gustaría mostrar es una fila de recuadros, y que cada recuadro se llene a medida que el usuario escribe su pin.Widget personalizado de entrada de código PIN de Android

que otro había hecho algo como esto, pero resultó ser un número fijo de EditText vistas y había una gran cantidad de código fea para el bombeo de enfoque como personajes fueron mecanografiados o eliminados. Este NO es el enfoque que quiero tomar; más bien, estoy diseñando el mío para tener longitud personalizable (fácil) y comportarme como vista individualizable (no tan fácil).

Mi concepto hasta ahora es algún tipo de híbrido entre un LinearLayout (para contener las "cajas") y un EditText (para almacenar la entrada del usuario).

Este es el código hasta ahora ...

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

Sobre esas anulaciones: onCheckIsTextEditor() debe devolver verdadero y onCreateInputConnection(EditorInfo outAttrs) debe devolver una nueva InputConnection objeto de interactuar con un InputMethod (un teclado), pero eso es todo lo saber.

¿Alguien sabe si estoy en el camino correcto? ¿Alguien ha trabajado anteriormente con InputConnection o ha creado sus propias vistas editables para orientar?

(Edit 1) Después de mirar esta un poco más, parece que debería subclase BaseInputConnection y suministrar una TextView o EditText como su objetivo:

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

Suponiendo que esta no almacenar el texto tal y como se escribe, Todavía necesito alguna forma de actualizar las vistas para reflejar el cambio de contenido ...

(Editar 2) Así que agregué esta vista personalizada a una pantalla para probar. Muestra el número de cuadros, y toda la vista es enfocable, pero el teclado nunca aparece. Sé que gana/pierde el foco porque los recuadros muestran el resaltado de manera apropiada y configuré un OnFocusChangedListener para escribir en logcat.

¿Qué hace que un teclado real aparezca cuando se enfoca una vista editable?

Respuesta

0

He hecho progresos considerables en esto y ya no necesito ayuda con InputConnection. En resumen, extiende BaseInputConnection y reemplaza getEditable() para devolver un Editable. En este caso, estoy devolviendo un TextView privado usado internamente por el PinCodeView. PinCodeView también anula varios métodos como onKey[foo]() y reenvía la llamada al interno TextView. El resto solo está utilizando un TextWatcher para actualizar uno de los ImageView s secundarios cada vez que el texto cambie.

Funciona muy bien. Todavía quedan algunos problemas menores para pulir, pero los abordaré como preguntas separadas y cierro esto aquí.

+5

Si se siente generoso, sería genial si este código se hiciera disponible en github. ¡Gracias por publicar! – saranicole

+0

Realmente me gustaría, pero está en uso en la aplicación de mi compañía, por lo que no sé si puedo liberar el código fuente para ello. Déjame verlo con mi gerente. – Karakuri

+0

¿Alguna actualización sobre cómo liberar esto en github o si alguien más hizo tal progreso? El código que se muestra aquí parece realmente prometedor y un buen punto de partida para otros, aunque realmente apreciaría el paquete total. Tal vez Android lo implemente eventualmente como otro tipo de campo :) –

1

Me parece bien. Algo que podría querer hacer es cuando un usuario escribe un carácter en un cuadro EditText, busque una referencia al siguiente cuadro Editar texto y haga un requestFocus() en él. Esto moverá la entrada de texto al siguiente cuadro. Muy simple.

+0

Este es el tipo de cosas que estoy tratando de evitar. El widget completo debe ser enfocable, no los cuadros individuales. – Karakuri

+0

Las cajas individuales deberán centrarse para escribir en ellas. Además, un EditText que esté enfocado tendrá una línea azul alrededor, que le mostrará al usuario que puede tomar entrada. Sin esa señal visual, el usuario no sabrá a dónde van sus personajes escritos. –

+0

Quizás esto no estaba claro, pero NO estoy usando una fila de EditTexts y NO quiero que cada cuadro sea individualmente enfocable. Como mencioné, he visto código para eso y es desordenado y feo y blech. Este enfoque está inflando ImageViews para los cuadros, y estos tendrán un selector dibujable como fondo y tendrán duplicadoParentState = "true" para que muestren un estado enfocado cuando el widget está enfocado. La clave es que el widget ENTERO obtiene el foco, no los cuadros individuales. – Karakuri

4

Parece que podría estar tratando de crear una iOS como la vista de entrada/widget.

Aquí hay un buen código de muestra que puede serle útil. Sin embargo, es de longitud fija, pero aún puede ser útil para algunas personas.

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

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

+0

Agradezco su opinión, y puede ser útil para otros, pero ya he resuelto una solución por mi cuenta. La mía es una 'Vista' personalizada que encapsula toda la fila de cuadros, interactúa con el teclado de Android y administra toda la lógica en sí misma. No requiere una actividad completa con un diseño completo de botones y vistas de texto. – Karakuri

+2

@Karakuri Dado que no ha proporcionado el código fuente ni las instrucciones detalladas, esta respuesta para la introducción del código PIN es más relevante para mí. –

2

Sé que esto ya ha sido contestada, pero desde su implementación no es compartida he encontrado una biblioteca de código abierto similar. Se ve bien y para todos los que deambular puede darle tratar

https://github.com/Philio/PinEntryView

Cuestiones relacionadas