Làm thế nào để loại bỏ tiêu điểm mà không cần đặt tiêu điểm cho một điều khiển khác?


93

Tôi thích giao diện người dùng của mình trực quan; mỗi màn hình phải hướng dẫn người dùng một cách tự nhiên và không phô trương đến bước tiếp theo trong ứng dụng. Bỏ qua điều đó, tôi cố gắng làm cho mọi thứ trở nên khó hiểu và gây nhiễu nhất có thể.

Đùa thôi :-)

Tôi có ba cái TableRow, mỗi cái chứa một điều khiển EditText chỉ đọc và không tiêu điểm và sau đó là một nút ở bên phải của nó. Mỗi nút bắt đầu cùng một hoạt động nhưng với một đối số khác nhau. Người dùng thực hiện một lựa chọn ở đó và hoạt động phụ kết thúc, điền vào EditTextlựa chọn thích hợp với lựa chọn của người dùng.

Đó là cơ chế giá trị xếp tầng cổ điển; mỗi lựa chọn sẽ thu hẹp các tùy chọn có sẵn cho lựa chọn tiếp theo, v.v. Vì vậy, tôi đang tắt cả hai điều khiển trên mỗi hàng tiếp theo cho đến khi EditText trên hàng hiện tại chứa một giá trị.

Tôi cần thực hiện một trong hai việc, theo thứ tự ưu tiên sau:

  1. Khi một nút được nhấp, ngay lập tức xóa tiêu điểm mà không đặt tiêu điểm vào một nút khác
  2. Đặt tiêu điểm vào nút đầu tiên khi hoạt động bắt đầu

Vấn đề biểu hiện sau khi hoạt động con trở lại; nút được nhấp sẽ giữ lại tiêu điểm.

Re: # 1 ở trên - Có vẻ như không có một removeFocus()phương pháp hoặc một cái gì đó tương tự

Re: # 2 ở trên - Tôi có thể sử dụng requestFocus()để đặt tiêu điểm cho nút trên hàng tiếp theo và điều đó hoạt động sau khi hoạt động con trở lại, nhưng vì một số lý do, nó không hoạt động trong hoạt động chính onCreate().

Tôi cần tính nhất quán của giao diện người dùng theo cả hai hướng - không có nút nào có tiêu điểm sau khi hoạt động phụ kết thúc hoặc mỗi nút nhận được tiêu điểm tùy thuộc vào vị trí của nó trong luồng logic, bao gồm cả nút hoạt động đầu tiên (và duy nhất) trước bất kỳ lựa chọn nào.

Câu trả lời:


173

Việc sử dụng clearFocus () dường như cũng không hiệu quả với tôi như bạn thấy (đã thấy trong phần nhận xét cho một câu trả lời khác), nhưng cuối cùng những gì hiệu quả với tôi là thêm:

<LinearLayout 
    android:id="@+id/my_layout" 
    android:focusable="true" 
    android:focusableInTouchMode="true" ...>

vào Chế độ xem bố cục cấp cao nhất của tôi (bố cục tuyến tính). Để xóa tiêu điểm khỏi tất cả các Buttons / EditTexts, v.v., bạn có thể thực hiện

LinearLayout myLayout = (LinearLayout) activity.findViewById(R.id.my_layout);
myLayout.requestFocus();

Yêu cầu lấy nét không làm gì trừ khi tôi đặt chế độ xem có thể lấy nét được.


Trong một khoảnh khắc thoáng qua, tôi nghĩ rằng điều này có thể hiệu quả. "Đẹp làm sao trong sự đơn giản của nó!" Tôi tự nhủ. Than ôi, nó đã không xảy ra. Ngay cả khi tôi xóa requestFocus (), nút của hàng tiếp theo vẫn được lấy nét. Đây sẽ là tùy chọn thứ hai được chấp nhận, nhưng chỉ khi bằng cách nào đó tôi có thể đặt tiêu điểm vào nút đầu tiên trong onCreate ().
InteXX

@InteXX: Hôm nay tôi lại gặp vấn đề này và tìm ra giải pháp. Tôi biết bây giờ bạn đã đi theo một con đường khác, nhưng hãy thử điều này nếu bạn thấy mình trên cùng một con thuyền một lần nữa!
actionhrimp

"Tôi biết bây giờ bạn đã đi một con đường khác" Vẫn chưa quá muộn để sao lưu :-) Tôi sẽ thử và cho bạn biết, cảm ơn.
InteXX

Em yêu. Gần như, nhưng không hoàn toàn. Có, nó làm mất tiêu điểm của nút được nhấp cuối cùng, nhưng sau đó nó cũng ngăn BẤT KỲ nút nào lấy được tiêu điểm. Điều này có nghĩa là người dùng không cảm ứng của tôi sẽ không thể nhấp vào nút. Nó có làm tương tự cho bạn không?
InteXX

6
Điều này sẽ không hoạt động trên ScrollView. Nếu chế độ xem trên cùng của bạn là ScrollView, hãy sử dụng nó trên con của nó.
Uroš Podkrižnik

79

Câu hỏi cũ, nhưng tôi đã gặp nó khi tôi gặp vấn đề tương tự và nghĩ rằng tôi sẽ chia sẻ những gì tôi đã làm.

Chế độ xem đạt được tiêu điểm mỗi lần khác nhau nên tôi đã sử dụng rất chung chung:

View current = getCurrentFocus();
if (current != null) current.clearFocus();

12
Cách thanh lịch để làm điều này. Người ta có thể muốn kiểm tra cho null một giá trị từ getCurrentFocus () trước khi gọi clearFocus ()
Vering

4
+1 Có, bạn sẽ phải ném vào séc trống đó! - Tại sao Java không thể triển khai toán tử safe-traversal-? Nó sẽ là đơn giản như getCurrentFocus()?.clearFocus();, vì vậy tốt đẹp và thanh lịch: - /
Lê-vi

1
@willlma: Vâng, đây chính xác là những gì tôi muốn nói.
Vering

5
@Levit Rất giống Swift. :-) Nhưng ngay cả khi Java đã thực hiện một toán tử như vậy, Android vẫn sẽ mất 4 năm để bắt kịp.
Greg Brown,

2
@Levit, chắc bạn đã tìm thấy nó rồi, nhưng Kotlin.
prodaea

9
  1. Bạn có thể sử dụng View.clearFocus().

  2. Sử dụng View.requestFocus()được gọi từ onResume().


@siliconeagle: Bây giờ điều này rất RẤT kỳ quặc. (Cảm ơn con trỏ tới clearFocus () btw - Tôi không biết điều này.) Khi tôi nhấp vào nút đầu tiên, thực hiện lựa chọn, rồi quay lại, nút đầu tiên không thể nhận tiêu điểm nữa. Tôi không đặt có thể lấy tiêu điểm cho nút này ở bất kỳ đâu trong mã của mình. Tôi muốn cho bạn xem mã của mình, nhưng không có đủ ký tự có sẵn trong cửa sổ chỉnh sửa này và là người mới đối với VẬY Tôi không chắc liệu mình có nên nhập một câu trả lời khác chỉ để có thể đăng mã hay không.
InteXX

@siliconeagle: Thật không may, clearFocus () không hoạt động - các nút vẫn giữ tiêu điểm khi hoạt động phụ trở lại.
InteXX

@siliconeagle: OK, đừng bận tâm về nhận xét đầu tiên đó. Tôi đang sử dụng setFocusable (false) trong sự kiện nhấp của nút và quên bật lại sau khi hoạt động phụ quay lại. clearFocus () vẫn không có tác dụng - Tôi tự hỏi tại sao? Tôi đang gọi nó trên tất cả các nút từ onActivityResult (), nhưng nút được nhấp vẫn giữ tiêu điểm. Kỳ quặc.
InteXX

@siliconeagle: @actionshrimp: Tôi đã quyết định loại bỏ tất cả các lệnh và cài đặt liên quan đến tiêu điểm. Mục đích ban đầu của tôi là ngăn chặn sự tập trung vào các nút bị vô hiệu hóa, nhưng nếu đây là những gì nó phải trả thì nó không đáng. Không có requestFocus (), clearFocus () hoặc setFocusable (), không có nút nào giữ lại tiêu điểm sau khi hoạt động phụ trở lại. Đó là ít hơn hai con mọt - tôi đoán tôi sẽ phải sống với việc người dùng có thể đặt tiêu điểm vào một nút bị tắt.
InteXX

các yếu tố bị vô hiệu hóa không thể lấy nét AFAIK ... use setEnabled (false)
siliconeagle

8

android:descendantFocusability="beforeDescendants"

bằng cách sử dụng phần sau trong hoạt động với một số tùy chọn bố cục bên dưới dường như hoạt động như mong muốn.

 getWindow().getDecorView().findViewById(android.R.id.content).clearFocus();

liên quan đến các tham số sau trên chế độ xem gốc.

<?xml
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:descendantFocusability="beforeDescendants" />

https://developer.android.com/reference/android/view/ViewGroup#attr_android:descendantFocusability

Trả lời nhờ: https://forums.xamarin.com/discussion/1856/how-to-disable-auto-focus-on-edit-text

Giới thiệu về windowSoftInputMode

Vẫn còn một điểm tranh chấp khác cần lưu ý. Theo mặc định, Android sẽ tự động gán tiêu điểm ban đầu cho EditText đầu tiên hoặc điều khiển có thể lấy tiêu điểm trong Hoạt động của bạn. Theo lẽ tự nhiên, InputMethod (thường là bàn phím mềm) sẽ phản hồi sự kiện tiêu điểm bằng cách hiển thị chính nó. Thuộc tính windowSoftInputMode trong AndroidManifest.xml, khi được đặt thành stateAlwaysHidden, sẽ hướng dẫn bàn phím bỏ qua tiêu điểm ban đầu được gán tự động này.

<activity
    android:name=".MyActivity"
    android:windowSoftInputMode="stateAlwaysHidden"/>

tài liệu tham khảo tuyệt vời


5
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:id="@+id/ll_root_view"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">

LinearLayout llRootView = findViewBindId(R.id.ll_root_view);
llRootView.clearFocus();

Tôi sử dụng điều này khi đã cập nhật xong thông tin hồ sơ và xóa tất cả tiêu điểm khỏi EditText trong bố cục của tôi

====> Cập nhật: Trong nội dung bố cục gốc, thêm dòng EditText của tôi:

android:focusableInTouchMode="true"


2

Trước hết, nó sẽ hoạt động 100% ........

  1. Tạo nên onResume() phương pháp.
  2. Bên trong này, onResume()hãy tìm chế độ xem đang lấy nét lại bằng cáchfindViewById() .
  3. Bên này onResume()bộrequestFocus() quan điểm này.
  4. Bên này onResume()bộclearFocus quan điểm này.
  5. Đi vào xml của cùng một bố cục và tìm chế độ xem trên cùng mà bạn muốn tập trung và đặt focusableđúng vàfocusableInTuch thật.
  6. Bên trong này, onResume()tìm chế độ xem trên cùng bằng cáchfindViewById
  7. Bên này onResume()thiết lập requestFocus()quan điểm này ở cuối cùng.
  8. Và bây giờ hãy tận hưởng ......

2

Tôi đã cố gắng tắt và bật khả năng lấy nét cho chế độ xem và nó hoạt động với tôi (tiêu điểm đã được đặt lại):

focusedView.setFocusable(false);
focusedView.setFocusableInTouchMode(false);
focusedView.setFocusable(true);
focusedView.setFocusableInTouchMode(true);

1

Bạn có thể thử tắt khả năng lưu trạng thái của Hoạt động chính (do đó làm cho nó quên điều khiển có văn bản và điều gì có tiêu điểm). Bạn sẽ cần có một số cách khác để ghi nhớ những gì EditText của bạn có và lưu trữ lại chúng trên onResume (). Khởi chạy các Hoạt động phụ của bạn với startActivityForResult () và tạo một trình xử lý onActivityResult () trong Hoạt động chính của bạn để cập nhật EditText một cách chính xác. Bằng cách này, bạn có thể đặt nút thích hợp mà bạn muốn tập trung vàoResume () đồng thời sao chép lại EditText bằng cách sử dụng myButton.post (new Runnable () {run () {myButton.requestFocus ();}});

Phương thức View.post () hữu ích để thiết lập tiêu điểm ban đầu vì có thể chạy đó sẽ được thực thi sau khi cửa sổ được tạo và mọi thứ ổn định, cho phép cơ chế lấy nét hoạt động bình thường vào thời điểm đó. Tôi đã phát hiện ra rằng cố gắng đặt tiêu điểm trong onCreate / Start / Resume () thường có vấn đề.

Xin lưu ý rằng đây là mã giả và không được kiểm tra, nhưng đó là một hướng khả thi mà bạn có thể thử.


Suy nghĩ thứ hai ... hãy thử chỉ sử dụng nội dung View.post () trước thay vì tắt trạng thái đã lưu của Hoạt động. Điều đó có thể tự làm ra mẹo cho bạn.
Uncle Code Monkey

Than ôi, tôi không còn cách nào dễ dàng để kiểm tra điều này nữa. Kể từ đó, tôi đã quyết định từ bỏ mô hình mã gốc và sử dụng HTML5 / CSS3 cho các ứng dụng dành cho thiết bị di động và do đó đã trang bị lại hệ thống của mình cho phù hợp. Nhưng cảm ơn bạn vì những gì dường như là một câu trả lời rất sâu sắc. Tôi đã bình chọn nó.
InteXX

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

Thêm chúng vào ViewGroup của bạn bao gồm EditTextView của bạn. Nó hoạt động đúng với Bố cục Ràng buộc của tôi. Hy vọng điều này giúp đỡ


0

Hãy thử cách sau (gọi điện clearAllEditTextFocuses();)

private final boolean clearAllEditTextFocuses() {
    View v = getCurrentFocus();
    if(v instanceof EditText) {
        final FocusedEditTextItems list = new FocusedEditTextItems();
        list.addAndClearFocus((EditText) v);

        //Focus von allen EditTexten entfernen
        boolean repeat = true;
        do {
            v = getCurrentFocus();
            if(v instanceof EditText) {
                if(list.containsView(v))
                    repeat = false;
                else list.addAndClearFocus((EditText) v);
            } else repeat = false;
        } while(repeat);

        final boolean result = !(v instanceof EditText);
        //Focus wieder setzen
        list.reset();
        return result;
    } else return false;
}

private final static class FocusedEditTextItem {

    private final boolean focusable;

    private final boolean focusableInTouchMode;

    @NonNull
    private final EditText editText;

    private FocusedEditTextItem(final @NonNull EditText v) {
        editText = v;
        focusable = v.isFocusable();
        focusableInTouchMode = v.isFocusableInTouchMode();
    }

    private final void clearFocus() {
        if(focusable)
            editText.setFocusable(false);
        if(focusableInTouchMode)
            editText.setFocusableInTouchMode(false);
        editText.clearFocus();
    }

    private final void reset() {
        if(focusable)
            editText.setFocusable(true);
        if(focusableInTouchMode)
            editText.setFocusableInTouchMode(true);
    }

}

private final static class FocusedEditTextItems extends ArrayList<FocusedEditTextItem> {

    private final void addAndClearFocus(final @NonNull EditText v) {
        final FocusedEditTextItem item = new FocusedEditTextItem(v);
        add(item);
        item.clearFocus();
    }

    private final boolean containsView(final @NonNull View v) {
        boolean result = false;
        for(FocusedEditTextItem item: this) {
            if(item.editText == v) {
                result = true;
                break;
            }
        }
        return result;
    }

    private final void reset() {
        for(FocusedEditTextItem item: this)
            item.reset();
    }

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