上篇文章还没写完,真的是没有太多时间写博客咯,今晚回去补上,最近在做银行的项目,需要用到自定义键盘,肯定会用到EditText,那么怎么禁止EditText弹出系统键盘呢,为此我也下了番功夫研究了下EditText的源码。下面我们从源码出发实现我们的需求。
我们看看EditText的源码:

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.widget;

import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.MovementMethod;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;


/*
 * This is supposed to be a *very* thin veneer over TextView.
 * Do not make any changes here that do anything that a TextView
 * with a key listener and a movement method wouldn't do!
 */

/**
 * EditText is a thin veneer over TextView that configures itself
 * to be editable.
 *
 * <p>See the <a href="{@docRoot}guide/topics/ui/controls/text.html">Text Fields</a>
 * guide.</p>
 * <p>
 * <b>XML attributes</b>
 * <p>
 * See {@link android.R.styleable#EditText EditText Attributes},
 * {@link android.R.styleable#TextView TextView Attributes},
 * {@link android.R.styleable#View View Attributes}
 */
public class EditText extends TextView {
    public EditText(Context context) {
        this(context, null);
    }

    public EditText(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.editTextStyle);
    }

    public EditText(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public EditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected boolean getDefaultEditable() {
        return true;
    }

    @Override
    protected MovementMethod getDefaultMovementMethod() {
        return ArrowKeyMovementMethod.getInstance();
    }

    @Override
    public Editable getText() {
        return (Editable) super.getText();
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        super.setText(text, BufferType.EDITABLE);
    }

    /**
     * Convenience for {@link Selection#setSelection(Spannable, int, int)}.
     */
    public void setSelection(int start, int stop) {
        Selection.setSelection(getText(), start, stop);
    }

    /**
     * Convenience for {@link Selection#setSelection(Spannable, int)}.
     */
    public void setSelection(int index) {
        Selection.setSelection(getText(), index);
    }

    /**
     * Convenience for {@link Selection#selectAll}.
     */
    public void selectAll() {
        Selection.selectAll(getText());
    }

    /**
     * Convenience for {@link Selection#extendSelection}.
     */
    public void extendSelection(int index) {
        Selection.extendSelection(getText(), index);
    }

    @Override
    public void setEllipsize(TextUtils.TruncateAt ellipsis) {
        if (ellipsis == TextUtils.TruncateAt.MARQUEE) {
            throw new IllegalArgumentException("EditText cannot use the ellipsize mode "
                    + "TextUtils.TruncateAt.MARQUEE");
        }
        super.setEllipsize(ellipsis);
    }

    @Override
    public CharSequence getAccessibilityClassName() {
        return EditText.class.getName();
    }

    /** @hide */
    @Override
    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
        switch (action) {
            case AccessibilityNodeInfo.ACTION_SET_TEXT: {
                CharSequence text = (arguments != null) ? arguments.getCharSequence(
                        AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
                setText(text);
                if (text != null && text.length() > 0) {
                    setSelection(text.length());
                }
                return true;
            }
            default: {
                return super.performAccessibilityActionInternal(action, arguments);
            }
        }
    }
}

整个EdtiText代码就那么100多行,不得不说EditText的父类TextView写的太牛逼了,不管其他的代码了,重点是实现我们今天的需求,禁止弹系统的键盘。我们看看这个方法:

/** @hide */
    @Override
    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
        switch (action) {
            case AccessibilityNodeInfo.ACTION_SET_TEXT: {
                CharSequence text = (arguments != null) ? arguments.getCharSequence(
                        AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
                setText(text);
                if (text != null && text.length() > 0) {
                    setSelection(text.length());
                }
                return true;
            }
            default: {
                return super.performAccessibilityActionInternal(action, arguments);
            }
        }
    }

然后看到super.performAccessibilityActionInternal(action, arguments);这一句点进去,发现我们到了父类TextView里面了

/**
     * Performs an accessibility action after it has been offered to the
     * delegate.
     *
     * @hide
     */
    @Override
    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
        if (mEditor != null
                && mEditor.mProcessTextIntentActionsHandler.performAccessibilityAction(action)) {
            return true;
        }
        switch (action) {
            case AccessibilityNodeInfo.ACTION_CLICK: {
                boolean handled = false;

                // Simulate View.onTouchEvent for an ACTION_UP event.
                if (isClickable() || isLongClickable()) {
                    if (isFocusable() && !isFocused()) {
                        requestFocus();
                    }

                    performClick();
                    handled = true;
                }

                // Simulate TextView.onTouchEvent for an ACTION_UP event.
                if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
                        && mText instanceof Spannable && mLayout != null
                        && (isTextEditable() || isTextSelectable()) && isFocused()) {
                    // Show the IME, except when selecting in read-only text.
                    final InputMethodManager imm = InputMethodManager.peekInstance();
                    viewClicked(imm);
                    if (!isTextSelectable() && mEditor.mShowSoftInputOnFocus && imm != null) {
                        handled |= imm.showSoftInput(this, 0);
                    }
                }

                return handled;
            }
            case AccessibilityNodeInfo.ACTION_COPY: {
                if (isFocused() && canCopy()) {
                    if (onTextContextMenuItem(ID_COPY)) {
                        return true;
                    }
                }
            } return false;
            case AccessibilityNodeInfo.ACTION_PASTE: {
                if (isFocused() && canPaste()) {
                    if (onTextContextMenuItem(ID_PASTE)) {
                        return true;
                    }
                }
            } return false;
            case AccessibilityNodeInfo.ACTION_CUT: {
                if (isFocused() && canCut()) {
                    if (onTextContextMenuItem(ID_CUT)) {
                        return true;
                    }
                }
            } return false;
            case AccessibilityNodeInfo.ACTION_SET_SELECTION: {
                ensureIterableTextForAccessibilitySelectable();
                CharSequence text = getIterableTextForAccessibility();
                if (text == null) {
                    return false;
                }
                final int start = (arguments != null) ? arguments.getInt(
                        AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1;
                final int end = (arguments != null) ? arguments.getInt(
                        AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1;
                if ((getSelectionStart() != start || getSelectionEnd() != end)) {
                    // No arguments clears the selection.
                    if (start == end && end == -1) {
                        Selection.removeSelection((Spannable) text);
                        return true;
                    }
                    if (start >= 0 && start <= end && end <= text.length()) {
                        Selection.setSelection((Spannable) text, start, end);
                        // Make sure selection mode is engaged.
                        if (mEditor != null) {
                            mEditor.startSelectionActionMode();
                        }
                        return true;
                    }
                }
            } return false;
            case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
            case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: {
                ensureIterableTextForAccessibilitySelectable();
                return super.performAccessibilityActionInternal(action, arguments);
            }
            case ACCESSIBILITY_ACTION_SHARE: {
                if (isFocused() && canShare()) {
                    if (onTextContextMenuItem(ID_SHARE)) {
                        return true;
                    }
                }
            } return false;
            default: {
                return super.performAccessibilityActionInternal(action, arguments);
            }
        }
    }

尼玛,太多了啊,我们看重点

// Simulate TextView.onTouchEvent for an ACTION_UP event.
                if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
                        && mText instanceof Spannable && mLayout != null
                        && (isTextEditable() || isTextSelectable()) && isFocused()) {
                    // Show the IME, except when selecting in read-only text.
                    final InputMethodManager imm = InputMethodManager.peekInstance();
                    viewClicked(imm);
                    if (!isTextSelectable() && mEditor.mShowSoftInputOnFocus && imm != null) {
                        handled |= imm.showSoftInput(this, 0);
                    }
                }

终于看到我们的想要的内容了,当下面这三个条件成立的时候就会默认弹出系统键盘,好的,既然知道思路了,我们就去看看怎么实现,

if (!isTextSelectable() && mEditor.mShowSoftInputOnFocus && imm != null) {
                        handled |= imm.showSoftInput(this, 0);
                    }

方案一:mEditor.mShowSoftInputOnFocu这个设为false
方案二:isTextSelectable()设为true

先说下第二种方案:

public boolean isTextSelectable() {
        return mEditor == null ? false : mEditor.mTextIsSelectable;
    }

我们看到有这么一个方法,我们在布局文件中把我们的EditText的android:textIsSelectable=”true”设为true试试,

<EditText
            android:id=@+id/id_edit1
            android:textIsSelectable=true
            android:layout_width=match_parent
            android:layout_height=50dp />

好吧,运行下代码,然后点击EditText,发现键盘不再弹出了,但貌似不是我们想要的效果啊,感觉怪怪的,
android:textIsSelectable=”true”的意思为文本是否可以复制,如果是true可以复制如果是false不可以复制,稍微查了一下,又把这哥们的东西翻出来了,啊哈哈哈~!!我发现真是受益良多啊,Android TextView支持拷贝&粘帖 textIsSelectable,
好了,是不弹出键盘了,但是光标没啦,很蛋疼啊~!!!
让我们再来研究下第二种方式mEditor.mShowSoftInputOnFocu这个设为false:顺藤摸瓜的让我们又找到了TextView的这个方法,不过默认是隐藏的,说到这里想必大家都知道要干什么了,那就是“反射”~~~!! 多么高大上的词汇啊,哈哈哈

@android.view.RemotableViewMethod
    public final void setShowSoftInputOnFocus(boolean show) {
        createEditorIfNeeded();

直接上代码了

public static void disableShowSoftInput(EditText editText)
      {
        if (android.os.Build.VERSION.SDK_INT <= 10) 
        {
            editText.setInputType(InputType.TYPE_NULL);  
            } 
        else {  
                    Class<EditText> cls = EditText.class;  
                    Method method;
                  try { 
                      method = cls.getMethod("setShowSoftInputOnFocus",boolean.class);  
                      method.setAccessible(true);  
                      method.invoke(editText, false);  
                  }catch (Exception e) {
              // TODO: handle exception
            }

                  try { 
                      method = cls.getMethod("setSoftInputShownOnFocus",boolean.class);  
                      method.setAccessible(true);  
                      method.invoke(editText, false);  
                  }catch (Exception e) {
              // TODO: handle exception
            }
            } 
      }

放到我们的工程中再试试,尼玛~! 居然可以了。。好吧,觉得被自己笑到了,不要喷哈~~!!!! 重点是学习的过程,