Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Keyboard is hiding the Edit box in Android

I have designed a custom key board with only numeric keys. I have followed the below link: example

Now when i am touching the edit box, key board is appearing. But if i have 10 editboxes, and i am touching the 10th edit box, key board is appeared and hiding the edit box.How can i make the edit box will scroll up automatically so that it will be not hidden.

I have written the below layout code for xml file:

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

Also here is my custom keyboard java class:

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

}

Help me please!!

Thanks, Arindam

like image 807
Arindam Mukherjee Avatar asked Jan 13 '14 17:01

Arindam Mukherjee


1 Answers

I had the exact same problem and after a full days research i have finally solved it.

Here is how:

I have nearly identical xml layout as yours but i have multiple KeyboardViews because i need different keyboards for different 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);
} 

And implemented this interface to my MainActivity to edit ScrollView's properties:

public class MainActivity extends Activity BaseKeyboard.OnKeyboardStateChangedListener

Also i passed MainActivity as a parameter and saved as OnKeyboardStateChangedListener:

private OnKeyboardStateChangedListener mStateListener;

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

And invoked it when displaying/hiding the keyboard:

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

And finally i edited the parameters in the 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);

}

Here are the screenshots:

  • How it should look without keyboard
  • With a keyboard displayed

Notes:

  • I have LinearLayout instead of RelativeLayout inside ScrollView because when my keyboard is shown, ScrollView works as needed but it cuts the most bottom View in half and padding or margin doesn't work with RelativeLayout in this situation but adding a paddingBottom to LinearLayout pushes it back and all of the View is visible. I couldn't find another way to fix this.

  • You should try different size of paddings to satisfy your needs.

  • I can provide full source code and additional info if you need.

like image 78
Ege Apak Avatar answered Sep 23 '22 14:09

Ege Apak