Programming

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

procodes 2020. 3. 5. 08:01
반응형

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


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

  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 바로 아래의보기에 추가 될 수 있습니다.


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

여기 내 해결책이 있습니다. 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. 소프트 키보드가 강제로 닫힙니다.


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

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

글쎄, 나는 다소 문제를 해결하고, 활동에 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 외부에 있으면 키보드를 숨 깁니다.


이를 위해 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);
}

나는 그것을 테스트하고 완벽하게 작동합니다!


모든 활동에서 공개 부울 dispatchTouchEvent (MotionEvent 이벤트)를 대체하거나 활동 클래스를 확장하십시오.

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

그리고 그게 당신이해야 할 전부입니다


코 틀린재질 디자인 사용 방법 TextInputEditText (이 방법은과도 호환 EditTextView ) ...

1. 다음 속성을 추가하여 상위 뷰 (활동 / 조각의 컨텐츠 뷰)를 클릭하고 초점을 맞 춥니 다.

android:focusable="true"
android:focusableInTouchMode="true"
android:clickable="true"

2. 모든 View의 확장명을 만듭니다 (예 : 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> 

그게 다야. 이 반복적 인 사례를 처리하기 위해 컨트롤러 (조각 또는 활동) 를 수정할 필요가 없습니다 .


이 스레드가 상당히 오래되었다는 것을 알고 있습니다. 정답은 유효하고 많은 해결책이 있지만, 아래에 언급 된 접근법은 효율성과 우아함에 대해 추가 이점이있을 수 있습니다.

모든 활동에 대해이 동작이 필요하므로 Activity 클래스에서 상속되는 CustomActivity 클래스를 작성 하고 dispatchTouchEvent 함수를 "후크"했습니다 . 주의해야 할 두 가지 조건이 있습니다.

  1. 포커스가 변경되지 않고 누군가 현재 입력 필드 외부를 두드리면 IME를 해제하십시오.
  2. 포커스가 변경되고 다음 포커스 요소가 입력 필드의 인스턴스가 아닌 경우 IME를 해제하십시오.

이것은 내 결과입니다.

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

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

나는 dispatchTouchEventhtafoya 의 전화 접근 방식이 마음에 들었습니다 .

  • 타이머 부분을 이해하지 못했습니다 (정지 시간을 측정 해야하는 이유를 모르십니까?)
  • 모든보기 변경마다 모든 EditText를 등록 / 등록 취소하고 싶지 않습니다 (복잡한 계층 구조에서 많은 viewchanges 및 edittext 일 수 있음)

따라서이 다소 쉬운 솔루션을 만들었습니다.

@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 인 경우 버터 나이프 바인드 호출은 다음과 같아야합니다.

(@OnClick(R.id.my_layout_id) 
public void yourMethod {
    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}

버터 나이프 문서 링크 : http://jakewharton.github.io/butterknife/

플러그 : 버터 나이프는 안드로이드 개발에 혁명을 일으킬 것입니다. 생각해 봐.

참고 : 외부 라이브러리 Butterknife를 사용하지 않고도 동일한 결과를 얻을 수 있습니다. 위에서 설명한대로 OnClickListener를 상위 레이아웃으로 설정하십시오.


다음은 사이트에서 제기 된 문제를 해결하는 fje의 답변에 대한 또 다른 변형입니다.

여기서 아이디어는 활동 dispatchTouchEvent방법 에서 아래로 및 위로 작업을 모두 처리 하는 것입니다. 다운 액션에서는 현재 포커스가있는 뷰 (있는 경우)와 터치가 내부에 있는지 여부를 기록하여 나중에 정보 비트를 모두 저장합니다.

우리는 먼저 다른 조치에 초점을 맞출 수 있도록 조치를 취합니다. 그 후에 현재 포커스가있는 뷰가 원래 포커스 된 뷰이고 아래쪽 터치가 해당 뷰 안에있는 경우 키보드를 열어 둡니다.

현재 포커스 뷰가 원래 뷰를 초점을 맞추고 다른 경우 그것이이다 EditText, 우리는 열려있는 키보드를 둡니다.

그렇지 않으면 우리는 그것을 닫습니다.

요약하면 다음과 같이 작동합니다.

  • 현재 포커스 EditText가있는 내부를 만지면 키보드는 열린 상태를 유지합니다
  • 포커스 EditText에서 다른 포커스 이동할 때 EditText키보드는 열린 상태를 유지합니다 (닫거나 다시 열지 않음)
  • 현재 초점 EditText이 아닌 다른 곳을 터치 EditText하면 키보드가 닫힙니다.
  • EditText상황에 맞는 작업 표시 줄 (잘라 내기 / 복사 / 붙여 넣기 단추 사용)을 표시하기 위해 길게 누르면 키보드가 열려 있습니다 (UP 작업이 초점을 벗어난 위치 EditText(CAB를위한 공간을 만들기 위해 아래로 이동)). . 그러나 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);
    }
    

이 코드로 최근 레이아웃을 클릭 가능하게 만들 수 있습니다.

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

listner에서 호출 된 메소드 :-

 public void hideKeyboard(View view) {
     InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }

이 간단한 요구 사항에 대해 허용되는 답변 비트가 복잡하다는 것을 알았습니다. 결함없이 나를 위해 일한 것은 다음과 같습니다.

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

소프트 키보드 표시 / 숨기기 방법

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

    }

나는 그들이 유용했으면 좋겠다.


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

나는 메소드를 세분화하고, 일부 UI 유틸리티 클래스 (바람직하게는 아니지만)에 다음 코드를 넣어 모든 활동 또는 프래그먼트 클래스에서 액세스하여 목적을 달성 할 수 있도록합니다.

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

그런 다음 예를 들어 활동에서 호출해야한다고 말하고 다음과 같이 호출하십시오.

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

ScreenUtils

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

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

이것은 오래되었지만 사용자 정의 클래스를 임박 하여이 작업을 수행했습니다.

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 클래스를 만드는 것이며 모든 컨테이너 Relative / Linear Layouts는이를 구현해야합니다.

**** 메인 컨테이너 만이 클래스를 구현해야합니다 (최적화) ****

다음과 같이 구현하십시오.

Parent.setOnClickListener( new DismissKeyboardListener(this) ); 

활동에 대한 키워드입니다. 그래서 조각에 있다면 getActivity ()와 같이 사용하십시오.

--- 엄청나게 도와 주면 ... --- Ralph를 응원합니다 ---


이것은 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 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");
                }
            }
        });

그런 다음 편집 텍스트가 포함 된 활동에서 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가 포커스가 변경되었다고 호출됩니다. 여기서 원하는 작업을 수행 할 수 있습니다.


@Override
    public boolean onTouchEvent(MotionEvent event) {
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.
                INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
        return true;
    }

이 코드를 사용할 수 있습니다. "mainRelativeLayout"대신 기본 레이아웃 ID를 사용하십시오.

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

    });

참고 URL : https://stackoverflow.com/questions/4165414/how-to-hide-soft-keyboard-on-android-after-clicking-outside-edittext



반응형