软键盘
软键盘
EditText 设置 imeOptions 属性对软键盘的影响
将软键盘的 Enter 键更改为其他键,可以设置其 android:imeOptions
属性,这个属性可以控制软键盘的 Enter 键,以及横屏情况下的软键盘显示状态。
该设置必须是下面所列的值之一,或者是一个 “action…
” 值加上一个 “flag…
” 值的组合,在 action…组中设置多个值(例如,多个 “action…” 值)都会产生未定义结果,而 flag….可以设置多个。各值之间使用垂直条 (|
) 分隔。
- 需要设置
android:singleLine=true
,否则 enter 是回车作用 - android:singleLine 在 API3 已经废弃,可以用
android:maxLines="1"
代替,还需要加上android:inputType="text"
才能生效
控制软键盘上的 Enter 键
android:imeOptions=”normal”
输入框后面还有输入控件的时候会显示 next,没有时会显示 done(完成)android:imeOptions=”actionUnspecified”
该属性为默认属性,一般情况下为 “normal” 的使用情形。- android:imeOptions=”actionNone”
没有反应。 - android:imeOptions=”actionSend”
显示 send(发送) 按钮,需要自己写事件。
- android:imeOptions=”actionNext”
显示 next(下一步) 按钮,作用是跳到下一个可输入的控件
- android:imeOptions=”actionPrevious”
显示上一步按钮,如果前面有输入控件,点击后会回到前一个控件获取焦点 - android:imeOptions=”actionDone”
显示 done(完成) 按钮,作用编辑完成。
横屏下控制软键盘
- android:imeOptions=”flagNoFullscreen”
在横屏下,当设置这个标志时,软键盘在弹出的时候,永远不会变成全屏状态,但是这个属性在 API 中说并不一定所有输入法都支持这个属性。 - android:imeOptions=”flagNoExtractUi”
这个属性也有意思,它的表现形式和 flagNoFullscreen 比较像。
因为在横屏下,这两个属性单独设置都让软键盘半屏显示,但是这两个属性还是有所不同的。
这里可以参阅下 API,flagNoExtractUI 显示的半屏软键盘本身软键盘显示还是全屏的,但是将之前的全屏输入框给隐藏掉,所以给你显示半屏的效果。而且在单独使用的时候,可能你会发现软键盘是先从全屏然后过渡到半屏的。
所以要去掉全屏到半屏过渡效果,在横屏状态下,需要和 flagNoFullscreen 一块使用,来达到更好的体验。
- android:imeOptions=”flagNavigatePrevious”
横屏下设置输入法全屏,设置输入框上的按钮为 (previous) 上一个的作用。 - android:imeOptions=”flagNavigateNext”
横屏下设置输入法全屏,设置输入框上的按钮为 (Next) 下一个作用。 - android:imeOptions=”flagNoAccessoryAction”
横屏下设置输入法全屏,并且使其输入框上的按钮隐藏。 - android:imeOptions=”flagNoEnterAction”
横屏下设置输入法全屏,输入框内的按钮为完成 (Done) 状态.编辑完毕,点完成,软键盘消失。
Android 软键盘上的按键监听
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
mMainEt = (EditText) findViewById(R.id.main_et);
mMainEt.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
switch (actionId) {
//点击GO键
case EditorInfo.IME_ACTION_GO:
return true;
//点击Done
case EditorInfo.IME_ACTION_DONE:
return true;
//点击Next
case EditorInfo.IME_ACTION_NEXT:
return true;
//点击Previous
case EditorInfo.IME_ACTION_PREVIOUS:
return true;
//点击None
case EditorInfo.IME_ACTION_NONE:
return true;
//点击Send
case EditorInfo.IME_ACTION_SEND:
return true;
}
return false;
}
});
Android 软键盘外触摸隐藏软键盘
在 Activity 中 copy 下面这段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
override
fun dispatchTouchEvent(ev: MotionEvent): Boolean {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
var v = getCurrentFocus()
if (isShouldHideKeyboard(v, ev)) {
var imm: InputMethodManager = this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS)
}
}
return super.dispatchTouchEvent(ev)
}
// Return whether touch the view.
private fun isShouldHideKeyboard(v: View, event: MotionEvent): Boolean {
if (v != null && (v is EditText)) {
var l = intArrayOf(0, 0)
v.getLocationInWindow(l)
var left = l[0]
var top = l[1]
var bottom = top + v.getHeight()
var right = left + v.getWidth()
return !(event.getX() > left && event.getX() < right
&& event.getY() > top && event.getY() < bottom)
}
return false
}
Android 监听软键盘显示和高度变化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
fun registerSoftInputChangedListener(activity: Activity, onSoftInputChangedListener: OnSoftInputChangedListener) {
val contentView = activity.findViewById<View>(android.R.id.content)
val onGlobalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
if (onSoftInputChangedListener != null) {
val height = getContentViewInvisibleHeight(activity)
onSoftInputChangedListener.onSoftInputChanged(height)
}
}
contentView.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)
}
interface OnSoftInputChangedListener {
fun onSoftInputChanged(height: Int)
}
private fun getContentViewInvisibleHeight(activity: Activity): Int {
val contentView = activity.findViewById<FrameLayout>(android.R.id.content)
val outRect = Rect()
contentView.getWindowVisibleDisplayFrame(outRect)
var statusBarHeight = BarUtils.getStatusBarHeight()
var height = (statusBarHeight + contentView.bottom) - outRect.bottom
var s1 = "contentView WindowVisibleDisplayFrame(${contentView}),top:${outRect.top}, bottom:${outRect.bottom}," +
"left:${outRect.left},right:${outRect.right}\n"
// tv_result.append(s1)
LogUtil.i(s1)
var s2 = "contentView ,top:${contentView.top}, bottom:${contentView.bottom}," +
"left:${contentView.left},right:${contentView.right}\n"
// tv_result.append(s2)
LogUtil.i(s2)
var s3 = "软键盘高度getContentViewInvisibleHeight ,${height}\n"
// tv_result.append(s3)
LogUtil.i(s3)
return height
}
软键盘显示和隐藏 toggle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public final class SoftInputShowHidden {
public static void showSoftInput(final Context context) {
if (!(context instanceof Activity)) {
return;
}
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
final View currentFocusView = ((Activity) context).getCurrentFocus();
if (inputMethodManager != null && currentFocusView != null)
try {
inputMethodManager.showSoftInput(currentFocusView, 0);
} catch (RuntimeException e) {
e.printStackTrace();
}
}
/**
* Toggle the soft input display or not.
*/
public static void toggleSoftInput(final Context context) {
InputMethodManager imm =
(InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
public static void hideSoftInput(final Context context) {
if (!(context instanceof Activity)) {
return;
}
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
final View currentFocusView = ((Activity) context).getCurrentFocus();
if (currentFocusView != null) {
final IBinder windowToken = currentFocusView.getWindowToken();
if (inputMethodManager != null && windowToken != null) {
try {
inputMethodManager.hideSoftInputFromWindow(windowToken, 0);
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
}
}
- Android 手动显示和隐藏软键盘方法总结
https://blog.csdn.net/ccpat/article/details/46717573
Android 软键盘泄漏 leak 和 5497 系统 bug
软键盘 leak
在 Activity#onDestroy() 调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Fix the leaks of soft input.
* <p>Call the function in {@link Activity#onDestroy()}.</p>
*
* @param context The context.
*/
public static void fixSoftInputLeaks(final Context context) {
if (context == null) return;
InputMethodManager imm =
(InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
String[] strArr = new String[]{"mCurRootView", "mServedView", "mNextServedView", "mLastSrvView"};
for (int i = 0; i < 4; i++) {
try {
Field declaredField = imm.getClass().getDeclaredField(strArr[i]);
if (declaredField == null) continue;
if (!declaredField.isAccessible()) {
declaredField.setAccessible(true);
}
Object obj = declaredField.get(imm);
if (obj == null || !(obj instanceof View)) continue;
View view = (View) obj;
if (view.getContext() == context) {
declaredField.set(imm, null);
} else {
return;
}
} catch (Throwable th) {
th.printStackTrace();
}
}
}
系统 5497bug
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Fix the bug of 5497 in Android.
*
* @param activity The activity.
*/
public static void fixAndroidBug5497(final Activity activity) {
final int flags = activity.getWindow().getAttributes().flags;
if ((flags & WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) != 0) {
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
final FrameLayout contentView = activity.findViewById(android.R.id.content);
final View contentViewChild = contentView.getChildAt(0);
final int paddingBottom = contentViewChild.getPaddingBottom();
sContentViewInvisibleHeightPre5497 = getContentViewInvisibleHeight(activity);
contentView.getViewTreeObserver()
.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int height = getContentViewInvisibleHeight(activity);
if (sContentViewInvisibleHeightPre5497 != height) {
contentViewChild.setPadding(
contentViewChild.getPaddingLeft(),
contentViewChild.getPaddingTop(),
contentViewChild.getPaddingRight(),
paddingBottom + height
);
sContentViewInvisibleHeightPre5497 = height;
}
}
});
}
- Android 软键盘挡住输入框问题的终极解决方案
https://blog.csdn.net/LuckChouDog/article/details/53099239
Android 键盘面板冲突,布局闪动的解决方法
JKeyboardPanelSwitch
Android 键盘面板冲突 布局闪动处理
Panel 使用:
- KPSwitchFSPanelLinearLayout 全屏和 Transulucent 使用
- KPSwitchPanelLinearLayout 非全屏和 Transulucent
PanelSwitchHelper
一个帮助键盘平稳过渡到功能面板的框架,支持动画无缝衔接,支持 activity/fragment/dialog/dialogFragment/popupWindow 容器,支持 IM/直播/视频播放/信息流评论等场景,支持全屏模式。
FluidKeyboardResize
本文由作者按照 CC BY 4.0 进行授权