Widget de entrada de código PIN personalizado do Android

Eu estou tentando criar um widget de código PIN personalizado para android como uma alternativa para apenas usando umEditText com um atributo inputType de senha. O que eu gostaria de exibir é uma linha de caixas, e cada caixa deve ser preenchida quando o usuário digita o pin dele.

Alguém fez algo assim, mas acabou por ser um número fixo deEditText pontos de vista e havia um monte defeio código para troca de foco conforme os caracteres foram digitados ou excluídos. Esta não é a abordagem que quero seguir; em vez disso, estou projetando o meu para tercomprimento personalizável (fácil) e se comportar comovisão única focalizável (não tão fácil).

Meu conceito até agora é algum tipo de híbrido entre umLinearLayout (para segurar as "caixas") e umEditText (para armazenar a entrada do usuário).

Este é o código até agora ...

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

Sobre essas substituições:onCheckIsTextEditor () deve retornar true eonCreateInputConnection (EditorInfo outAttrs) deve retornar um novoInputConnection objeto para interagir com um InputMethod (um teclado), mas isso é tudo que eu sei.

Alguém sabe se estou no caminho certo? Alguém já trabalhou comInputConnection antes ou fizeram suas próprias visualizações editáveis ​​capazes de dar orientação?

(Edit 1) Depois de olhar para isso um pouco mais, parece que eu deveria subclassificar BaseInputConnection e fornecer umaTextView ouEditText como seu alvo:

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

Supondo que isso armazene o texto enquanto ele é digitado, ainda preciso de alguma maneira para atualizar as exibições para refletir a alteração de conteúdo ...

(Edit 2) Então, adicionei essa visualização personalizada a uma tela para teste. Ele mostra o número de caixas, e toda a visão é focável, mas o teclado nunca aparece. Eu sei que ganha / perde o foco porque as caixas mostram destaque de forma adequada e eu definir umOnFocusChangedListener para gravar no logcat.

O que faz um teclado real aparecer quando uma visualização editável fica em foco?

questionAnswers(4)

yourAnswerToTheQuestion