Пользовательский виджет ввода пин-кода Android

Я пытаюсь создать пользовательский виджет пин-кода для Android в качестве альтернативы просто использовать EditText с атрибутом ввода пароля типа. То, что я хотел бы отобразить, это ряд ящиков, и каждый из них должен быть заполнен, когда пользователь вводит свой пин-код.

Кто-то сделал что-то подобное, но оказалось, что это фиксированное число EditText просмотров и было много уродливого кода для смены фокуса при вводе или удалении символов. Это НЕ подход, который я хочу использовать; скорее я проектирую мой, чтобы иметь настраиваемую длину (легко) и вести себя как один фокусируемый вид (не так просто).

Моя концепция до сих пор является своего рода гибридом между LinearLayout (чтобы держать "коробки") и EditText (для хранения ввода пользователя).

Это код до сих пор...

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

Об этих переопределениях: onCheckIsTextEditor () должен возвращать true, а onCreateInputConnection(EditorInfo outAttrs) должен возвращать новый InputConnection объект для взаимодействия с InputMethod (клавиатура), но это все, что я знаю.

Кто-нибудь знает, нахожусь ли я на правильном пути? Кто-нибудь сделал работу с InputConnection раньше или сделали свои собственные редактируемые представления способными дать руководство?

(Правка 1) Посмотрев еще раз, мне кажется, что я должен создать подкласс BaseInputConnection и предоставить TextView или же EditText как его цель:

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

Предполагая, что это сохраняет текст в том виде, в котором он напечатан, мне все еще нужен какой-то способ обновить представления, чтобы отразить изменение содержимого...

(Изменить 2) Поэтому я добавил этот пользовательский вид на экран для тестирования. Он показывает количество блоков, и весь вид можно сфокусировать, но клавиатура никогда не всплывает. Я знаю, что он получает / теряет фокус, потому что поля показывают выделение соответствующим образом, и я установил OnFocusChangedListener написать в logcat.

Что заставляет настоящую клавиатуру появляться, когда редактируемый вид фокусируется?

4 ответа

Решение

Я добился значительного прогресса в этом и больше не нуждаюсь в помощи с InputConnection. Короче говоря, вы продлеваете BaseInputConnection и переопределить getEditable() вернуть редактируемый. В этом случае я возвращаю личное TextView используется внутри PinCodeView, PinCodeView также переопределяет несколько методов, таких как onKey[foo]() и переадресация вызова на внутренний TextView, Остальное просто с помощью TextWatcher обновить одного из детей ImageViews всякий раз, когда текст изменяется.

Это работает очень хорошо. Осталось еще несколько незначительных проблем, чтобы исправить это, но я рассмотрю их как отдельные вопросы и закрою здесь.

Похоже, вы пытаетесь создать iOS-вид, похожий на запись с пин-кодом.

Вот хороший пример кода, который вы можете найти полезным. Тем не менее, это фиксированная длина, но все же может быть полезно для некоторых людей.

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

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

Я знаю, что на это уже ответили, но так как его реализация не передана, я нашел похожую библиотеку с открытым исходным кодом Это выглядит хорошо и для всех тех, кто бродит может попробовать

https://github.com/Philio/PinEntryView

Выглядит нормально для меня. Что-то, что вы можете сделать, это когда пользователь вводит символ в один EditText найти ссылку на следующее поле EditText и сделать requestFocus() в теме. Это переместит текстовую запись в следующее поле. Очень просто.

implementation 'com.alimuzaffar.lib:pinentryedittext:1.3.10'

Поместите эту зависимость в файл Gradle вашего модуля приложения и выполните синхронизацию.

    <com.alimuzaffar.lib.pin.PinEntryEditText

                    android:inputType="number"
                    android:id="@+id/Pin_Et"
                    android:maxLength="6"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>

Поместите этот код в XML (файл макета).
Он отлично работает, я использую этот код

Другие вопросы по тегам