Пользовательская клавиатура скрывает поле редактирования в Android

Я разработал специальную клавиатуру только с цифровыми клавишами. Я перешел по ссылке ниже: пример

Теперь, когда я касаюсь поля редактирования, появляется клавиатура. Но если у меня есть 10 полей редактирования, и я касаюсь 10-го поля редактирования, появляется клавиатура и скрывается поле редактирования. Как я могу сделать так, чтобы поле редактирования автоматически прокручивалось вверх, чтобы оно не было скрыто.

Я написал приведенный ниже код макета для файла xml:

  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <EditText
                android:id="@+id/edittext0"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="30dp"
                android:inputType="text" />

            <EditText
                android:id="@+id/edittext1"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/edittext0"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="30dp"
                android:inputType="text" />

            <EditText
                android:id="@+id/edittext2"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/edittext1"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="40dp"
                android:inputType="text" />

            <EditText
                android:id="@+id/edittext3"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/edittext2"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="40dp"
                android:inputType="text" />

            <EditText
                android:id="@+id/edittext4"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/edittext3"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="40dp"
                android:inputType="text" />
        </RelativeLayout>
    </ScrollView>

    <android.inputmethodservice.KeyboardView
        android:id="@+id/keyboardview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:visibility="gone" />

</RelativeLayout>

Также вот мой пользовательский класс Java для клавиатуры:

    class CustomKeyboard {

    /** A link to the KeyboardView that is used to render this CustomKeyboard. */
    private KeyboardView mKeyboardView;
    /** A link to the activity that hosts the {@link #mKeyboardView}. */
    private Activity mHostActivity;

    /** The key (code) handler. */
    private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener() {

        public final static int CodeDelete = -5; // Keyboard.KEYCODE_DELETE
        public final static int CodePrev = 55000;
        public final static int CodeNext = 55001;
        public final static int CodeDone = 55002;

        @Override
        public void onKey(int primaryCode, int[] keyCodes) {
            // NOTE We can say '<Key android:codes="49,50" ... >' in the xml
            // file; all codes come in keyCodes, the first in this list in
            // primaryCode
            // Get the EditText and its Editable
            View focusCurrent = mHostActivity.getWindow().getCurrentFocus();
            if (focusCurrent == null
                    || focusCurrent.getClass() != EditText.class)
                return;
            EditText edittext = (EditText) focusCurrent;
            Editable editable = edittext.getText();
            int start = edittext.getSelectionStart();
            // Apply the key to the edittext
            if (primaryCode == CodeDone) {
                hideCustomKeyboard();
            } 
            else if (primaryCode == CodeDelete) 
            {
                if (editable != null && start > 0)
                    editable.delete(start - 1, start);
            } 
            else if (primaryCode == CodePrev) {
                View focusNew = edittext.focusSearch(View.FOCUS_BACKWARD);
                if (focusNew != null)
                    focusNew.requestFocus();
            } 
            else if (primaryCode == CodeNext) {
                View focusNew = edittext.focusSearch(View.FOCUS_FORWARD);
                if (focusNew != null)
                    focusNew.requestFocus();
            } 
            else { // insert character
                editable.insert(start, Character.toString((char) primaryCode));
            }
        }

        @Override
        public void onPress(int arg0) {
        }

        @Override
        public void onRelease(int primaryCode) {
        }

        @Override
        public void onText(CharSequence text) {
        }

        @Override
        public void swipeDown() {
        }

        @Override
        public void swipeLeft() {
        }

        @Override
        public void swipeRight() {
        }

        @Override
        public void swipeUp() {
        }
    };

    /**
     * Create a custom keyboard, that uses the KeyboardView (with resource id
     * <var>viewid</var>) of the <var>host</var> activity, and load the keyboard
     * layout from xml file <var>layoutid</var> (see {@link Keyboard} for
     * description). Note that the <var>host</var> activity must have a
     * <var>KeyboardView</var> in its layout (typically aligned with the bottom
     * of the activity). Note that the keyboard layout xml file may include key
     * codes for navigation; see the constants in this class for their values.
     * Note that to enable EditText's to use this custom keyboard, call the
     * {@link #registerEditText(int)}.
     * 
     * @param host
     *            The hosting activity.
     * @param viewid
     *            The id of the KeyboardView.
     * @param layoutid
     *            The id of the xml file containing the keyboard layout.
     */
    public CustomKeyboard(Activity host, int viewid, int layoutid) {
        mHostActivity = host;
        mKeyboardView = (KeyboardView) mHostActivity.findViewById(viewid);
        mKeyboardView.setKeyboard(new Keyboard(mHostActivity, layoutid));
        mKeyboardView.setPreviewEnabled(false); // NOTE Do not show the preview
                                                // balloons
        mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);
        // Hide the standard keyboard initially
        mHostActivity.getWindow().setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
    }

    /** Returns whether the CustomKeyboard is visible. */
    public boolean isCustomKeyboardVisible() {
        return mKeyboardView.getVisibility() == View.VISIBLE;
    }

    /**
     * Make the CustomKeyboard visible, and hide the system keyboard for view v.
     */
    public void showCustomKeyboard(View v) {
        mKeyboardView.setVisibility(View.VISIBLE);
        mKeyboardView.setEnabled(true);
        if (v != null)
            ((InputMethodManager) mHostActivity
                    .getSystemService(Activity.INPUT_METHOD_SERVICE))
                    .hideSoftInputFromWindow(v.getWindowToken(), 0);
    }

    /** Make the CustomKeyboard invisible. */
    public void hideCustomKeyboard() {
        mKeyboardView.setVisibility(View.GONE);
        mKeyboardView.setEnabled(false);
    }

    /**
     * Register <var>EditText<var> with resource id <var>resid</var> (on the
     * hosting activity) for using this custom keyboard.
     * 
     * @param resid
     *            The resource id of the EditText that registers to the custom
     *            keyboard.
     */
    public void registerEditText(int resid) {
        // Find the EditText 'resid'
        EditText edittext = (EditText) mHostActivity.findViewById(resid);
        // Make the custom keyboard appear
        edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
            // NOTE By setting the on focus listener, we can show the custom
            // keyboard when the edit box gets focus, but also hide it when the
            // edit box loses focus
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus)
                    showCustomKeyboard(v);
                else
                    hideCustomKeyboard();
            }
        });
        edittext.setOnClickListener(new OnClickListener() {
            // NOTE By setting the on click listener, we can show the custom
            // keyboard again, by tapping on an edit box that already had focus
            // (but that had the keyboard hidden).
            @Override
            public void onClick(View v) {
                showCustomKeyboard(v);
            }
        });
        // Disable standard keyboard hard way
        // NOTE There is also an easy way:
        // 'edittext.setInputType(InputType.TYPE_NULL)' (but you will not have a
        // cursor, and no 'edittext.setCursorVisible(true)' doesn't work )
        edittext.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                EditText edittext = (EditText) v;
                int inType = edittext.getInputType(); // Backup the input type
                edittext.setInputType(InputType.TYPE_NULL); // Disable standard
                                                            // keyboard
                edittext.onTouchEvent(event); // Call native handler
                edittext.setInputType(inType); // Restore input type
                return true; // Consume touch event
            }
        });
        // Disable spell check (hex strings look like words to Android)
        edittext.setInputType(edittext.getInputType()
                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
    }

}

Помоги мне, пожалуйста!!

Спасибо, Ариндам.


person Arindam Mukherjee    schedule 13.01.2014    source источник
comment
Используйте scrollView с RelativeLayout, чтобы позволить textView двигаться вверх, когда что-то появляется внизу   -  person Saqib    schedule 13.01.2014
comment
Это только я сделал правильно на xml. Где вы хотите, чтобы я изменил?   -  person Arindam Mukherjee    schedule 13.01.2014
comment
ваш относительный макет не открывается и не закрывается правильно, проверьте это и поместите свою клавиатуру также внутрь относительного макета, чтобы все отображалось относительно друг друга   -  person Saqib    schedule 13.01.2014
comment
Обновил код. макет xml. Но не повезло. Также сохранил клавиатуру внутри относительной раскладки. Потом тоже не прокручивал..   -  person Arindam Mukherjee    schedule 13.01.2014


Ответы (2)


У меня была точно такая же проблема, и после полных исследований я, наконец, решил ее.

Вот как:

У меня почти такой же макет xml, как у вас, но у меня есть несколько KeyboardViews, потому что мне нужны разные клавиатуры для разных EditTexts.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="HardcodedText,TextFields" >    

<ScrollView 
    android:id="@+id/scroll_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:orientation="vertical"
        android:layout_gravity="center_horizontal"
        android:paddingBottom="16dp">

        <TextView
            android:id="@+id/DecLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Decimal" />

        <EditText
            android:id="@+id/DecText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:focusable="true"
            android:focusableInTouchMode="true" />

        <TextView
            android:id="@+id/HexLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="24dp"
            android:text="Hexadecimal" />

        <EditText
            android:id="@+id/HexText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:focusable="true"
            android:focusableInTouchMode="true" />

        <TextView
            android:id="@+id/BinaryLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="24dp"
            android:text="Binary" />

        <EditText
            android:id="@+id/BinaryText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:focusable="true"
            android:focusableInTouchMode="true" />

        <TextView
            android:id="@+id/OctalLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="24dp"
            android:text="Octal" />

        <EditText
            android:id="@+id/OctalText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:layout_gravity="fill" />
    </LinearLayout>

</ScrollView>

<android.inputmethodservice.KeyboardView
    android:id="@+id/keyboardview_hex"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_margin="0dp"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:keyBackground="@drawable/btn_keyboard_key_ics"
    android:visibility="gone" />

<android.inputmethodservice.KeyboardView
    android:id="@+id/keyboardview_dec"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_margin="0dp"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:keyBackground="@drawable/btn_keyboard_key_ics"
    android:visibility="gone" />

<android.inputmethodservice.KeyboardView
    android:id="@+id/keyboardview_oct"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_margin="0dp"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:keyBackground="@drawable/btn_keyboard_key_ics"
    android:visibility="gone" />

<android.inputmethodservice.KeyboardView
    android:id="@+id/keyboardview_bin"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_margin="0dp"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:keyBackground="@drawable/btn_keyboard_key_ics"
    android:visibility="gone" />

It is not enough. I also needed to set ScrollView's android:layout_above property when the KeyboardView is shown and i did this with an interface:

public interface OnKeyboardStateChangedListener
{
    public void OnDisplay(View currentview, KeyboardView currentKeyboard);

    public void OnHide(KeyboardView currentKeyboard);
} 

И реализовал этот интерфейс для моей MainActivity для редактирования свойств ScrollView:

public class MainActivity extends Activity BaseKeyboard.OnKeyboardStateChangedListener

Также я передал MainActivity в качестве параметра и сохранил как OnKeyboardStateChangedListener:

private OnKeyboardStateChangedListener mStateListener;

public BaseKeyboard(Activity host, int viewid, int layoutid, OnKeyboardStateChangedListener listener) {
    ..
    ..
    mStateListener = listener;
}

И вызывал его при отображении/скрытии клавиатуры:

public void showCustomKeyboard( View v ) {
    mKeyboardView.setVisibility(View.VISIBLE);
    mKeyboardView.setEnabled(true);
    if( v!=null ) {
        mStateListener.OnDisplay(v, mKeyboardView);
        ((InputMethodManager)mHostActivity.getSystemService(Activity.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
    }
}

public void hideCustomKeyboard() {
    mKeyboardView.setVisibility(View.GONE);
    mKeyboardView.setEnabled(false);
    mStateListener.OnHide(mKeyboardView);
}

И, наконец, я отредактировал параметры в MainActivity:

@Override
public void OnDisplay(View currentview, KeyboardView currentKeyboard) {
    ScrollView mScroll = (ScrollView) findViewById(R.id.scroll_content);
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT);
    params.addRule(RelativeLayout.ABOVE,  currentKeyboard.getId());
    mScroll.setLayoutParams(params);                
    mScroll.scrollTo(0, currentview.getBaseline()); //Scrolls to focused EditText

}

@Override
public void OnHide(KeyboardView currentKeyboard) {
    ScrollView mScroll = (ScrollView) findViewById(R.id.scroll_content);
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT);
    mScroll.setLayoutParams(params);

}

Вот скриншоты:

Заметки:

  • У меня есть LinearLayout вместо RelativeLayout внутри ScrollView, потому что, когда отображается моя клавиатура, ScrollView работает по мере необходимости, но он сокращает самое нижнее представление пополам, а отступы или поля не работают с RelativeLayout в этой ситуации, но добавление paddingBottom к LinearLayout отодвигает его назад и весь вид виден. Я не мог найти другого способа исправить это.

  • Вы должны попробовать разные размеры прокладок, чтобы удовлетворить ваши потребности.

  • Я могу предоставить полный исходный код и дополнительную информацию, если вам нужно.

person Ege Apak    schedule 03.02.2014
comment
у меня тоже такая же проблема. не могли бы вы уточнить свой код в следующем методе: private OnKeyboardStateChangedListener mStateListener; public BaseKeyboard (узел активности, int viewid, int layoutid, прослушиватель OnKeyboardStateChangedListener) { .. .. mStateListener = listener; } - person NikhilReddy; 12.03.2014
comment
Мне нужно было изменить значение параметра android:layout_above ScrollView, когда клавиатура отображается и скрывается, и для этого я создал интерфейс (с именем OnKeyboardStateChangedListener) в своем классе клавиатуры (он же BaseKeyboard), и в этом методе я сохраняю ссылку в основной класс, который реализует этот настраиваемый интерфейс и сохраняет другие параметры (например, активность хоста, идентификатор KeyboardView и т. д.), и я регистрирую EditTexts в другом методе для событий щелчка. Когда это событие срабатывает, я показываю клавиатуру и отправляю информацию в основной класс с этим интерфейсом. - person Ege Apak; 13.03.2014
comment
Хорошее мышление. Хорошее объяснение со скриншотом. Работает как шарм. - person void; 15.08.2014

Проверил, работает нормально.

Ваш основной макет - это RelativeLayout, который дает целое относительное расположение, и поэтому все меняется относительно в поле зрения.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<ScrollView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/edittext0"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="30dp"
            android:inputType="text" />

        <EditText
            android:id="@+id/edittext1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/edittext0"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="30dp"
            android:inputType="text" />

        <EditText
            android:id="@+id/edittext2"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/edittext1"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="40dp"
            android:inputType="text" />

        <EditText
            android:id="@+id/edittext3"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/edittext2"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="40dp"
            android:inputType="text" />

        <EditText
            android:id="@+id/edittext4"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/edittext3"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="40dp"
            android:inputType="text" />
    </RelativeLayout>
</ScrollView>

<android.inputmethodservice.KeyboardView
    android:id="@+id/keyboardview"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:visibility="gone" />
 </RelativeLayout>

Проверьте этот вывод, который я только что попробовал

Img1 = http://i44.tinypic.com/2412r0n.png Img2 = введите здесь описание ссылки

person Saqib    schedule 13.01.2014
comment
Нет, это не работает. Выложенный вами код не работает. Вы тестируете с пользовательской клавиатурой или программной клавиатурой (по умолчанию для Android)? - person Arindam Mukherjee; 13.01.2014
comment
Должна работать и с пользовательской клавиатурой. Вёрстка работает как надо, у меня нет вашего кастомного кода, проверить не могу - person Saqib; 13.01.2014
comment
Он не работает с пользовательской клавиатурой. это причина, по которой я написал. Я знаю, что он работает с клавиатурой по умолчанию. - person Arindam Mukherjee; 13.01.2014
comment
И я поделился ссылкой уже в моем посте. Там можно скачать весь проект и запустить. - person Arindam Mukherjee; 13.01.2014
comment
затем попробуйте разные вещи в своем xml. как посмотреть, работают ли разные вещи. добавить пользовательскую раскладку клавиатуры android:layout_below=@+id/scrollViewIdName - person Saqib; 13.01.2014