IT

EditText, 외부 터치에 대한 명확한 증가

lottoking 2020. 9. 8. 08:15
반응형

EditText, 외부 터치에 대한 명확한 증가


내 레이아웃에는 ListView, SurfaceViewEditText. 를 클릭하면 EditText포커스를 받고 화상 키보드가 나타납니다. 외부 어딘가를 클릭 EditText해도 여전히 포커스가 있습니다 (안됨). OnTouchListener레이아웃의 다른 뷰에서의 설정하고 EditText의 포커스를 수동으로 지울 수있는 생각 합니다. 하지만 너무 끔찍해 보이네요 ...

다른 레이아웃 동일한 상황이 발생합니다. 다른 유형의 항목이있는 목록보기 중 일부는 EditText내부에 '가 있습니다. 위에서 쓴 것처럼 행동합니다.

작업은 사용자가 외부의 작업 만질 EditText때 점점 늘어나는 것을 잃게 만드는 것입니다.

여기에서 질문을 질문을 제안하지만 해결책을 찾습니다 ...


이 모든 솔루션을 시도했습니다. edc598은 작동에 가장 가깝지만 터치 이벤트는 View레이아웃에 포함 된 다른 것에서 찾을 수 없습니다 . 누군가가 행동이 필요한 경우, 이것이 내가 한 일입니다.

나는 (보이지 않는) 생성 FrameLayout이라는 touchInterceptor 마지막 으로을 View은 모든 기계 그래서 레이아웃에 ( 편집 : 당신은 또한 사용할 필요가 RelativeLayout부모 레이아웃으로와 줄 touchInterceptor의 fill_parent 특성). 그런 다음 터치를 차단하고 터치가 맨 위에 있는지 여부를 결정하는 데 사용했습니다 EditText.

FrameLayout touchInterceptor = (FrameLayout)findViewById(R.id.touchInterceptor);
touchInterceptor.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (mEditText.isFocused()) {
                Rect outRect = new Rect();
                mEditText.getGlobalVisibleRect(outRect);
                if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
                    mEditText.clearFocus();
                    InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
        }
        return false;
    }
});

터치 처리가 실패하면 거짓을 반환합니다.

그것은 해키이지만 나에게 일한 유일한 것입니다.


Ken의 답변을 바탕으로 가장 모듈화 된 복사 및 가져 오기 솔루션이 있습니다.

XML이 필요하지 않습니다.

그것을 당신의 활동에 포함되는 활동의 조각을 포함하여 모든 EditText에 적용됩니다.

@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())) {
                v.clearFocus();
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent( event );
}

글고의 상위 뷰에 대해 클릭 , 포커스 , focusableIn TouchMode를의 3 가지 속성을 " 진정한 "설정로 합니다.

다음 3 가지 조건을 참석해야합니다.

android.view 참조 :

public boolean onTouchEvent(MotionEvent event) {
    ...
    if (((viewFlags & CLICKABLE) == CLICKABLE || 
        (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
        ...
        if (isFocusable() && isFocusableInTouchMode()
            && !isFocused()) {
                focusTaken = requestFocus();
        }
        ...
    }
    ...
}

도움이되기를 바랍니다.


이 속성을 최상위 상위 항목에 등록하십시오.

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

Ken의 대답은 작동하지만 해키입니다. pcans가 답변의 주석에서 언급했듯이 dispatchTouchEvent를 수행 할 수 있습니다. 이 솔루션은 투명한 더미 FrameLayout으로 XML을 해킹하지 않고 더 깔끔합니다. 다음은 다음과 가변.

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    EditText mEditText = findViewById(R.id.mEditText);
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        View v = getCurrentFocus();
        if (mEditText.isFocused()) {
            Rect outRect = new Rect();
            mEditText.getGlobalVisibleRect(outRect);
            if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
                mEditText.clearFocus();
                //
                // Hide keyboard
                //
                InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent(event);
}

이미이 문제에 대한 답을 찾았습니다.이 문제를 해결하는 방법을 찾고 있었지만 여전히 내가 찾고있는 것을 정확히 파악할 수 있습니다 여기에 게시 할 생각했습니다.

내가 한 일은 다음과 같다 (이것은 매우 일반화되어있는 모든 코드를 복사하고 너에게 넣는 방법에 아이디어를 제공하는 것이 O : D 작동하지 않습니다) :

먼저 EditText 및 프로그램에서 원하는 다른 뷰를 단일 뷰로 래핑하십시오. 제 경우에는 LinearLayout을 사용하여 모든 것을 래핑했습니다.

<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/mainLinearLayout">
 <EditText
  android:id="@+id/editText"/>
 <ImageView
  android:id="@+id/imageView"/>
 <TextView
  android:id="@+id/textView"/>
 </LinearLayout>

그런 다음 코드에서 터치 리스너를 기본 LinearLayout으로 설정해야합니다.

final EditText searchEditText = (EditText) findViewById(R.id.editText);
mainLinearLayout.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            if(searchEditText.isFocused()){
                if(event.getY() >= 72){
                    //Will only enter this if the EditText already has focus
                    //And if a touch event happens outside of the EditText
                    //Which in my case is at the top of my layout
                    //and 72 pixels long
                    searchEditText.clearFocus();
                    InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
            Toast.makeText(getBaseContext(), "Clicked", Toast.LENGTH_SHORT).show();
            return false;
        }
    });

나는 이것이 어떤 사람들에게 도움이되기를 바랍니다. 또는 문제 해결을 시작하도록 지원합니다.


저를 위해 일한 것-

1. 추가 android:clickable="true"하고 android:focusableInTouchMode="true"받는 사람 parentLayoutEditTextandroid.support.design.widget.TextInputLayout

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:focusableInTouchMode="true">
<EditText
    android:id="@+id/employeeID"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:ems="10"
    android:inputType="number"
    android:hint="Employee ID"
    tools:layout_editor_absoluteX="-62dp"
    tools:layout_editor_absoluteY="16dp"
    android:layout_marginTop="42dp"
    android:layout_alignParentTop="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_marginRight="36dp"
    android:layout_marginEnd="36dp" />
    </android.support.design.widget.TextInputLayout>

2. Activity 클래스 재정의 dispatchTouchEventhideKeyboard()함수 삽입

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View view = getCurrentFocus();
            if (view != null && view instanceof EditText) {
                Rect r = new Rect();
                view.getGlobalVisibleRect(r);
                int rawX = (int)ev.getRawX();
                int rawY = (int)ev.getRawY();
                if (!r.contains(rawX, rawY)) {
                    view.clearFocus();
                }
            }
        }
        return super.dispatchTouchEvent(ev);
    }

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

3. EditText 추가setOnFocusChangeListener

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

난 정말이 사용하는 더 강력한 방법 생각 getLocationOnScreen보다 getGlobalVisibleRect. 문제가 발생했기 때문입니다. 일부 Edittext를 포함 ajustpan하고 활동에 설정된 Listview가 있습니다 . 내가 찾아 getGlobalVisibleRect거기에 scrollY하지만 event.getRawY 등 같은 외모가 화면에 의해 항상하는 값을 반환합니다. 아래 코드는 잘 작동합니다.

public boolean dispatchTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        View v = getCurrentFocus();
        if ( v instanceof EditText) {
            if (!isPointInsideView(event.getRawX(), event.getRawY(), v)) {
                Log.i(TAG, "!isPointInsideView");

                Log.i(TAG, "dispatchTouchEvent clearFocus");
                v.clearFocus();
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    }
    return super.dispatchTouchEvent( event );
}

/**
 * Determines if given points are inside view
 * @param x - x coordinate of point
 * @param y - y coordinate of point
 * @param view - view object to compare
 * @return true if the points are within view bounds, false otherwise
 */
private boolean isPointInsideView(float x, float y, View view) {
    int location[] = new int[2];
    view.getLocationOnScreen(location);
    int viewX = location[0];
    int viewY = location[1];

    Log.i(TAG, "location x: " + location[0] + ", y: " + location[1]);

    Log.i(TAG, "location xWidth: " + (viewX + view.getWidth()) + ", yHeight: " + (viewY + view.getHeight()));

    // point is inside view bounds
    return ((x > viewX && x < (viewX + view.getWidth())) &&
            (y > viewY && y < (viewY + view.getHeight())));
}

다음 EditText과 같이 부모의 두 속성을 정의하기 만하면 됩니다.

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

따라서 사용자가 EditText영역 외부를 터치 하면 포커스가 상위 뷰로 전환되므로 포커스가 제거됩니다.


다른 뷰를 터치했을 때 포커스를 잃으려면 두 뷰를 모두 view.focusableInTouchMode (true)로 설정해야합니다.

그러나 터치 모드에서 초점을 사용하는 것은 권장되지 않는 것 같습니다. 여기를보세요 : http://android-developers.blogspot.com/2008/12/touch-mode.html


나는 견해 ListView구성되어 EditText있습니다. 시나리오는 하나 이상의 행에서 텍스트를 편집 한 후 "마침"이라는 버튼을 클릭해야한다고 말합니다. 내부보기 onFocusChanged에서 사용 했지만 완료를 클릭하면 데이터가 저장되지 않습니다. 문제는 다음을 추가하여 해결되었습니다.EditTextlistView

listView.clearFocus();

내부 onClickListener"마침"버튼과 데이터를 성공적으로 저장되었습니다.


가장 좋은 방법은 기본 방법을 사용하는 것입니다. clearFocus()

코드를 onTouchListener올바르게 해결하는 방법을 알고 있습니까?

전화 만하세요 EditText.clearFocus(). 에서 초점이 명확 해 last EditText집니다.


@pcans가 제안했듯이 dispatchTouchEvent(MotionEvent event)활동 에서이 재정의 수행 할 수 있습니다 .

여기에서 터치 좌표를 얻고이를 뷰 경계와 비교합니다. 터치가 뷰 외부에서 수행되면 무언가를 수행하십시오.

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        View yourView = (View) findViewById(R.id.view_id);
        if (yourView != null && yourView.getVisibility() == View.VISIBLE) {
            // touch coordinates
            int touchX = (int) event.getX();
            int touchY = (int) event.getY();
            // get your view coordinates
            final int[] viewLocation = new int[2];
            yourView.getLocationOnScreen(viewLocation);

            // The left coordinate of the view
            int viewX1 = viewLocation[0];
            // The right coordinate of the view
            int viewX2 = viewLocation[0] + yourView.getWidth();
            // The top coordinate of the view
            int viewY1 = viewLocation[1];
            // The bottom coordinate of the view
            int viewY2 = viewLocation[1] + yourView.getHeight();

            if (!((touchX >= viewX1 && touchX <= viewX2) && (touchY >= viewY1 && touchY <= viewY2))) {

                Do what you want...

                // If you don't want allow touch outside (for example, only hide keyboard or dismiss popup) 
                return false;
            }
        }
    }
    return super.dispatchTouchEvent(event);
}

또한 활동의 ​​레이아웃이 런타임 중에 변경되지 않는 경우보기 존재 여부와 가시성을 확인할 필요가 없습니다 (예 : 레이아웃에서 조각을 추가하거나보기를 교체 / 제거하지 않음). 그러나 사용자 정의 컨텍스트 메뉴 (예 : 항목의 오버플로 메뉴를 사용할 때 Google Play 스토어에서)를 닫고 (또는 유사한 작업을 수행하려면)보기 존재 여부를 확인해야합니다. 그렇지 않으면 NullPointerException.


이 간단한 코드 조각은 원하는 작업을 수행합니다.

GestureDetector gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                KeyboardUtil.hideKeyboard(getActivity());
                return true;
            }
        });
mScrollView.setOnTouchListener((v, e) -> gestureDetector.onTouchEvent(e));

참고 URL : https://stackoverflow.com/questions/4828636/edittext-clear-focus-on-touch-outside

반응형