关于输入框肯定有很多困惑。个人就有困惑来着。。。

主要分几种使用场景:

1. 进入有EditText控件的页面,默认会弹出软键盘?

2. 进入带输入框的界面,默认不弹出软键盘

3. 点击输入框弹出后,点击其他按钮手动软键盘或者退出页面时隐藏软键盘;

4. 多个输入框焦点获取如何显示next按键,以便跳转到下一个输入框;

5. 其他的呢? 在想想看...先把上面验证下吧....

1. 先从xml着手这个键盘是否默认弹窗来的问题吧..focus?

1.1 Activity界面如果存在输入框,默认弹窗键盘

xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".SoftkeyActivity">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/app_name"
android:textSize="20sp"
android:textColor="@color/colorAccent"/>
android:onClick="fucnSbs"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="弹个球窗(带输入框)"/>


1.1.1 当进入界面时你会发现键盘并没有弹出来?? 我印象中,如果是HomeActvity,如果底部有搜索框是会默认弹出来的。还会把底部的导航栏顶上去....这个解决办法是:

android:name=".app.HomeActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/MineActivityAppTheme"
android:windowSoftInputMode="adjustPan|stateHidden" />
看区别
"adjustResize"

该活动的主窗口始终调整大小,以使屏幕上的软键盘的余地。

"adjustPan"

该活动的主窗口无法调整大小,使软键盘的余地。

相反,窗口的内容是自动平移以便当前焦点从来没有遮挡键盘,用户始终可以看到他们正在键入。

这是比调整大小,一般是较不可取,因为用户可能需要关闭软键盘在获取和与模糊部分窗口的互动。

就是说,如果你不喜欢窗口被调整,比如底部导航栏被强行顶上去,以便留出空间给键盘。那么就需要设置为adjustPan...同时你不喜欢进入主页就弹窗键盘,那就stateHidden。

综上我们就可以解决进入带搜索的主页的问题 --- 其他的属性其实内容还是不少。暂时我们放到下篇分析吧.....

1.1.2 现在我们是想让页面弹窗键盘,那就简单了吧。。。

看图说话就行,不想用adjustresize就别用哈....

1.2 问题来了,如果是一个Dialog呢?有没有xml可以给你去配置dialog属性呀! 你基本上找相关资料,基本都是用代码。。那我们也用代码吧。干嘛非得xml妮!

1.2.1 随便创建个dialog

package com.example.lieyun_android.myapplication;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
public class CustomSoftDialog extends Dialog {
private Context mContext;
public CustomSoftDialog(@NonNull Context context) {
super(context);
mContext = context;
}
public CustomSoftDialog(@NonNull Context context, int themeResId) {
super(context, themeResId);
}
protected CustomSoftDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = View.inflate(mContext, R.layout.dialog_layout,null);
setContentView(view);
}
}
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SoftkeyActivity">
android:id="@+id/ddddd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/app_name"
android:textColor="@color/colorAccent"
android:textSize="20sp" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="fucnSbs"
android:text="弹个球窗(带输入框)"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/ddddd" />
然后弹一弹:
new CustomSoftDialog(this).show();
1.2.1 此时并没有弹出来键盘。我们看看代码好伐? 不过需要注意的时候,有时候你在页面初始化里面弹貌似会弹不出来 - 由于界面还未被初始化,所以需要一个弹窗显示完的事件里面或者延迟弹等方式!
Let's do it:
Dialog dlg;
dlg = new CustomSoftDialog(this);
dlg.setOnShowListener(new DialogInterface.OnShowListener() {
public void onShow(DialogInterface dialog) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
///< 隐藏就显示,显示就隐藏 - 这种有时候再逻辑上会给你带来困扰,如果要强制隐藏,建议用别的方式;不要靠什么Boolean状态来做..
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
});
dlg.show();

这样就可以弹出来了呀 - 后面还会说明一些参数和更多的方式以及区别:

右侧有想法方法结束,后面我们一起去看看吧~~(它这个搜索不得劲,不能模糊搜索....差劲了有点)

好吧。我们看一段toggleSoftInput的介绍吧....

toggleSoftInput
added in API level 3
public void toggleSoftInput (int showFlags,
int hideFlags)
This method toggles the input method window display. If the input window is already displayed, it gets hidden. If not the input window will be displayed.
Parameters
showFlagsint: Provides additional operating flags. May be 0 or have the SHOW_IMPLICIT, SHOW_FORCED bit set.
hideFlagsint: Provides additional operating flags. May be 0 or have the HIDE_IMPLICIT_ONLY, HIDE_NOT_ALWAYS bit set.

解释:反正就是说如果显示了,那么再次调用会隐藏。反之,则会显示。

再看哈里面的flag说明:

showFlags为显示软键盘时使用的标记,只有当前软键盘处于隐藏状态时才会使用。hideFlags是隐藏软键盘时使用的标记,只有当前软键盘处于显示状态时才会使用。

showFlags和hideFlags取值范围,以及不同取值的影响和上文分析的一样。

即showFlags和hideFlags都只影响软键盘的隐藏,不影响软键盘的显示。

不同取值对软键盘隐藏的影响参见上文中的表格。

当显示软键盘时,并不要求当前界面布局中有一个已经获取焦点的EditText,

即使当前布局是完全空白的,一个View也没有(除了最外层的Layout),

toggleSoftInput也能够显示软键盘。不过如果没有一个已经获取焦点的EditText,那么软键盘中的按键输入都是无效的。

那HIDE_NOT_ALWAYS呢?

HIDE_NOT_ALWAYS
added in API level 3
public static final int HIDE_NOT_ALWAYS
Flag for hideSoftInputFromWindow(IBinder, int) and InputMethodService.requestShowSelf(int) to indicate that the soft input window should normally be hidden, unless it was originally shown with SHOW_FORCED.
Constant Value: 2 (0x00000002)

解释: 它表明了soft input widows正常情况都应该隐藏,除非之前采用

1.2.1.1 按照官方说法采用SHOW_FORCED显示之后,我们用toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); 就没有用了。无法隐藏的呀。。。啊哈。

而看force:
SHOW_FORCED
added in API level 3
public static final int SHOW_FORCED
Flag for showSoftInput(View, int) to indicate that the user has forced the input method open (such as by long-pressing menu) so it should not be closed until they explicitly do so.
Constant Value: 2 (0x00000002)

所以我们需要采用showSoftInput来强制显示的喲。 而不是说采用了imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED); 的不能隐藏。。。我们有时候需要关注参数的说明和用法,再结合整体,不然容易迷雾...对,迷雾...

看显示 - View view1 = dlg.findViewById(R.id.ddddd);这个放到里面哟,不然找不到控件了就麻烦了....:

final Dialog dlg;
dlg = new CustomSoftDialog(this);
dlg.setOnShowListener(new DialogInterface.OnShowListener() {
public void onShow(DialogInterface dialog) {
View view1 = dlg.findViewById(R.id.ddddd);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
///< 隐藏就显示,显示就隐藏 - 这种有时候再逻辑上会给你带来困扰,如果要强制隐藏,建议用别的方式;不要靠什么Boolean状态来做..
imm.showSoftInput(view1, InputMethodManager.SHOW_FORCED);
}
});
dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
}
});
dlg.setCanceledOnTouchOutside(false);
dlg.show();

再看下点击dialog里面的文本的点击事件隐藏的代码:

public void fucnSbsddd(View view) {
Toast.makeText(this, "fuck,不能被隐藏了呀", Toast.LENGTH_SHORT).show();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
///< 隐藏就显示,显示就隐藏 - 这种有时候再逻辑上会给你带来困扰,如果要强制隐藏,建议用别的方式;不要靠什么Boolean状态来做..
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
 }

1.2.2.2 说明个人就大概先这样理解。我想后续的属性还是蛮多的。不过我们可以去分析,尝试,然后总结,然后纠错,然后再分析,总会弄清楚一些事情的。有个思路就行。。。这篇我们先把实际用的来实践下吧。。。别的后面慢慢来。不然一下子是总结不完了的....

2.既然说到了显示,我们简单的使用应该是问题不大。平时需求多半也就是进入页面是否弹不弹的问题。其实比较麻烦的可能是隐藏了吧。。。

比如点击登录按钮,需要先隐藏键盘;页面消失也需要隐藏键盘;个人目前主要就是这两种状态。

2.1 隐藏方式之上面的toggleSoftInput方式:

inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);

这个有个逻辑问题,你如果是点击输入框弹出了键盘, 登录事件里面你想调用隐藏,这个逻辑没问题。 但是如果你打开键盘后,点击键盘上的收回键。 然后当你点击登录时,会弹出来。这个不是我们要的效果? 此时你可能就需要判断键盘状态,如果是隐藏不可用,则点击登录的时候不能调用这种隐藏方法了。 稍微显得有点麻烦....

2.2 隐藏方式之showSoftInput???别闹了,好伐,这明明是显示方法吗...哈哈哈。。。。

2.3 隐藏方式之hideSoftInputFromWindow的方法

显示:
Dialog dlg;
public void fucnSbs(View view) {
dlg = new CustomSoftDialog(this);
dlg.setOnShowListener(new DialogInterface.OnShowListener() {
public void onShow(DialogInterface dialog) {
View view1 = dlg.findViewById(R.id.ddddd);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
///< 隐藏就显示,显示就隐藏 - 这种有时候再逻辑上会给你带来困扰,如果要强制隐藏,建议用别的方式;不要靠什么Boolean状态来做..
//imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
imm.showSoftInput(view1, InputMethodManager.SHOW_IMPLICIT);
}
});
dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
}
});
dlg.setCanceledOnTouchOutside(false);
dlg.show();
}
隐藏走一走:
public void fucnSbsddd(View view) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
///< 隐藏就显示,显示就隐藏 - 这种有时候再逻辑上会给你带来困扰,如果要强制隐藏,建议用别的方式;不要靠什么Boolean状态来做..
imm.hideSoftInputFromWindow(dlg.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
 }

效果没问题。隐藏了就隐藏了呀。。。。也不用像toggle那样需要判断状态,以免混乱...

那Activity呢?我们也试试...

Actv也没问题呀。。。我们封装下吧:

/*
*@Description: 隐藏键盘2
*@Author: hl
*@Time: 2018/8/21 11:57
*/
public static void hideKeyBord(Activity context) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isActive() && context.getCurrentFocus() != null) {
if (context.getCurrentFocus().getWindowToken() != null) {
imm.hideSoftInputFromWindow(context.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
}

貌似基本上我们的显示隐藏基本就够用了。 目前来看个人的几个项目都基本够用了额....

3.我们还是来看看hideSoftInputFromWindow吧。。

hideSoftInputFromWindow
added in API level 3
public boolean hideSoftInputFromWindow (IBinder windowToken,
int flags)
Synonym for hideSoftInputFromWindow(IBinder, int, ResultReceiver) without a result: request to hide the soft input window from the context of the window that is currently accepting input.
Parameters
windowTokenIBinder: The token of the window that is making the request, as returned by View.getWindowToken().
flagsint: Provides additional operating flags. Currently may be 0 or have the HIDE_IMPLICIT_ONLY bit set.

解释: 意思就是说这是一种不带结果返回的隐藏软键盘的方式,其中flag可以是0或者

而第二个参数给0, 如果给 HIDE_IMPLICIT_ONLY,用这种方式隐藏的话,那么显示时也就需要这种方式才能显示。 有点像force的情况。 他们之间应该是有相对关系的。。。。

这是目前从官方文档和实践来看,个人的一些总结吧。 我觉得后续有空还是应该深入分析和实践下这些个参数。。。其实个人不太明白google设计了这些个复杂的并且对外提供的方式? 为什么不提供简单的隐藏显示。。。或者看过原理的人会比较明白...

对了后来看了一篇文章分析,将的还比较细。 比较值得参考....当然笔者建议从官方文档入手,印象更深....后面我们再继续搞吧...要学习的东西还再很多....