自定义键盘在安卓系统中隐藏了编辑框

5
我设计了一个只有数字键的自定义键盘。我遵循了以下链接:示例
现在当我触摸编辑框时,键盘会出现。但如果我有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);
    }

}

请帮助我!

谢谢, Arindam


使用RelativeLayout和scrollView,让textView在下方出现内容时向上移动。 - Saqib
我只在 XML 上做对了的事情。你想让我在哪里修改? - Arindam Mukherjee
你的RelativeLayout打开和关闭的方式不正确,请检查并将键盘也放在RelativeLayout内,以便所有内容都相对于彼此视图。 - Saqib
更新了代码和xml布局,但没有运行成功。我将键盘保留在相对布局中,并尝试滚动页面,但仍然无法达成预期效果。 - Arindam Mukherjee
2个回答

5

我曾经遇到过完全相同的问题,经过一整天的研究,我终于解决了它。

以下是解决方法:

我的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" />

这还不够。当键盘视图显示时,我还需要设置ScrollView的android:layout_above属性,我通过接口来实现:

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

}

这里是屏幕截图:

注释:

  • 在ScrollView内,我使用LinearLayout而不是RelativeLayout,因为当我的键盘显示时,ScrollView按照需要工作,但会将最底部的视图切成两半,并且在这种情况下,RelativeLayout的填充或边距无法起作用,但是在LinearLayout中添加paddingBottom可以将其推回来,从而使所有视图都可见。我找不到其他解决方法。

  • 您应该尝试不同大小的填充以满足您的需求。

  • 如果您需要,我可以提供完整的源代码和其他信息。


我也遇到了同样的问题。您能否按照以下方法详细说明您的代码? private OnKeyboardStateChangedListener mStateListener;public BaseKeyboard(Activity host, int viewid, int layoutid, OnKeyboardStateChangedListener listener) { .. .. mStateListener = listener; } - NikhilReddy
当键盘显示和隐藏时,我需要更改ScrollView的android:layout_above参数的值。为了实现这一点,我在我的键盘类(又名BaseKeyboard)中创建了一个接口(命名为OnKeyboardStateChangedListener),并在该方法中保存对实现此自定义接口的主类的引用以及保存其他参数(如宿主活动、KeyboardView的ID等)。我在另一个方法中注册EditText的点击事件。当此事件触发时,我会显示键盘并通过该接口向主类发送信息。 - Ege Apak
思路很好。附带截图的解释清晰易懂。运行得非常顺畅。 - void

0

检查过了,工作正常。

你的主布局是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 = 输入链接描述


1
不,它没有起作用。您发布的代码无法正常工作。您是在测试自定义键盘还是软键盘(Android默认)? - Arindam Mukherjee
应该也可以与自定义键盘一起使用。布局完全按照预期工作,我没有您的自定义代码,因此无法检查。 - Saqib
1
它无法与自定义键盘配合使用。这就是我发布的原因。我知道它可以与默认键盘一起使用。 - Arindam Mukherjee
我已经在我的帖子中分享了链接。你可以在那里下载整个项目并运行。 - Arindam Mukherjee
然后在您的xml中尝试不同的事情。例如查看不同的事物是否有效。在自定义键盘布局中添加android:layout_below="@+id/scrollViewIdName"。 - Saqib

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接