项目中有时会需要用到一个不可编辑的 EditText
,用于展示,很奇怪的需求对吧,明明就应该使用 TextView
来做展示,使用 EditText
来做输入,但现实就是可能为了 UI 统一,又或者是其他乱七八糟的原因,就得这么实现。
比如在之前的『PassBox』和『HacppleStore』,我就是这么干的。
那么在 Android 中应如何将 EditText
设置为不可编辑状态呢?
我总结了几种方法:
android:editable
<EditText
...
android:editable="false" />
效果如下:
可以看到,默认情况下,EditText
并没有获取到焦点,但点击 EditText
后,尽管焦点马上被激活,但输入法并没有弹出。
需要提醒的是,该属性已经被标记为 @Deprecated
:
<!-- If set, specifies that this TextView has an input method.
It will be a textual one unless it has otherwise been specified.
For TextView, this is false by default.
For EditText, it is true by default.
{@deprecated Use inputType instead.} -->
<attr name="editable" format="boolean" />
虽然上面提到使用 android:inputType
来代替,但我暂时没找到该属性的替代方法。
setKeyListener()
在逻辑中使用:
editText.setKeyListener(false);
效果与 android:editable
相同,默认情况下没有获取到焦点,点击后焦点被激活,输入法没有弹出。
setKeyListener()
实际上是继承自 TextView
的一个方法,传入 null
即为禁止用户输入。
android:focusable / setFocusable()
在布局文件中:
<EditText
...
android:focusable="false" />
或使用逻辑控制:
editText.setFocusable(false) // boolean
editText.setFocusable(View.NOT_FOCUSABLE); // int
效果如下:
这其实是继承自 View
的一个属性,用于控制对应的 View
能否获取焦点。
可以看到,默认情况下,EditText
并没有获取到焦点,触摸时 EditText
获取到焦点,并在触摸结束后失去焦点,而通过长按可以将剪贴板的内容粘贴至 EditText
内。
需要注意的是,setFocusable()
做了方法重载,使用 int
类型参数则需要到 API 26 才支持。
android:focusableInTouchMode / setFocusableInTouchMode()
在布局文件中:
<EditText
...
android:focusableInTouchMode="false" />
或使用逻辑控制:
editText.setFocusableInTouchMode(false);
该方法效果和 android:focusable
也一样,同样是继承自 View
的一个属性,用于控制对应的 View
在触摸时能否获取焦点。
android:enabled / setEnabled()
在布局文件中:
<EditText
...
android:enabled="false" />
或使用逻辑控制:
editText.setEnabled(false);
效果如下:
编辑框完全失去焦点,即无法通过粘贴的方法修改输入内容,但是整个编辑框变成了暗色状态,不易于阅读。
android:longClickable / setLongClickable()
为了可以清晰显示,并且不可以通过粘贴的方式编辑,我们可以考虑引入一些其他的解决方法。
通过粘贴方式编辑,实际操作过程是通过长按 EditText
以弹出对应的操作浮窗,才得以完成粘贴操作,那么我们就可以禁用长按操作,来避免用户进行粘贴。
在布局中:
<EditText
...
android:focusable="false"
android:longClickable="false" />
或使用逻辑控制:
editText.setFocusable(false);
editText.setLongClickable(false);
效果如下:
可以看到,文字能够清晰显示,长按 EditText
时也无法呼出操作浮窗,使用 android:focusable
或 setFocusable()
来搭配使用,因此同时也具备了相同的缺点,就是触摸时 EditText
仍然会获取焦点,但因为已经禁用了长按,所以不会产生功能上的问题。
如果还是不想存在焦点效果,添加个背景即可。
自定义 EditText
没有什么效果是自定义 View
解决不了的。
public class NonEditableEditText extends AppCompatEditText {
public NonEditableEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return true;
}
}
其实不需要多复杂,只需要重写 onTouchEvent()
方法即可,这里涉及到 View
的事件分发机制,简单来说,返回 true
代表当前 View
已经完整地处理了该事件,且不希望上层 ViewGroup
其他回调方法再次处理。
我们只需要在布局中使用该自定义控件:
<com.custom.widget.NonEditableEditText
... />
效果如下:
可以看到,无论是点击还是长按,该自定义的 EditText
都不会获取焦点,因为它并不会对我们的触摸事件做任何处理。