Làm cách nào để ẩn bàn phím mềm trên Android sau khi nhấp bên ngoài EditText?


354

Ok mọi người đều biết rằng để ẩn bàn phím bạn cần thực hiện:

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

Nhưng vấn đề lớn ở đây là làm thế nào để ẩn bàn phím khi người dùng chạm hoặc chọn bất kỳ địa điểm nào khác không phải là EditTexthoặc softPal?

Tôi đã cố gắng sử dụng onTouchEvent()trên cha mẹ của mình Activitynhưng nó chỉ hoạt động nếu người dùng chạm vào bên ngoài bất kỳ chế độ xem nào khác và không có chế độ xem cuộn.

Tôi đã cố gắng thực hiện một cú chạm, nhấp, tập trung nghe mà không thành công.

Tôi thậm chí đã cố gắng thực hiện cuộn xem của riêng mình để chặn các sự kiện chạm nhưng tôi chỉ có thể nhận được tọa độ của sự kiện chứ không phải chế độ xem được nhấp.

Có một cách tiêu chuẩn để làm điều này ?? Trong iPhone thật dễ dàng.


Vâng, tôi nhận ra rằng scrollview không thực sự là vấn đề, nhưng các nhãn ở đó. Khung nhìn là bố cục dọc với một cái gì đó như: TextView, EditText, TextView, EditText, v.v. và textViews sẽ không để edittext mất tiêu điểm và ẩn bàn phím
htafoya

Bạn có thể tìm một giải pháp cho getFields()đây: stackoverflow.com/questions/7790487/ cấp
Reto

Có thể đóng bàn phím bằng cách nhấn nút quay lại, vì vậy tôi có thể nghi ngờ liệu điều này có đáng để nỗ lực hay không
gerrytan

4
Tôi tìm thấy câu trả lời này: stackoverflow.com/a/28939113/2610855 Cái tốt nhất.
Loenix

Câu trả lời:


575

Đoạn mã sau chỉ cần ẩn bàn phím:

public static void hideSoftKeyboard(Activity activity) {
    InputMethodManager inputMethodManager = 
        (InputMethodManager) activity.getSystemService(
            Activity.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow(
        activity.getCurrentFocus().getWindowToken(), 0);
}

Bạn có thể đưa nó lên trong một lớp tiện ích hoặc nếu bạn đang xác định nó trong một hoạt động, tránh tham số hoạt động hoặc gọi hideSoftKeyboard(this).

Phần khó nhất là khi gọi nó. Bạn có thể viết một phương thức lặp đi lặp lại Viewtrong mọi hoạt động của mình và kiểm tra xem nó có phải là instanceof EditTextnếu nó không đăng ký setOnTouchListenerthành phần đó không và mọi thứ sẽ rơi đúng vị trí. Trong trường hợp bạn đang tự hỏi làm thế nào để làm điều đó, trên thực tế nó khá đơn giản. Đây là những gì bạn làm, bạn viết một phương thức đệ quy như sau, trên thực tế bạn có thể sử dụng phương thức này để làm bất cứ điều gì, như thiết lập kiểu chữ tùy chỉnh, v.v ... Đây là phương pháp

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

Đó là tất cả, chỉ cần gọi phương thức này sau khi bạn setContentViewtrong hoạt động của bạn. Trong trường hợp bạn đang tự hỏi bạn sẽ vượt qua tham số nào, thì đó là idcontainer chính. Chỉ định một idcho container cha mẹ của bạn như

<RelativeLayoutPanel android:id="@+id/parent"> ... </RelativeLayout>

và gọi setupUI(findViewById(R.id.parent)), đó là tất cả.

Nếu bạn muốn sử dụng nó một cách hiệu quả, bạn có thể tạo một phần mở rộng Activityvà đưa phương thức này vào, và làm cho tất cả các hoạt động khác trong ứng dụng của bạn mở rộng hoạt động này và gọi nó setupUI()trong onCreate()phương thức.

Hy vọng nó giúp.

Nếu bạn sử dụng nhiều hơn 1 hoạt động, hãy xác định id chung cho bố cục cha mẹ như <RelativeLayout android:id="@+id/main_parent"> ... </RelativeLayout>

Sau đó mở rộng một lớp từ Activityvà định nghĩa setupUI(findViewById(R.id.main_parent))Trong phạm vi của nó OnResume()và mở rộng lớp này thay vì `` Activityin your program


Đây là phiên bản Kotlin của chức năng trên:

@file:JvmName("KeyboardUtils")

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

Tôi đã không tự kiểm tra nhưng có vẻ như nó sẽ hoạt động và vì nó có đánh giá cao nên tôi sẽ thay đổi câu trả lời được chấp nhận cho vấn đề này.
htafoya

4
Không nên rất khó khăn? Tôi đã ra khỏi chương trình Android ngay bây giờ, vì vậy hãy sửa tôi nếu tôi sai. Bạn bằng cách nào đó có thể theo dõi EditText tập trung bất cứ lúc nào và chỉ yêu cầu nó mất tập trung trong OnTouchEvent?
Navneeth G

25
Không chắc chắn liệu có ai khác đã chạy qua vấn đề này không, nhưng điều này khiến ứng dụng bị sập khi bạn gọi hideSoftPal nếu không có gì tập trung. Bạn có thể giải quyết điều này bằng cách bao quanh dòng thứ hai của phương thức vớiif(activity.getCurrentFocus() != null) {...}
Frank Cangialosi

14
Vấn đề với cách tiếp cận này là nó giả định rằng tất cả các quan điểm khác sẽ không bao giờ cần phải đặt ra OnTouchListenercho chúng. Bạn chỉ có thể đặt logic đó trong ViewGroup.onInterceptTouchEvent(MotionEvent)chế độ xem gốc.
Alex.F

2
Không hoạt động khi tôi nhấp vào các điều khiển khác giữ cho bàn phím mở
mohitum

285

Bạn có thể đạt được điều này bằng cách thực hiện các bước sau:

  1. Làm cho chế độ xem chính (chế độ xem nội dung của hoạt động của bạn) có thể nhấp và tập trung bằng cách thêm các thuộc tính sau

        android:clickable="true" 
        android:focusableInTouchMode="true" 
  2. Thực hiện một phương thức hidePal ()

        public void hideKeyboard(View view) {
            InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
  3. Cuối cùng, đặt onF FocusChangeListener của edittext của bạn.

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

Như đã chỉ ra trong một trong những ý kiến ​​dưới đây, điều này có thể không hoạt động nếu chế độ xem chính là ScrollView. Trong trường hợp như vậy, có thể thêm và có thể tập trungInTouchMode có thể được thêm vào chế độ xem ngay dưới ScrollView.


67
Theo tôi đây là câu trả lời đúng. Ít mã hơn, không lặp lại không cần thiết ...
gattshjoty

14
Tôi thích câu trả lời này rất nhiều. Một điều cần lưu ý là điều này không hiệu quả với tôi khi thêm clickablefocusableInTouchModevào ScrollViewphần tử gốc của tôi . Tôi đã phải thêm vào cha mẹ trực tiếp của tôi EditTextđó là một LinearLayout.
Adam Johns

10
Làm việc hoàn hảo cho tôi. Mặc dù, nếu bạn có hai tiện ích edittext, bạn cần đảm bảo rằng bạn xử lý lấy nét trên cả hai chính xác nếu không bạn sẽ tắt bàn phím ẩn một cách không cần thiết.
Marka A

1
@MarkaA Tôi không gặp vấn đề gì với điều này, Khi tôi nhấp vào EditText khác, bàn phím vẫn ở lại, nếu nhấp vào nền nó sẽ ẩn như thế. Tôi đã có một số xử lý khác tại onF FocusChange, chỉ thay đổi nền của EditText khi nó có tiêu điểm, không có gì sai.
CularBytes

3
@Shrikant - Tôi cũng thấy nhấp nháy với nhiều văn bản chỉnh sửa. Tôi chỉ đặt onF FocusChangeListener trên cha mẹ thay vì trên mỗi văn bản chỉnh sửa và chuyển điều kiện sang nói if (hasF Focus) {hidePal (v); } Không nhận thấy nhấp nháy nữa khi chuyển văn bản chỉnh sửa btwn.
manisha

69

Chỉ cần ghi đè mã bên dưới trong Hoạt động

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

4
Giải pháp đơn giản, Thêm vào hoạt động và nó cũng sẽ giải quyết vấn đề
Rohit Maurya

1
Một giải pháp khác là tạo BaseActivity và mở rộng nó trong tất cả các Hoạt động
sumit sonawane 28/03/19

1
Giải pháp tuyệt vời
Ahmed Adel Ismail

1
bạn đã cứu tôi khỏi bị tắt màn hình khi đóng bàn phím. Đồng ý
Dimas Mendes

1
Thật tuyệt, nhưng nó quá tốt để trở thành sự thật: đơn giản, rất ngắn và nó hoạt động ... than ôi, có một vấn đề: khi bàn phím được hiển thị, mỗi lần chúng ta chạm vào EditText hỏi bàn phím, nó sẽ tắt và tự động lên.
Chrysotribax

60

Tôi thấy câu trả lời được chấp nhận hơi phức tạp.

Đây là giải pháp của tôi. Thêm một OnTouchListenervào bố cục chính của bạn, tức là:

findViewById(R.id.mainLayout).setOnTouchListener(this)

và đặt đoạn mã sau vào phương thức onTouch.

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

Bằng cách này, bạn không phải lặp đi lặp lại trên tất cả các lượt xem.


@roepit - tôi nhận được một classCastexception để cố gắng đưa bố cục vào chế độ xem. tui bỏ lỡ điều gì vậy?
katzenhut

Bạn có thể tham khảo mã của bạn ở đâu đó? Tôi không thể nói sai khi tôi không thể nhìn vào bố cục và hoạt động / đoạn mã et cetera của bạn.
roepit

Câu trả lời hay nhất ngoài kia, vẫn cố quấn đầu tôi xung quanh cách nó hoạt động.
dùng40797

nó sẽ hoạt động nếu bạn nhấp vào thanh tiêu đề của ứng dụng?
user1506104

1
Điều này hoạt động hoàn hảo để ẩn bàn phím! Lưu ý rằng điều này không thực sự làm mất tập trung EditText, nó chỉ ẩn bàn phím. Để cũng không tập trung vào EditText, hãy thêm ví dụ android:onClick="stealFocusFromEditTexts"vào xml của chế độ xem chính và sau đó public void stealFocusFromEditTexts(View view) {}vào hoạt động của nó. Phương thức nhấp chuột không cần phải làm gì cả, nó chỉ cần tồn tại để chế độ xem cha mẹ có thể tập trung / có thể lựa chọn, cần thiết để lấy cắp tiêu điểm từ đứa trẻ EditText
Jacob R

40

Tôi có thêm một giải pháp để ẩn bàn phím bằng cách:

InputMethodManager imm = (InputMethodManager) getSystemService(
    Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);

Ở đây vượt qua HIDE_IMPLICIT_ONLYtại vị trí showFlag0tại vị trí của hiddenFlag. Nó sẽ mạnh mẽ đóng bàn phím mềm.


3
Cảm ơn nó hoạt động ..... trên tất cả tôi đã thử nhưng nó không hoạt động trong khi tôi nhận được giá trị từ hộp thoại editext văn bản đóng hộp thứ hai ...
PankajAndroid

Cảm ơn, cái này chỉ hoạt động, và nó sạch hơn nhiều cái khác ở trên! +1
Edmond Tamas

Nó hoạt động như mong đợi, cảm ơn vì giải pháp của bạn +1
thử

Hoạt động như một cơ duyên đối với tôi. +1 cho giải pháp thanh lịch.
Saintjab

2
xin lỗi, nhưng phương pháp này là chuyển đổi, vì vậy nếu trạng thái bàn phím đã bị đóng, nó sẽ hiển thị bàn phím
HendraWD

16

Vâng, tôi quản lý để giải quyết phần nào vấn đề, tôi đã xử lý công vănTouchEvent về hoạt động của mình, ở đó tôi đang sử dụng cách sau để ẩn bàn phím.

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

EDIT: Phương thức getFields () chỉ là một phương thức trả về một mảng với các trường văn bản trong dạng xem. Để tránh tạo mảng này trên mỗi lần chạm, tôi đã tạo một mảng tĩnh có tên sFields, được trả về tại phương thức getFields (). Mảng này được khởi tạo trên các phương thức onStart (), chẳng hạn như:

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


Nó không hoàn hảo, Thời gian sự kiện kéo chỉ dựa trên heuristic nên đôi khi nó không ẩn khi thực hiện các clics dài và tôi cũng đã hoàn thành bằng cách tạo một phương thức để có được tất cả các editTexts trên mỗi lượt xem; nếu không, bàn phím sẽ ẩn và hiển thị khi nhấp vào EditText khác.

Tuy nhiên, các giải pháp sạch hơn và ngắn hơn được chào đón


8
Để giúp những người khác trong tương lai, bạn có xem xét việc chỉnh sửa mã trong câu trả lời của bạn để bao gồm getFields()phương pháp của bạn không? Nó không phải là chính xác, chỉ là một ví dụ với có lẽ chỉ một số ý kiến ​​cho thấy rằng nó trả về một mảng các EditTextđối tượng.
Squonk

14

Sử dụng OnF FocusChangeListener .

Ví dụ:

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

Cập nhật : bạn cũng có thể ghi đè lên onTouchEvent()hoạt động của mình và kiểm tra tọa độ của cảm ứng. Nếu tọa độ nằm ngoài EditText, thì ẩn bàn phím.


9
Vấn đề là edittext không mất tập trung khi tôi nhấp vào Nhãn hoặc các chế độ xem khác không thể lấy nét được.
htafoya

Trong trường hợp này tôi có thêm một giải pháp. Tôi đã cập nhật câu trả lời.
Serge Glotov

2
onTouchEvent được gọi nhiều lần vì vậy đây cũng không phải là một thực hành tốt
Jesus Dimrix

13

Tôi đã triển khai ClarkTouchEvent trong Activity để thực hiện việc này:

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

và tôi đã thử nó, hoạt động hoàn hảo!


hoạt động, nhưng vấn đề ở đây là nếu chúng ta có nhiều hơn một EditText thì chúng ta cũng cần xem xét điều đó, nhưng tôi thích câu trả lời của bạn :-)
Lalit Poptani

getActionMasked (ev) không được dùng nữa, vì vậy bây giờ sử dụng: Final int action = ev.getActionMasked (); cho dòng đầu tiên.
Andrew

12

Một cách khác của Kotlin & Thiết kế Vật liệu bằng TextInputEditText (cách tiếp cận này cũng tương thích với EditTextView ) ...

1. Thực hiện chế độ xem chính (chế độ xem nội dung của hoạt động / đoạn của bạn) có thể nhấp và tập trung bằng cách thêm các thuộc tính sau

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

2. Tạo một tiện ích mở rộng cho tất cả Chế độ xem (ví dụ bên trong tệp ViewExtension.kt):

fun View.hideKeyboard(){
    val inputMethodManager = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
    inputMethodManager.hideSoftInputFromWindow(this.windowToken, 0)
}

3. Tạo một BaseTextInputEditText kế thừa TextInputEditText. Thực hiện phương thức onF FocusChanged để ẩn bàn phím khi chế độ xem không được tập trung:

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.Chỉ cần gọi chế độ xem tùy chỉnh hoàn toàn mới trong XML của bạn:

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

Đó là tất cả. Không cần phải sửa đổi bộ điều khiển của bạn (đoạn hoặc hoạt động) để xử lý trường hợp lặp đi lặp lại này.


Vâng tốt một nhưng tôi ước có một cách đơn giản hơn!
devDeejay

11

Ghi đè công văn boolean công khaiTouchEvent (sự kiện MotionEvent) trong bất kỳ Hoạt động nào (hoặc mở rộng lớp Hoạt động)

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

Và đó là tất cả những gì bạn cần làm


đây là cách dễ nhất mà tôi tìm thấy để làm cho nó hoạt động. hoạt động với nhiều EditTexts và ScrollView
RJH

Đã thử nghiệm nó với nhiều EditTexts; nó hoạt động Nhược điểm duy nhất là khi bạn thực hiện một động tác kéo, nó cũng ẩn đi.
RominaV

9

Tôi đã sửa đổi giải pháp của Andre Luis IM Tôi đã đạt được điều này:

Tôi đã tạo một phương thức tiện ích để ẩn bàn phím mềm giống như cách Andre Luiz IM đã làm:

public static void hideSoftKeyboard(Activity activity) {
    InputMethodManager inputMethodManager = (InputMethodManager)  activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}

Nhưng thay vì đăng ký OnTouchListener cho mọi chế độ xem, điều đó mang lại hiệu suất kém, tôi đã đăng ký OnTouchListener cho chỉ chế độ xem gốc. Vì bong bóng sự kiện cho đến khi nó được tiêu thụ (EditText là một trong những chế độ xem tiêu thụ theo mặc định), nếu nó đến chế độ xem gốc, thì đó là vì nó không được tiêu thụ, vì vậy tôi đóng bàn phím mềm.

findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Utils.hideSoftKeyboard(activity);
        return false;
    }
});

1
Điều này dường như an toàn hơn với tôi.
superarts.org

9

Tôi biết rằng chủ đề này khá cũ, câu trả lời đúng có vẻ hợp lệ và có rất nhiều giải pháp hoạt động ngoài kia, nhưng tôi nghĩ cách tiếp cận được nêu dưới đây có thể có một lợi ích bổ sung về hiệu quả và sự thanh lịch.

Tôi cần hành vi này cho tất cả các hoạt động của mình, vì vậy tôi đã tạo một lớp CustomActivity kế thừa từ Hoạt động của lớp và "nối" hàm hàm hàmTouchEvent . Chủ yếu có hai điều kiện để chăm sóc:

  1. Nếu tiêu điểm không thay đổi và ai đó đang gõ bên ngoài trường đầu vào hiện tại, thì hãy loại bỏ IME
  2. Nếu tiêu điểm đã thay đổi và phần tử tập trung tiếp theo không phải là trường hợp của bất kỳ loại trường đầu vào nào, thì hãy loại bỏ IME

Đây là kết quả của tôi:

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

Lưu ý bên lề: Ngoài ra, tôi chỉ định các thuộc tính này cho chế độ xem gốc giúp có thể xóa tiêu điểm trên mọi trường đầu vào và ngăn trường nhập vào tập trung vào khởi động hoạt động (làm cho chế độ xem nội dung trở thành "trình bắt tiêu điểm"):

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final View view = findViewById(R.id.content);

    view.setFocusable(true);
    view.setFocusableInTouchMode(true);
}

Siêu hoạt động tốt cảm ơn !! tôi đã đặt một upvote cho câu trả lời của bạn.
vijay

2
Tôi nghĩ đó là giải pháp tốt nhất cho bố cục phức tạp. Nhưng tôi đã tìm thấy 2 nhược điểm cho đến nay: 1. Menu ngữ cảnh EditText không thể bấm được - bất kỳ nhấp chuột nào vào nó đều gây mất tập trung từ EditText 2. Khi EditText của chúng tôi ở dưới cùng của chế độ xem và chúng tôi nhấp vào nó (để chọn từ), sau đó chọn bàn phím hiển thị "điểm nhấp" của chúng tôi là trên bàn phím, không phải trên EditText - vì vậy chúng tôi mất tiêu điểm một lần nữa: /
sange

@sổng, tôi nghĩ tôi đã giải quyết những hạn chế đó trong câu trả lời của mình; hãy xem
Andy Dennie

6

Tôi thích cách tiếp cận của cuộc gọi dispatchTouchEventđược thực hiện bởi htafoya, nhưng:

  • Tôi không hiểu phần hẹn giờ (không biết tại sao cần đo thời gian chết?)
  • Tôi không muốn đăng ký / hủy đăng ký tất cả các EditTexts với mỗi lần thay đổi chế độ xem (có thể có khá nhiều lượt xem và edittexts trong hệ thống phân cấp phức tạp)

Vì vậy, tôi đã thực hiện giải pháp này có phần dễ dàng hơn:

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

Có một nhược điểm:

Chuyển đổi từ cái này EditTextsang cái khác EditTextlàm cho bàn phím ẩn đi và làm lại - trong trường hợp của tôi, nó muốn như vậy, bởi vì nó cho thấy rằng bạn đã chuyển đổi giữa hai thành phần đầu vào.


Phương pháp này hoạt động tốt nhất ở khả năng chỉ có thể cắm và chạy với FragmentActivity của tôi.
BillyRayCyrus 16/1/2015

Cảm ơn, đó là cách tốt nhất! Tôi cũng vừa thêm kiểm tra cho hành động sự kiện: int action = ev.getActionMasked (); if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {...}
sergey.n

Cảm ơn ! Bạn đã tiết kiệm thời gian của tôi .. Câu trả lời tốt nhất.
I.d007

6

Lời cầu xin: Tôi nhận ra tôi không có ảnh hưởng, nhưng xin hãy nghiêm túc trả lời.

Vấn đề: Loại bỏ bàn phím mềm khi nhấp khỏi bàn phím hoặc chỉnh sửa văn bản với mã tối thiểu.

Giải pháp: Thư viện bên ngoài được gọi là Butterknife.

Giải pháp một dòng:

@OnClick(R.id.activity_signup_layout) public void closeKeyboard() { ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); }

Giải pháp dễ đọc hơn:

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

Giải trình: Liên kết Trình nghe OnClick với ID cha của Bố cục XML của hoạt động, để bất kỳ nhấp chuột nào vào bố cục (không phải trên văn bản chỉnh sửa hoặc bàn phím) sẽ chạy đoạn mã đó sẽ ẩn bàn phím.

Ví dụ: Nếu tệp bố cục của bạn là R.layout.my_layout và id bố cục của bạn là R.id.my_layout_id, thì cuộc gọi liên kết Butterknife của bạn sẽ giống như:

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

Liên kết tài liệu Butterknife: http://jakewharton.github.io/butterknife/

Phích cắm: Butterknife sẽ cách mạng hóa sự phát triển Android của bạn. Hãy xem xét nó.

Lưu ý: Kết quả tương tự có thể đạt được mà không cần sử dụng thư viện bên ngoài Butterknife. Chỉ cần đặt OnClickListener thành bố cục cha mẹ như được mô tả ở trên.


Giải pháp tuyệt vời, hoàn hảo! Cảm ơn bạn.
nullforlife

6

Trong kotlin, chúng ta có thể làm như sau. Không cần phải lặp lại tất cả các quan điểm. Nó cũng sẽ làm việc cho các mảnh vỡ.

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

không hoạt động từ mảnh vỡ
Nurseyit Tursunkulov

Điều này hoạt động nhưng nó có một lỗi. ví dụ: nếu tôi muốn dán văn bản trong chế độ xem văn bản, bàn phím sẽ ẩn và sau đó hiển thị. Đó là một chút khó chịu.
George Shalvashvili

Vì vậy, hãy cho tôi biết giải pháp tốt nhất ..
Sai

4

Đây là một biến thể khác trong câu trả lời của fje nhằm giải quyết các vấn đề được nêu lên.

Ý tưởng ở đây là xử lý cả hành động xuống và hành động lên trong Hoạt động dispatchTouchEvent phương thức . Về hành động xuống, chúng tôi lưu ý đến chế độ xem hiện đang tập trung (nếu có) và liệu cảm ứng có ở bên trong nó hay không, lưu cả hai bit thông tin đó cho lần sau.

Về hành động lên, trước tiên chúng tôi gửi đi, để cho phép một góc nhìn khác có khả năng tập trung. Nếu sau đó, chế độ xem hiện tại tập trung là chế độ xem được tập trung ban đầu và cảm ứng xuống bên trong chế độ xem đó, thì chúng tôi để bàn phím mở.

Nếu chế độ xem hiện tại tập trung khác với chế độ xem tập trung ban đầu đó là chế độ xem EditText, thì chúng tôi cũng để bàn phím mở.

Nếu không, chúng tôi đóng nó.

Vì vậy, để tóm tắt, điều này hoạt động như sau:

  • Khi chạm vào bên trong một tiêu điểm hiện tại EditText, bàn phím vẫn mở
  • khi chuyển từ tiêu điểm này EditTextsang tiêu điểm khác EditText, bàn phím vẫn mở (không đóng / mở lại)
  • Khi chạm vào bất cứ nơi nào bên ngoài một tiêu điểm hiện tại EditTextkhông phải là khác EditText, bàn phím sẽ đóng lại
  • khi nhấn lâu EditTextđể hiển thị thanh hành động theo ngữ cảnh (với các nút cắt / sao chép / dán), bàn phím vẫn mở, ngay cả khi hành động UP diễn ra bên ngoài tiêu điểm EditText(di chuyển xuống để nhường chỗ cho CAB) . Tuy nhiên, xin lưu ý rằng khi bạn nhấn vào nút trong CAB, nó sẽ đóng bàn phím. Điều đó có thể hoặc không thể được mong muốn; nếu bạn muốn cắt / sao chép từ một trường và dán vào trường khác, nó sẽ như vậy. Nếu bạn muốn dán lại vào cùngEditText , nó sẽ không như vậy.
  • khi tiêu điểm EditTextnằm ở dưới cùng của màn hình và bạn nhấp lâu vào một số văn bản để chọn nó, EditTextlấy nét và do đó bàn phím mở ra như bạn muốn, bởi vì chúng tôi thực hiện kiểm tra "chạm trong giới hạn xem" , không phải là hành động lên.

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

4

quá đơn giản, chỉ cần làm cho bố cục gần đây của bạn có thể nhấp được theo tiêu điểm:

android:id="@+id/loginParentLayout"
android:clickable="true"
android:focusableInTouchMode="true"

và sau đó viết một phương thức và OnClickListner cho bố cục đó, để khi bố trí trên cùng được chạm vào bất kỳ nơi nào nó sẽ gọi một phương thức trong đó bạn sẽ viết mã để loại bỏ bàn phím. sau đây là mã cho cả hai; // bạn phải viết cái này trong OnCreate ()

 yourLayout.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View view) {
                    hideKeyboard(view);
                }
            });

phương thức được gọi từ listner: -

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

4

Tôi thấy phức tạp câu trả lời được chấp nhận cho yêu cầu đơn giản này. Đây là những gì làm việc cho tôi mà không có trục trặc.

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

1
Nếu bạn sử dụng NestedScrollViewhoặc bố trí phức tạp, hãy xem câu trả lời được chấp nhận: stackoverflow.com/a/11656129/2914140 . Bạn nên biết rằng các container khác có thể tiêu thụ chạm.
CoolMind

3

Có một cách tiếp cận đơn giản hơn, dựa trên cùng một vấn đề của iPhone. Chỉ cần ghi đè lên bố cục của nền trong sự kiện chạm, nơi chứa văn bản chỉnh sửa. Chỉ cần sử dụng mã này trong OnCreate của hoạt động (login_fondo là bố cục gốc):

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

1
Như tôi đã nói và tôi nhớ, điều này chỉ hoạt động nếu biểu mẫu không nằm trong ScrollView.
htafoya

1
Điều này không hoạt động tốt nếu bố trí nền có bố trí trẻ em khác.
AxeEffect

Cảm ơn đã nhắc nhở rằng onClick không phải là lựa chọn duy nhất.
Harpreet

3

Phương pháp hiển thị / ẩn bàn phím mềm

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

    }

Tôi hy vọng chúng có ích


3

Đây là giải pháp dễ nhất cho tôi (và do tôi thực hiện).

Đây là phương pháp để ẩn bàn phím.

public void hideKeyboard(View view){
        if(!(view instanceof EditText)){
            InputMethodManager inputMethodManager=(InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);
        }
    }

bây giờ đặt thuộc tính onclick của bố trí mẹ của hoạt động thành phương thức trên hideKeyboardhoặc từ chế độ xem Thiết kế của tệp XML của bạn hoặc viết mã dưới đây trong dạng xem Văn bản của tệp XML của bạn.

android:onClick="hideKeyboard"

2

Tôi đã tinh chỉnh phương thức, đặt mã sau vào một số lớp tiện ích UI (tốt nhất là không nhất thiết) để có thể truy cập nó từ tất cả các lớp Activity hoặc Fragment của bạn để phục vụ mục đích của nó.

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

Sau đó nói ví dụ bạn cần gọi nó từ hoạt động, gọi nó như sau;

UIutils.serachAndHideSoftKeybordFromView(findViewById(android.R.id.content), YourActivityName.this);

Để ý

findViewById (android.R.id.content)

Điều này cung cấp cho chúng tôi chế độ xem gốc của nhóm hiện tại (bạn không phải đặt id trên chế độ xem gốc).

Chúc mừng :)



2

Hoạt động

 @Override
 public boolean dispatchTouchEvent(MotionEvent ev) {
     ScreenUtils.hideKeyboard(this, findViewById(android.R.id.content).getWindowToken());
     return super.dispatchTouchEvent(ev);
 }

Màn hình

 public static void hideKeyboard(Context context, IBinder windowToken) {
     InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
     imm.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS);
 }

3
Mã này đơn giản, nhưng nó có một vấn đề rõ ràng: nó đóng bàn phím khi chạm vào bất cứ nơi nào . Đó là nếu bạn nhấn vào một vị trí khác của EditText để di chuyển con trỏ đầu vào, nó sẽ ẩn bàn phím và bàn phím bật lên một lần nữa bởi hệ thống.
Rau chết tiệt

2

Chỉ cần thêm mã này trong lớp @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);
}

3
Trong khi điều này có thể trả lời câu hỏi, tốt hơn là giải thích các phần thiết yếu của câu trả lời và có thể vấn đề với mã OP là gì.
pirho

có @pirho Tôi cũng đồng ý với bạn Haseeb cần tập trung vào việc đưa ra câu trả lời thích hợp.
Dilip

2
@Dilip Bạn có biết bạn cũng có thể nêu ý kiến ​​bạn đồng ý không? Đây chỉ là để giữ cho phần bình luận sạch sẽ để không có nhiều bình luận có cùng quan điểm.
pirho

2

Thay vì lặp qua tất cả các chế độ xem hoặc ghi đè công vănTouchEvent.

Tại sao Không chỉ ghi đè onUserInteraction () của Hoạt động này sẽ đảm bảo bàn phím loại bỏ bất cứ khi nào người dùng chạm bên ngoài EditText.

Sẽ hoạt động ngay cả khi EditText nằm trong scrollView.

@Override
public void onUserInteraction() {
    if (getCurrentFocus() != null) {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    }
}

đây là câu trả lời tốt hơn
ovluca

Đúng! Đó là một câu trả lời siêu sạch. Và nếu bạn tạo một AbstractActivity mà tất cả các Hoạt động khác của bạn mở rộng, bạn có thể nướng nó dưới dạng hành vi mặc định trong suốt ứng dụng của mình.
mèo hoang12

1

Tôi đã làm việc này với một biến thể nhỏ trên giải pháp của Fernando Camarago. Trong phương thức onCreate của tôi, tôi đính kèm một onTouchListener vào chế độ xem gốc nhưng gửi chế độ xem thay vì hoạt động như một đối số.

        findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {           
        public boolean onTouch(View v, MotionEvent event) {
            Utils.hideSoftKeyboard(v);
            return false;
        }
    });

Trong một lớp Utils riêng biệt là ...

    public static void hideSoftKeyboard(View v) {
    InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 
    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}

1

Điều này có thể cũ nhưng tôi đã làm việc này bằng cách thực hiện một lớp tùy chỉnh

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

cách thực hành tốt nhất ở đây là tạo một lớp Trình trợ giúp và mọi Bố cục tương đối / Bố cục tuyến tính nên thực hiện việc này.

**** Chỉ lưu ý rằng Container chính sẽ triển khai lớp này (Để tối ưu hóa) ****

và thực hiện nó như thế này:

Parent.setOnClickListener( new DismissKeyboardListener(this) ); 

từ khóa này là dành cho Hoạt động. vì vậy nếu bạn ở trên đoạn bạn sử dụng như getActivity ();

--- giơ ngón tay cái lên nếu nó giúp bạn ... --- chúc mừng Ralph ---


1

Đây là một phiên bản sửa đổi một chút của câu trả lời của fje mà hầu hết hoạt động hoàn hảo.

Phiên bản này sử dụng ACTION_DOWN để thực hiện hành động cuộn cũng đóng bàn phím. Nó cũng không truyền bá sự kiện trừ khi bạn nhấp vào EditText khác. Điều này có nghĩa là nhấp vào bất cứ nơi nào bên ngoài EditText của bạn, ngay cả trên một lần nhấp khác, chỉ cần đóng bàn phím.

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

Một cái gì đó không nhìn đúng ở đây; bạn đang gán cả hai viewviewTmpcho getCurrentFocus(), vì vậy chúng sẽ luôn có cùng giá trị.
Andy Dennie

1

Tôi đã làm theo cách này:

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

Ẩn mã bàn phím :

public static void hideKeyboard(Activity act) {
    if(act!=null)
      ((InputMethodManager)act.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow((act.getWindow().getDecorView().getApplicationWindowToken()), 0);
  }

Làm xong

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.