上篇文章还没写完,真的是没有太多时间写博客咯,今晚回去补上,最近在做银行的项目,需要用到自定义键盘,肯定会用到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
}
}
}
放到我们的工程中再试试,尼玛~! 居然可以了。。好吧,觉得被自己笑到了,不要喷哈~~!!!! 重点是学习的过程,