![](/img/trans.png)
[英]How to hide soft keyboard on android after clicking outside EditText? in fragment
[英]How to hide soft keyboard on android after clicking outside EditText?
好的,每個人都知道要隱藏鍵盤,您需要實現:
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
但是這里的大問題是當用戶觸摸或選擇任何其他不是EditText
或 softKeyboard 的地方時如何隱藏鍵盤?
我嘗試在我的父Activity
上使用onTouchEvent()
,但這僅在用戶觸摸任何其他視圖之外並且沒有滾動視圖時才有效。
我試圖實現一個觸摸、點擊、聚焦監聽器,但沒有成功。
我什至嘗試實現自己的滾動視圖來攔截觸摸事件,但我只能獲取事件的坐標而不是單擊的視圖。
有沒有標准的方法來做到這一點? 在 iPhone 中,這真的很容易。
以下代碼段只是隱藏了鍵盤:
public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager =
(InputMethodManager) activity.getSystemService(
Activity.INPUT_METHOD_SERVICE);
if(inputMethodManager.isAcceptingText()){
inputMethodManager.hideSoftInputFromWindow(
activity.getCurrentFocus().getWindowToken(),
0
);
}
}
您可以將其放在實用程序類中,或者如果您在活動中定義它,請避免使用活動參數,或調用hideSoftKeyboard(this)
。
最棘手的部分是何時調用它。 您可以編寫一個方法來遍歷活動中的每個View
,並檢查它是否是instanceof EditText
,如果它沒有向該組件注冊setOnTouchListener
並且一切都會到位。 如果您想知道如何做到這一點,它實際上非常簡單。 這就是你要做的,你寫一個像下面這樣的遞歸方法,實際上你可以用它來做任何事情,比如設置自定義字體等......這是方法
public void setupUI(View view) {
// Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText)) {
view.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard(MyActivity.this);
return false;
}
});
}
//If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
就是這樣,只需在您的活動中setContentView
后調用此方法。 如果您想知道要傳遞什么參數,它是父容器的id
。 為您的父容器分配一個id
,例如
<RelativeLayoutPanel android:id="@+id/parent"> ... </RelativeLayout>
並調用setupUI(findViewById(R.id.parent))
,僅此而已。
如果你想有效地使用它,你可以創建一個擴展的Activity
並放入這個方法,並讓你的應用程序中的所有其他活動都擴展這個 Activity 並在onCreate()
方法中調用它的setupUI()
。
希望能幫助到你。
如果您使用超過 1 個活動,請為父布局定義公共 id,例如<RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>
然后從Activity
擴展一個類並在其OnResume()
中定義setupUI(findViewById(R.id.main_parent))
並in your program
擴展此類而不是 ``Activity
這是上述函數的 Kotlin 版本:
@file:JvmName("KeyboardUtils")
fun Activity.hideSoftKeyboard() {
currentFocus?.let {
val inputMethodManager = ContextCompat.getSystemService(this, InputMethodManager::class.java)!!
inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0)
}
}
您可以通過執行以下步驟來實現此目的:
通過添加以下屬性使父視圖(您的活動的內容視圖)可點擊和可聚焦
android:clickable="true" android:focusableInTouchMode="true"
實現一個 hideKeyboard() 方法
public void hideKeyboard(View view) { InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); }
最后,設置編輯文本的 onFocusChangeListener。
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { hideKeyboard(v); } } });
正如以下評論之一所指出的,如果父視圖是 ScrollView,這可能不起作用。 對於這種情況,可以在 ScrollView 正下方的視圖上添加 clickable 和 focusableInTouchMode。
只需在 Activity 中覆蓋以下代碼
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (getCurrentFocus() != null) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
return super.dispatchTouchEvent(ev);
}
更新:
如果有人需要這個答案的 Kotlin 版本:
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (currentFocus != null) {
val imm = activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(activity!!.currentFocus!!.windowToken, 0)
}
return super.dispatchTouchEvent(ev)
}
我發現接受的答案有點復雜。
這是我的解決方案。 將OnTouchListener
添加到您的主布局中,即:
findViewById(R.id.mainLayout).setOnTouchListener(this)
並將以下代碼放入 onTouch 方法中。
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
這樣您就不必遍歷所有視圖。
我得到了另一種隱藏鍵盤的解決方案:
InputMethodManager imm = (InputMethodManager) getSystemService(
Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
這里在 showFlag 的位置傳遞HIDE_IMPLICIT_ONLY
,在showFlag
的位置hiddenFlag
0
。 它將強制關閉軟鍵盤。
使用TextInputEditText的更多Kotlin & Material Design方式(這種方法也與EditTextView兼容)......
1.通過添加以下屬性使父視圖(您的活動/片段的內容視圖)可點擊和可聚焦
android:focusable="true"
android:focusableInTouchMode="true"
android:clickable="true"
2.為所有視圖創建一個擴展名(例如在 ViewExtension.kt 文件中):
fun View.hideKeyboard(){
val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(this.windowToken, 0)
}
3.創建繼承TextInputEditText的BaseTextInputEditText。 實現 onFocusChanged 方法以在視圖未聚焦時隱藏鍵盤:
class BaseTextInputEditText(context: Context?, attrs: AttributeSet?) : TextInputEditText(context, attrs){
override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
super.onFocusChanged(focused, direction, previouslyFocusedRect)
if (!focused) this.hideKeyboard()
}
}
4.只需在您的 XML 中調用您全新的自定義視圖:
<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayout"
...>
<com.your_package.BaseTextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
... />
</android.support.design.widget.TextInputLayout>
就這樣。 無需修改您的控制器(片段或活動)來處理這種重復的情況。
好吧,我設法在一定程度上解決了這個問題,我在我的活動中覆蓋了 dispatchTouchEvent,我正在使用以下內容來隱藏鍵盤。
/**
* Called to process touch screen events.
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
touchDownTime = SystemClock.elapsedRealtime();
break;
case MotionEvent.ACTION_UP:
//to avoid drag events
if (SystemClock.elapsedRealtime() - touchDownTime <= 150){
EditText[] textFields = this.getFields();
if(textFields != null && textFields.length > 0){
boolean clickIsOutsideEditTexts = true;
for(EditText field : textFields){
if(isPointInsideView(ev.getRawX(), ev.getRawY(), field)){
clickIsOutsideEditTexts = false;
break;
}
}
if(clickIsOutsideEditTexts){
this.hideSoftKeyboard();
}
} else {
this.hideSoftKeyboard();
}
}
break;
}
return super.dispatchTouchEvent(ev);
}
編輯: getFields() 方法只是一個返回視圖中包含文本字段的數組的方法。 為了避免在每次觸摸時都創建這個數組,我創建了一個名為 sFields 的靜態數組,它在 getFields() 方法中返回。 該數組在 onStart() 方法上初始化,例如:
sFields = new EditText[] {mUserField, mPasswordField};
它並不完美,拖動事件時間僅基於啟發式,因此有時在執行長 clics 時它不會隱藏,我還通過創建一個方法來獲取每個視圖的所有 editTexts 完成; 否則,當單擊其他 EditText 時,鍵盤會隱藏並顯示。
盡管如此,還是歡迎更清潔和更短的解決方案
在任何 Activity(或擴展 Activity 類)中覆蓋 public boolean dispatchTouchEvent(MotionEvent event)
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
View view = getCurrentFocus();
boolean ret = super.dispatchTouchEvent(event);
if (view instanceof EditText) {
View w = getCurrentFocus();
int scrcoords[] = new int[2];
w.getLocationOnScreen(scrcoords);
float x = event.getRawX() + w.getLeft() - scrcoords[0];
float y = event.getRawY() + w.getTop() - scrcoords[1];
if (event.getAction() == MotionEvent.ACTION_UP
&& (x < w.getLeft() || x >= w.getRight()
|| y < w.getTop() || y > w.getBottom()) ) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus().getWindowToken(), 0);
}
}
return ret;
}
科特林版本:
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
val ret = super.dispatchTouchEvent(ev)
ev?.let { event ->
if (event.action == MotionEvent.ACTION_UP) {
currentFocus?.let { view ->
if (view is EditText) {
val touchCoordinates = IntArray(2)
view.getLocationOnScreen(touchCoordinates)
val x: Float = event.rawX + view.getLeft() - touchCoordinates[0]
val y: Float = event.rawY + view.getTop() - touchCoordinates[1]
//If the touch position is outside the EditText then we hide the keyboard
if (x < view.getLeft() || x >= view.getRight() || y < view.getTop() || y > view.getBottom()) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
view.clearFocus()
}
}
}
}
}
return ret
}
這就是你需要做的所有事情
例如:
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
hideKeyboard();
}
}
});
更新:您還可以在活動中覆蓋onTouchEvent()
並檢查觸摸坐標。 如果坐標在 EditText 之外,則隱藏鍵盤。
我在 Activity 中實現了 dispatchTouchEvent 來做到這一點:
private EditText mEditText;
private Rect mRect = new Rect();
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
int[] location = new int[2];
mEditText.getLocationOnScreen(location);
mRect.left = location[0];
mRect.top = location[1];
mRect.right = location[0] + mEditText.getWidth();
mRect.bottom = location[1] + mEditText.getHeight();
int x = (int) ev.getX();
int y = (int) ev.getY();
if (action == MotionEvent.ACTION_DOWN && !mRect.contains(x, y)) {
InputMethodManager input = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
input.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}
return super.dispatchTouchEvent(ev);
}
我測試了它,完美!
我修改了 Andre Luis IM 的解決方案,我實現了這個:
我創建了一個實用方法來隱藏軟鍵盤,就像 Andre Luiz IM 所做的那樣:
public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
但是我沒有為每個視圖注冊一個 OnTouchListener,這會導致性能很差,我只為根視圖注冊了 OnTouchListener。 由於事件冒泡直到被消費(EditText是默認消費它的視圖之一),如果它到達根視圖,那是因為它沒有被消費,所以我關閉了軟鍵盤。
findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Utils.hideSoftKeyboard(activity);
return false;
}
});
我知道這個線程已經很老了,正確的答案似乎是有效的,並且有很多可行的解決方案,但我認為下面所述的方法可能在效率和優雅方面有額外的好處。
我的所有活動都需要這種行為,所以我創建了一個繼承自類Activity的類CustomActivity並“掛鈎”了dispatchTouchEvent函數。 主要有兩個條件需要注意:
這是我的結果:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_UP) {
final View view = getCurrentFocus();
if(view != null) {
final boolean consumed = super.dispatchTouchEvent(ev);
final View viewTmp = getCurrentFocus();
final View viewNew = viewTmp != null ? viewTmp : view;
if(viewNew.equals(view)) {
final Rect rect = new Rect();
final int[] coordinates = new int[2];
view.getLocationOnScreen(coordinates);
rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight());
final int x = (int) ev.getX();
final int y = (int) ev.getY();
if(rect.contains(x, y)) {
return consumed;
}
}
else if(viewNew instanceof EditText || viewNew instanceof CustomEditText) {
return consumed;
}
final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0);
viewNew.clearFocus();
return consumed;
}
}
return super.dispatchTouchEvent(ev);
}
旁注:此外,我將這些屬性分配給根視圖,從而可以清除每個輸入字段的焦點並防止輸入字段獲得對活動啟動的關注(使內容視圖成為“焦點捕捉器”):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final View view = findViewById(R.id.content);
view.setFocusable(true);
view.setFocusableInTouchMode(true);
}
而不是遍歷所有視圖或覆蓋 dispatchTouchEvent。
為什么不直接覆蓋 Activity 的 onUserInteraction() 這將確保當用戶在 EditText 之外點擊時鍵盤會消失。
即使 EditText 在滾動視圖內也可以工作。
@Override
public void onUserInteraction() {
if (getCurrentFocus() != null) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
在 kotlin 中,我們可以執行以下操作。 無需迭代所有視圖。 它也適用於片段。
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
currentFocus?.let {
val imm: InputMethodManager = getSystemService(
Context.INPUT_METHOD_SERVICE
) as (InputMethodManager)
imm.hideSoftInputFromWindow(it.windowToken, 0)
}
return super.dispatchTouchEvent(ev)
}
我喜歡調用 htafoya 制作的dispatchTouchEvent
的方法,但是:
所以,我做了這個更簡單的解決方案:
@Override
public boolean dispatchTouchEvent(final MotionEvent ev) {
// all touch events close the keyboard before they are processed except EditText instances.
// if focus is an EditText we need to check, if the touchevent was inside the focus editTexts
final View currentFocus = getCurrentFocus();
if (!(currentFocus instanceof EditText) || !isTouchInsideView(ev, currentFocus)) {
((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
return super.dispatchTouchEvent(ev);
}
/**
* determine if the given motionevent is inside the given view.
*
* @param ev
* the given view
* @param currentFocus
* the motion event.
* @return if the given motionevent is inside the given view
*/
private boolean isTouchInsideView(final MotionEvent ev, final View currentFocus) {
final int[] loc = new int[2];
currentFocus.getLocationOnScreen(loc);
return ev.getRawX() > loc[0] && ev.getRawY() > loc[1] && ev.getRawX() < (loc[0] + currentFocus.getWidth())
&& ev.getRawY() < (loc[1] + currentFocus.getHeight());
}
有一個缺點:
從一個EditText
切換到另一個EditText
會使鍵盤隱藏並重新顯示 - 在我的情況下,這是需要的,因為它表明您在兩個輸入組件之間切換。
懇求:我承認我沒有影響力,但請認真對待我的回答。
問題:當點擊離開鍵盤或用最少的代碼編輯文本時關閉軟鍵盤。
解決方案:稱為Butterknife 的外部庫。
一條線解決方案:
@OnClick(R.id.activity_signup_layout) public void closeKeyboard() { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }
更具可讀性的解決方案:
@OnClick(R.id.activity_signup_layout)
public void closeKeyboard() {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
說明:將 OnClick 偵聽器綁定到活動的 XML 布局父 ID,以便對布局的任何點擊(而不是在編輯文本或鍵盤上)將運行將隱藏鍵盤的代碼片段。
示例:如果您的布局文件是 R.layout.my_layout 並且您的布局 id 是 R.id.my_layout_id,那么您的 Butterknife 綁定調用應如下所示:
(@OnClick(R.id.my_layout_id)
public void yourMethod {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
Butterknife 文檔鏈接:http: //jakewharton.github.io/butterknife/
Plug: Butterknife 將徹底改變您的 android 開發。 考慮一下。
注意:不使用外部庫 Butterknife 也可以達到相同的結果。 如上所述,只需將 OnClickListener 設置為父布局。
它太簡單了,只需通過以下代碼使您最近的布局可點擊成為焦點:
android:id="@+id/loginParentLayout"
android:clickable="true"
android:focusableInTouchMode="true"
然后為該布局編寫一個方法和一個 OnClickListner ,這樣當觸摸最上面的布局時,它會調用一個方法,您將在其中編寫代碼以關閉鍵盤。 以下是兩者的代碼; // 你必須在 OnCreate() 中寫這個
yourLayout.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
hideKeyboard(view);
}
});
從偵聽器調用的方法:-
public void hideKeyboard(View view) {
InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
這是 fje 答案的另一個變體,它解決了 sosite 提出的問題。
這里的想法是在 Activity 的dispatchTouchEvent
方法中同時處理 down 和 up 動作。 在向下操作中,我們記下當前聚焦的視圖(如果有)以及觸摸是否在其中,將這兩個信息都保存下來以備后用。
在 up 動作上,我們首先調度,以允許另一個視圖潛在地獲得焦點。 如果在那之后,當前聚焦的視圖是最初聚焦的視圖,並且向下觸摸在該視圖內,那么我們讓鍵盤保持打開狀態。
如果當前聚焦的視圖與最初聚焦的視圖不同並且它是一個EditText
,那么我們也讓鍵盤保持打開狀態。
否則我們關閉它。
因此,總而言之,它的工作原理如下:
EditText
內觸摸時,鍵盤保持打開狀態EditText
移動到另一個EditText
時,鍵盤保持打開狀態(不關閉/重新打開)EditText
之外的任何地方時,不是另一個EditText
,鍵盤關閉EditText
以調出上下文操作欄(使用剪切/復制/粘貼按鈕)時,鍵盤保持打開狀態,即使 UP 操作發生在焦點EditText
之外(向下移動以為出租車)。 但請注意,當您點擊 CAB 中的按鈕時,它將關閉鍵盤。 這可能是可取的,也可能不是可取的; 如果您想從一個字段剪切/復制並粘貼到另一個字段,那就是。 如果您想粘貼回相同的EditText
,則不會。 當聚焦的EditText
位於屏幕底部並且您長按某些文本以選擇它時, EditText
會保持焦點,因此鍵盤會按您想要的方式打開,因為我們對“觸摸在視圖范圍內”進行了檢查向下動作,而不是向上動作。
private View focusedViewOnActionDown; private boolean touchWasInsideFocusedView; @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: focusedViewOnActionDown = getCurrentFocus(); if (focusedViewOnActionDown != null) { final Rect rect = new Rect(); final int[] coordinates = new int[2]; focusedViewOnActionDown.getLocationOnScreen(coordinates); rect.set(coordinates[0], coordinates[1], coordinates[0] + focusedViewOnActionDown.getWidth(), coordinates[1] + focusedViewOnActionDown.getHeight()); final int x = (int) ev.getX(); final int y = (int) ev.getY(); touchWasInsideFocusedView = rect.contains(x, y); } break; case MotionEvent.ACTION_UP: if (focusedViewOnActionDown != null) { // dispatch to allow new view to (potentially) take focus final boolean consumed = super.dispatchTouchEvent(ev); final View currentFocus = getCurrentFocus(); // if the focus is still on the original view and the touch was inside that view, // leave the keyboard open. Otherwise, if the focus is now on another view and that view // is an EditText, also leave the keyboard open. if (currentFocus.equals(focusedViewOnActionDown)) { if (touchWasInsideFocusedView) { return consumed; } } else if (currentFocus instanceof EditText) { return consumed; } // the touch was outside the originally focused view and not inside another EditText, // so close the keyboard InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow( focusedViewOnActionDown.getWindowToken(), 0); focusedViewOnActionDown.clearFocus(); return consumed; } break; } return super.dispatchTouchEvent(ev); }
對於這個簡單的要求,我發現接受的答案有點復雜。 這對我有用,沒有任何故障。
findViewById(R.id.mainLayout).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
return false;
}
});
這對我來說是最簡單的解決方案(並且由我制定)。
這是隱藏鍵盤的方法。
public void hideKeyboard(View view){
if(!(view instanceof EditText)){
InputMethodManager inputMethodManager=(InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
}
}
現在將活動的父布局的 onclick 屬性設置為上述方法hideKeyboard
從 XML 文件的設計視圖或在 XML 文件的文本視圖中編寫以下代碼。
android:onClick="hideKeyboard"
有一種更簡單的方法,基於 iPhone 相同的問題。 只需在包含編輯文本的觸摸事件上覆蓋背景的布局。 只需在活動的 OnCreate 中使用此代碼(login_fondo 是根布局):
final LinearLayout llLogin = (LinearLayout)findViewById(R.id.login_fondo);
llLogin.setOnTouchListener(
new OnTouchListener()
{
@Override
public boolean onTouch(View view, MotionEvent ev) {
InputMethodManager imm = (InputMethodManager) mActivity.getSystemService(
android.content.Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mActivity.getCurrentFocus().getWindowToken(), 0);
return false;
}
});
顯示/隱藏軟鍵盤的方法
InputMethodManager inputMethodManager = (InputMethodManager) currentActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
if (isShow) {
if (currentActivity.getCurrentFocus() == null) {
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
} else {
inputMethodManager.showSoftInput(currentActivity.getCurrentFocus(), InputMethodManager.SHOW_FORCED);
}
} else {
if (currentActivity.getCurrentFocus() == null) {
inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);
} else {
inputMethodManager.hideSoftInputFromInputMethod(currentActivity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
我希望它們有用
我在 Fernando Camarago 的解決方案上做了一個小改動。 在我的 onCreate 方法中,我將單個 onTouchListener 附加到根視圖,但將視圖而不是活動作為參數發送。
findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
Utils.hideSoftKeyboard(v);
return false;
}
});
在一個單獨的 Utils 類中是......
public static void hideSoftKeyboard(View v) {
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
我已經這樣做了:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
View view = getCurrentFocus();
if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) {
int scrcoords[] = new int[2];
view.getLocationOnScreen(scrcoords);
float x = ev.getRawX() + view.getLeft() - scrcoords[0];
float y = ev.getRawY() + view.getTop() - scrcoords[1];
if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom())
hideKeyboard(this);
}
return super.dispatchTouchEvent(ev);
}
隱藏鍵盤代碼:
public static void hideKeyboard(Activity act) {
if(act!=null)
((InputMethodManager)act.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((act.getWindow().getDecorView().getApplicationWindowToken()), 0);
}
完畢
要解決此問題,您必須首先使用該 Edittext 的 setOnFocusChangeListener
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
Log.d("focus", "focus loosed");
// Do whatever you want here
} else {
Log.d("focus", "focused");
}
}
});
然后你需要做的是在包含 Edittext 的活動中覆蓋 dispatchTouchEvent 見下面的代碼
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if ( v instanceof EditText) {
Rect outRect = new Rect();
v.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
Log.d("focus", "touchevent");
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(event);
}
現在會發生什么,當用戶點擊外部時,首先會調用這個 dispatchTouchEvent,然后會從editext中清除焦點,現在你的 OnFocusChangeListener 將被調用,焦點已經改變,現在在這里你可以做任何你想做的事情,希望它能工作
我已經改進了該方法,將以下代碼放在一些 UI 實用程序類中(最好,不一定),以便可以從所有 Activity 或 Fragment 類訪問它以達到其目的。
public static void serachAndHideSoftKeybordFromView(View view, final Activity act) {
if(!(view instanceof EditText)) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard(act);
return false;
}
});
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View nextViewInHierarchy = ((ViewGroup) view).getChildAt(i);
serachAndHideSoftKeybordFromView(nextViewInHierarchy, act);
}
}
}
public static void hideSoftKeyboard (Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
然后說比如你需要從activity中調用它,調用方式如下;
UIutils.serachAndHideSoftKeybordFromView(findViewById(android.R.id.content), YourActivityName.this);
注意
findViewById(android.R.id.content)
這為我們提供了當前組的根視圖(您不能在根視圖上設置 id)。
干杯:)
嘗試將 stateHidden 作為您的活動windowSoftInputMode
值
http://developer.android.com/reference/android/R.attr.html#windowSoftInputMode
例如對於您的活動:
this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
活動
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
ScreenUtils.hideKeyboard(this, findViewById(android.R.id.content).getWindowToken());
return super.dispatchTouchEvent(ev);
}
屏幕工具
public static void hideKeyboard(Context context, IBinder windowToken) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS);
}
只需在 @Overide 類中添加此代碼
public boolean dispatchTouchEvent(MotionEvent ev) {
View view = getCurrentFocus();
if (view != null && (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_MOVE) && view instanceof EditText && !view.getClass().getName().startsWith("android.webkit.")) {
int scrcoords[] = new int[2];
view.getLocationOnScreen(scrcoords);
float x = ev.getRawX() + view.getLeft() - scrcoords[0];
float y = ev.getRawY() + view.getTop() - scrcoords[1];
if (x < view.getLeft() || x > view.getRight() || y < view.getTop() || y > view.getBottom())
((InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((this.getWindow().getDecorView().getApplicationWindowToken()), 0);
}
return super.dispatchTouchEvent(ev);
}
您可以實現 View.onClickListener 並覆蓋 onClick 方法並將此 onclicklistener 設置為布局
ConstraintLayout constraintLayout;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = findViewById(R.id.layout);
constraintLayout.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v.getId()==R.id.layout){
InputMethodManager inm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
inm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
}
}
這可能很舊,但我通過實現一個自定義類來完成這個工作
public class DismissKeyboardListener implements OnClickListener {
Activity mAct;
public DismissKeyboardListener(Activity act) {
this.mAct = act;
}
@Override
public void onClick(View v) {
if ( v instanceof ViewGroup ) {
hideSoftKeyboard( this.mAct );
}
}
}
public void hideSoftKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager)
getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
}
這里的最佳實踐是創建一個 Helper 類,並且每個容器相對/線性布局都應該實現它。
****注意只有主容器應該實現這個類(用於優化)****
並像這樣實現它:
Parent.setOnClickListener( new DismissKeyboardListener(this) );
這是用於活動的關鍵字。 所以如果你在片段上,你可以使用 getActivity();
---如果對您有幫助,請豎起大拇指... --- 歡呼拉爾夫 ---
這是 fje 答案的一個稍微修改過的版本,大部分工作都很完美。
此版本使用 ACTION_DOWN,因此執行滾動操作也會關閉鍵盤。 除非您單擊另一個 EditText,否則它也不會傳播該事件。 這意味着點擊 EditText 之外的任何地方,即使是在另一個可點擊的地方,也會簡單地關閉鍵盤。
@Override
public boolean dispatchTouchEvent(MotionEvent ev)
{
if(ev.getAction() == MotionEvent.ACTION_DOWN)
{
final View view = getCurrentFocus();
if(view != null)
{
final View viewTmp = getCurrentFocus();
final View viewNew = viewTmp != null ? viewTmp : view;
if(viewNew.equals(view))
{
final Rect rect = new Rect();
final int[] coordinates = new int[2];
view.getLocationOnScreen(coordinates);
rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight());
final int x = (int) ev.getX();
final int y = (int) ev.getY();
if(rect.contains(x, y))
{
super.dispatchTouchEvent(ev);
return true;
}
}
else if(viewNew instanceof EditText || viewNew instanceof CustomEditText)
{
super.dispatchTouchEvent(ev);
return true;
}
final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0);
viewNew.clearFocus();
return true;
}
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.
INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
return true;
}
好吧,您可以使用此代碼,使用您的主布局 ID 而不是“mainRelativeLayout”
//hide Soft keyboard on click outside the input text
findViewById(R.id.mainRelativeLayout).setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
InputMethodManager im = (InputMethodManager)
getSystemService(INPUT_METHOD_SERVICE);
im.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
0);
}
});
我稍微修改了答案@navneeth-g,增加了空活動焦點處理,避免了多個實例創建OnTouchListener,鍵盤隱藏時移除焦點,屏幕滾動時移除隱藏鍵盤,在小型設備上方便。
//In general, the view parameter is root layout
fun Activity.hideKeyboardOnClickOutsideEditText(view: View) {
// Set up touch listener for non-text box views to hide keyboard.
var previousAction = 0
val onTouchListener = View.OnTouchListener { v, event ->
if (currentFocus != null
&& event.action != MotionEvent.ACTION_DOWN
&& event.action != MotionEvent.ACTION_MOVE
&& previousAction != MotionEvent.ACTION_MOVE
) {
currentFocus?.clearFocus()
v?.hideKeyboard()
}
previousAction = event.action
false
}
if (view !is EditText) {
view.setOnTouchListener(onTouchListener)
}
//If a layout container, iterate over children and seed recursion.
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val innerView = view.getChildAt(i)
hideKeyboardOnClickOutsideEditText(innerView)
}
}
}
//in root layout.xml
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
非常困難的決定。 我建議一個更簡單的解決方案。 在 onViewCreated 中,我們為整個 View 設置了一個 setOnClickListener 並從 EditText 中移除焦點,以及移除鍵盤。
片段中的示例。 爪哇。
@Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
nameTextInputEditText = view.findViewById(R.id.NameTextInputEditText);
view.setOnClickListener(v -> {
nameTextInputEditText.clearFocus();
InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
});
}
您可以輕松地覆蓋活動和片段中的 onKey() 事件以隱藏鍵盤。
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (keyCode == event.KEYCODE_ENTER) {
intiateLoginProcess();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindow().getCurrentFocus()
.getWindowToken(), 0);
return true;
}
}
return false;
}
嘿伙計們,我有這個問題的簡單解決方案,這個解決方案可用於簡單的注冊或登錄表單。 我的解決方案與我在 ios setontouch 監聽器中實現的主視圖相同
activity_main.xml 將 ID 添加到您的主要相對布局android:id="@+id/mainlayout"
並將此代碼添加到您的活動中
RelativeLayout mainLayout = (RelativeLayout)findViewById(R.id.mainlayout);
mainLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
Log.d("Json Response", "Touch outside");
InputMethodManager inputMethodManager = (InputMethodManager) MainActivity.this.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(MainActivity.this.getCurrentFocus().getWindowToken(), 0);
return false;
}
});
我想到了這個問題。 首先,我認為 setOnTouchListener 不是簡單的解決方案。 所以我相信 dispatchTouchEvent 是最好的簡單解決方案。
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
View v = getCurrentFocus();
if (v instanceof EditText) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
return super.dispatchKeyEvent(event);
}
在這里,一個重要的是ACTION_UP。
我假設 EditText 只顯示軟鍵盤,否則不顯示鍵盤。 我在 Android5.0.1(LG 的 G3.cat6)上測試過。
如果您需要拖動檢查,長按,...,請在上面顯示評論。
我的解決方案在任何活動中隱藏外部點擊鍵盤,以及所有編輯文本。 沒有一一指定。
首先添加到布局xml的根視圖: android:clickable="true" android:focusableInTouchMode="true"
接下來,為所有要隱藏鍵盤的活動創建一個父 Acitvity,並指定 onResume() 方法:
@Override
protected void onResume() {
super.onResume();
//getting Root View that gets focus
View rootView =((ViewGroup)findViewById(android.R.id.content)).
getChildAt(0);
rootView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
hideKeyboard(AbstractActivity.this);
}
}
});
}
使用此通用活動(繼承能力!)擴展您的活動,僅此而已,每次任何 EditText(在任何擴展活動上)失去焦點時,鍵盤將被隱藏。
PS hideKeyboard 方法:
public static void hideKeyboard(Activity context) {
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow( context.getCurrentFocus().getWindowToken(), 0);
}
context.getCurrentFocus() 不需要指定特定的 EditText 視圖..
你可以試試下面的方法,它對我很有用:)
這種方式可以應用於Activity或者Fragment,也兼容ScrollView。
我們把 ScrollView 作為頂層布局,在里面為 LinearLayout 聲明 id parentView 並添加如下兩個屬性:
android:id="@+id/parentView"
android:clickable="true"
android:focusableInTouchMode="true"
在代碼中,編寫如下函數:
public static void hideSoftKeyboard (Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
然后為根視圖注冊一個 OnFocusChangeListener (寫入 onCreate 方法),使 Activity 中的所有 EditText 受到影響:
parentLayout.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
hideSoftKeyboard(your_activity_name.this);
}
}
});
我設法從onItemClick
AutoCompleteTextView
內部隱藏了鍵盤
public void onItemClick(AdapterView<?> adapterViewIn, View viewIn, int indexSelected, long arg3) {
InputMethodManager imm = (InputMethodManager) getSystemService(viewIn.getContext().INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(viewIn.getApplicationWindowToken(), 0);
// your code HERE
}
其他想法是在您的 Activity 的根視圖上覆蓋onInterceptTouchEvent
方法。
觸摸事件從屏幕上最前面的視圖(觸摸事件發生的地方)向下傳遞到調用onTouch
方法的視圖堆棧,直到任何視圖返回 true,表示觸摸事件已被使用。 由於許多視圖默認使用觸摸事件(例如EditText
或TextView
的情況),因此事件不會到達 Activity 的根視圖onTouch
方法。
但是,在進行此遍歷之前,觸摸事件會經過另一條路徑,從根視圖沿着視圖樹向下直到到達最前面的視圖。 這個遍歷是通過調用onInterceptTouchEvent
來完成的。 如果該方法返回 true,它會攔截事件……不,但這有點小技巧,我認為您不想這樣做,也不想知道細節。 您需要知道的是,您可以在 Activity 的根視圖上覆蓋此方法,並在必要時將代碼放在那里隱藏鍵盤。
添加到@smit sonawane 的先前答案,如果用戶正在滾動,此解決方案將不會隱藏鍵盤。
public long pressTime = 0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
pressTime = System.currentTimeMillis();
}
else if (ev.getAction() == MotionEvent.ACTION_UP) {
long releaseTime = System.currentTimeMillis();
if (releaseTime-pressTime < 200) {
if (getCurrentFocus() != null) {
GhostTube.print("BottomNavActivity", "Touch event with keyboard detected...");
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(ev);
}
將代碼添加到您的活動中,也會處理片段。
唯一有效的代碼
private var viewHeight = 0
private fun setRootViewListener() {
binding.root.apply {
viewTreeObserver.addOnGlobalLayoutListener {
viewHeight = height
}
}
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
currentFocus?.let {
if (it is EditText && event.y < viewHeight - it.measuredHeight) {
hideKeyboard(it)
}
}
return super.dispatchTouchEvent(event)
}
對於那些正在為此尋找 Xamarin 代碼的人,請點擊此處:
public override bool DispatchTouchEvent(MotionEvent ev)
{
try
{
View view = CurrentFocus;
if (view != null && (ev.Action == MotionEventActions.Up || ev.Action == MotionEventActions.Move) && view is EditText && !view.Class.Name.StartsWith("android.webkit."))
{
int[] Touch = new int[2];
view.GetLocationOnScreen(Touch);
float x = ev.RawX + view.Left - Touch[0];
float y = ev.RawY + view.Top - Touch[1];
if (x < view.Left || x > view.Right || y < view.Top || y > view.Bottom)
((InputMethodManager)GetSystemService(InputMethodService)).HideSoftInputFromWindow((Window.DecorView.ApplicationWindowToken), 0);
}
}
catch (System.Exception ex)
{
}
return base.DispatchTouchEvent(ev);
}
轉到 Manifest 並在活動中寫入:android:windowSoftInputMode="stateHidden",就像這樣
<activity
android:name=".MainActivity"
android:exported="false"
android:windowSoftInputMode="stateHidden" />
我有這個問題的簡單解決方案:
InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
setupUI((RelativeLayout) findViewById(R.id.activity_logsign_up_RelativeLayout));
將該方法傳遞到您的布局文件中。 您必須選擇 XML 格式的通用布局文件。 因為,鍵盤隱藏適用於整個布局。
public void setupUI(View view) {
// Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText)) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard(Your Context); // Pass your context
return false;
}
});
}
//If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.