[android] EditText 외부를 클릭 한 후 안드로이드에서 소프트 키보드를 숨기는 방법은 무엇입니까?

누구나 키보드를 숨기려면 구현해야한다는 것을 모두 알고 있습니다.

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);

그러나 여기서 가장 중요한 것은 사용자가 소프트 키보드가 아닌 다른 장소를 만지거나 선택할 때 키보드를 숨기는 방법입니다 EditText.

onTouchEvent()부모님 을 사용하려고했지만 Activity사용자가 다른보기 외부를 만지고 스크롤보기가없는 경우에만 작동합니다.

나는 터치, 클릭, 포커스 리스너를 성공없이 구현하려고했습니다.

터치 이벤트를 가로 채기 위해 자체 스크롤보기를 구현하려고했지만보기를 클릭하지 않고 이벤트의 좌표 만 가져올 수 있습니다.

이것을 수행하는 표준 방법이 있습니까 ?? iPhone에서는 정말 쉬웠습니다.



답변

다음 스 니펫은 단순히 키보드를 숨 깁니다.

public static void hideSoftKeyboard(Activity activity) {
    InputMethodManager inputMethodManager =
        (InputMethodManager) activity.getSystemService(
            Activity.INPUT_METHOD_SERVICE);
    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하고이 메소드를 삽입하고 애플리케이션의 다른 모든 활동이이 활동을 확장 setupUI()하고 onCreate()메소드 에서 호출하도록 할 수 있습니다.

도움이 되길 바랍니다.

둘 이상의 활동을 사용하는 경우 공통 ID를 상위 레이아웃에 정의하십시오.
<RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>

그런 다음 클래스를 확장하고 클래스 내 에서 Activity정의 하고“활동 대신이 클래스를 확장하십시오.setupUI(findViewById(R.id.main_parent))OnResume()in your program


위 함수의 Kotlin 버전은 다음과 같습니다.

@file:JvmName("KeyboardUtils")

fun Activity.hideSoftKeyboard() {
    currentFocus?.let {
        val inputMethodManager = ContextCompat.getSystemService(this, InputMethodManager::class.java)!!
        inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0)
    }
}


답변

다음 단계를 수행하여이를 달성 할 수 있습니다.

  1. 다음 속성을 추가하여 상위보기 (활동의 컨텐츠보기)를 클릭 가능하고 집중 가능하게하십시오.

        android:clickable="true"
        android:focusableInTouchMode="true" 
  2. hideKeyboard () 메소드 구현

        public void hideKeyboard(View view) {
            InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
  3. 마지막으로 편집 텍스트의 onFocusChangeListener를 설정하십시오.

        edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus) {
                    hideKeyboard(v);
                }
            }
        });

아래 주석 중 하나에서 지적했듯이 부모보기가 ScrollView 인 경우 작동하지 않을 수 있습니다. 이러한 경우 클릭 가능 및 포커스 가능 InTouchMode가 ScrollView 바로 아래의보기에 추가 될 수 있습니다.


답변

활동에서 아래 코드를 재정의하십시오.

 @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);
}


답변

수락 된 답변이 약간 복잡하다는 것을 알았습니다.

여기 내 해결책이 있습니다. 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);

여기서 전달 HIDE_IMPLICIT_ONLY의 위치 showFlag0의 위치 hiddenFlag. 소프트 키보드가 강제로 닫힙니다.


답변

글쎄, 나는 다소 문제를 해결하고, 활동에 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 () 메서드는보기에서 텍스트 필드가있는 배열을 반환하는 메서드 일뿐입니다. 터치 할 때마다이 배열을 만들지 않기 위해 getFields () 메서드에서 반환되는 sFields라는 정적 배열을 만들었습니다. 이 배열은 다음과 같은 onStart () 메소드에서 초기화됩니다.

sFields = new EditText[] {mUserField, mPasswordField};


완벽하지는 않습니다. 드래그 이벤트 시간은 휴리스틱에만 기반하기 때문에 긴 성직자를 수행 할 때 숨기지 않는 경우가 많으며 뷰당 모든 editText를 가져 오는 방법도 작성했습니다. 그렇지 않으면 다른 EditText를 클릭 할 때 키보드가 숨겨져 표시됩니다.

더 깨끗하고 짧은 솔루션은 환영합니다


답변

OnFocusChangeListener를 사용하십시오 .

예를 들면 다음과 같습니다.

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
            hideKeyboard();
        }
    }
});

업데이트 : onTouchEvent()활동을 재정의 하고 터치 좌표를 확인할 수도 있습니다 . 좌표가 EditText 외부에 있으면 키보드를 숨 깁니다.