Bagaimana cara menghapus fokus tanpa mengatur fokus ke kontrol lain?

96

Saya suka UI saya yang intuitif; setiap layar harus secara alami dan tidak mencolok memandu pengguna ke langkah berikutnya dalam aplikasi. Kecuali itu, saya berusaha untuk membuat segala sesuatunya membingungkan dan membingungkan mungkin.

Hanya bercanda :-)

Saya punya tiga TableRows, masing-masing berisi kontrol EditText read-only dan non-focusable dan kemudian tombol di sebelah kanannya. Setiap tombol memulai aktivitas yang sama tetapi dengan argumen yang berbeda. Pengguna membuat pilihan di sana dan sub kegiatan selesai, mengisi yang sesuai EditTextdengan pilihan pengguna.

Ini adalah mekanisme nilai berjenjang klasik; setiap pilihan mempersempit pilihan yang tersedia untuk pilihan berikutnya, dll. Jadi saya menonaktifkan kedua kontrol pada setiap baris berikutnya sampai EditText pada baris saat ini berisi nilai.

Saya perlu melakukan satu dari dua hal, dalam urutan preferensi ini:

  1. Saat tombol diklik, segera hapus fokus tanpa menyetel fokus ke tombol lain
  2. Setel fokus ke tombol pertama saat aktivitas dimulai

Masalahnya muncul setelah sub kegiatan kembali; tombol yang diklik mempertahankan fokus.

Re: # 1 di atas - Sepertinya tidak ada removeFocus()metode, atau yang serupa

Perihal: # 2 di atas - Saya dapat menggunakan requestFocus()untuk menyetel fokus ke tombol di baris berikutnya, dan itu berfungsi setelah sub kegiatan kembali, tetapi untuk beberapa alasan itu tidak berfungsi di aktivitas induk onCreate().

Saya membutuhkan konsistensi UI di kedua arah - baik tidak ada tombol yang memiliki fokus setelah sub kegiatan selesai atau setiap tombol menerima fokus tergantung pada tempatnya di alur logika, termasuk tombol aktif pertama (dan satu-satunya) sebelum pemilihan apa pun.

InteXX
sumber

Jawaban:

174

Menggunakan clearFocus () tampaknya tidak berhasil untuk saya seperti yang Anda temukan (lihat di komentar untuk jawaban lain), tetapi yang berhasil bagi saya pada akhirnya adalah menambahkan:

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

ke Tampilan Tata Letak tingkat paling atas saya (tata letak linier). Untuk menghapus fokus dari semua Buttons / EditTexts dll, Anda dapat melakukannya

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

Meminta fokus tidak melakukan apa pun kecuali saya menyetel tampilan agar dapat difokuskan.

tindakan udang
sumber
Untuk sesaat saya pikir ini mungkin berhasil. "Betapa indahnya kesederhanaannya!" Aku berkata pada diriku sendiri. Sayangnya, itu tidak terjadi. Bahkan ketika saya menghapus requestFocus (), tombol baris berikutnya mendapatkan fokus. Ini akan baik-baik saja sebagai preferensi kedua, tetapi hanya jika saya entah bagaimana dapat mengatur fokus pada tombol pertama di onCreate ().
InteXX
@InteXX: Saya menemukan masalah ini lagi hari ini dan menemukan solusinya. Saya tahu Anda telah menempuh rute yang berbeda sekarang, tetapi cobalah ini jika Anda pernah berada di perahu yang sama lagi!
actionshrimp
"Saya tahu Anda telah mengambil rute yang berbeda sekarang" Masih belum terlambat untuk membuat cadangan :-) Saya akan mencobanya dan memberi tahu Anda, terima kasih.
InteXX
Menisik. Hampir, tapi tidak cukup. Ya, ini menghilangkan fokus dari tombol yang terakhir diklik, tetapi juga mencegah tombol APAPUN mendapatkan fokus. Ini berarti pengguna non-sentuh saya tidak akan dapat mengklik tombol. Apakah itu melakukan hal yang sama untuk Anda?
InteXX
6
Ini tidak akan berfungsi di ScrollView. Jika tampilan teratas Anda adalah ScrollView, gunakan ini pada anaknya.
Uroš Podkrižnik
79

Pertanyaan lama, tetapi saya menemukannya ketika saya memiliki masalah serupa dan berpikir saya akan membagikan apa yang akhirnya saya lakukan.

Pemandangan yang mendapatkan fokus berbeda setiap kali, jadi saya menggunakan yang sangat umum:

View current = getCurrentFocus();
if (current != null) current.clearFocus();
willlma
sumber
12
Cara yang elegan untuk melakukan ini. Seseorang mungkin ingin memeriksa null nilai dari getCurrentFocus () sebelum memanggil clearFocus ()
Vering
4
+1 Ya, Anda harus memasukkan cek nol itu! - Mengapa Java tidak dapat menerapkan operator safe-traversal saja? Ini akan sesederhana getCurrentFocus()?.clearFocus();, begitu bagus dan elegan: - /
Levite
1
@ Willlma: Ya, inilah yang saya maksud.
Vering
5
@Levit Sangat Cepat. :-) Tetapi bahkan jika Java benar-benar menerapkan operator seperti itu, masih dibutuhkan Android 4 tahun untuk menyusulnya.
Greg Brown
2
@Levit, Anda mungkin sudah menemukannya sekarang, tetapi Kotlin.
prodaea
9
  1. Anda bisa menggunakan View.clearFocus().

  2. Gunakan View.requestFocus()dipanggil dari onResume().

burung silikon
sumber
@siliconeagle: Sekarang ini SANGAT aneh. (Terima kasih atas penunjuk ke clearFocus () btw - Saya tidak mengetahui hal ini.) Ketika saya mengklik tombol pertama, membuat pilihan, dan kemudian kembali, tombol pertama tidak dapat lagi menerima fokus. Saya tidak menyetel fokus untuk tombol ini di mana pun di kode saya. Saya ingin menunjukkan kepada Anda kode saya, tetapi tidak ada cukup karakter yang tersedia di jendela pengeditan ini dan karena masih baru di SO Saya tidak yakin apakah saya harus memasukkan jawaban lain hanya untuk dapat mengirim kode.
InteXX
@siliconeagle: Sayangnya, clearFocus () tidak berfungsi - tombol mempertahankan fokus saat sub kegiatan kembali.
InteXX
@siliconeagle: Oke, tidak masalah tentang komentar pertama itu. Saya menggunakan setFocusable (false) di acara klik tombol dan lupa menyalakannya kembali setelah sub-aktivitas kembali. clearFocus () masih belum berpengaruh - Saya bertanya-tanya mengapa? Saya memanggilnya di semua tombol dari onActivityResult (), tetapi tombol yang diklik masih mempertahankan fokus. Aneh.
InteXX
@siliconeagle: @actionshrimp: Saya telah memutuskan untuk menyingkirkan semua perintah dan pengaturan yang berhubungan dengan fokus. Maksud awal saya adalah untuk mencegah fokus pada tombol yang dinonaktifkan, tetapi jika ini biayanya, itu tidak sepadan. Tanpa requestFocus (), clearFocus () atau setFocusable (), tidak ada tombol yang mempertahankan fokus setelah sub kegiatan kembali. Ini lebih rendah dari dua kumbang - saya kira saya harus hidup dengan pengguna yang dapat mengatur fokus ke tombol yang dinonaktifkan.
InteXX
elemen yang dinonaktifkan tidak dapat difokuskan AFAIK ... gunakan setEnabled (false)
siliconeagle
8

android:descendantFocusability="beforeDescendants"

menggunakan yang berikut ini dalam aktivitas dengan beberapa opsi tata letak di bawah ini tampaknya berfungsi sesuai keinginan.

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

sehubungan dengan parameter berikut pada tampilan root.

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

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

Terima kasih kepada: https://forums.xamarin.com/discussion/1856/how-to-disable-auto-focus-on-edit-text

Tentang windowSoftInputMode

Masih ada hal lain yang perlu diperhatikan. Secara default, Android akan secara otomatis menetapkan fokus awal ke EditText pertama atau kontrol yang dapat difokuskan di Aktivitas Anda. Secara alami mengikuti bahwa InputMethod (biasanya keyboard lunak) akan merespons acara fokus dengan menampilkan dirinya sendiri. Atribut windowSoftInputMode di AndroidManifest.xml, saat disetel ke stateAlwaysHidden, memerintahkan keyboard untuk mengabaikan fokus awal yang ditetapkan secara otomatis ini.

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

referensi yang bagus

CrandellWS
sumber
6
<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();

Saya menggunakan ini ketika sudah selesai memperbarui info profil dan menghapus semua fokus dari EditText di tata letak saya

====> Update: Dalam konten tata letak induk, baris edit EditText saya:

android:focusableInTouchMode="true"
Ho Luong
sumber
3

Bagaimana dengan menambahkan android:windowSoftInputMode="stateHidden"aktivitas Anda di manifes.

Diambil dari orang pintar yang mengomentari ini: https://stackoverflow.com/a/2059394/956975

marienke
sumber
2

Pertama-tama, ini akan 100% berhasil ........

  1. Buat onResume()metode.
  2. Di dalamnya, onResume()temukan pemandangan yang terus menerus memusatkan perhatian findViewById().
  3. Di dalam onResume()set requestFocus()ini ke tampilan ini.
  4. Di dalam onResume()set clearFocusini ke tampilan ini.
  5. Masuk dalam xml dengan tata letak yang sama dan temukan tampilan atas yang ingin Anda fokuskan dan tetapkan focusable benar dan focusableInTuchbenar.
  6. Di dalam ini onResume() temukan tampilan atas olehfindViewById
  7. Di dalam ini onResume() setrequestFocus() ke tampilan ini pada akhirnya.
  8. Dan sekarang nikmati ......
pandey vishambar
sumber
2

Saya mencoba menonaktifkan dan mengaktifkan fokus untuk tampilan dan berhasil untuk saya (fokus disetel ulang):

focusedView.setFocusable(false);
focusedView.setFocusableInTouchMode(false);
focusedView.setFocusable(true);
focusedView.setFocusableInTouchMode(true);
Serhiy
sumber
1

Anda dapat mencoba mematikan kemampuan Aktivitas utama untuk menyimpan statusnya (sehingga melupakan kontrol apa yang memiliki teks dan apa yang memiliki fokus). Anda perlu memiliki cara lain untuk mengingat apa yang dimiliki EditText Anda dan mengisi kembali mereka di onResume (). Luncurkan sub-Aktivitas Anda dengan startActivityForResult () dan buat penangan onActivityResult () di Aktivitas utama Anda yang akan memperbarui EditText dengan benar. Dengan cara ini Anda dapat menyetel tombol yang tepat yang ingin Anda fokuskan padaResume () pada saat yang sama Anda mengisi ulang EditText dengan menggunakan myButton.post (new Runnable () {run () {myButton.requestFocus ();}});

Metode View.post () berguna untuk mengatur fokus pada awalnya karena runnable itu akan dijalankan setelah jendela dibuat dan semuanya tenang, memungkinkan mekanisme fokus berfungsi dengan baik pada saat itu. Saya menemukan bahwa mencoba menetapkan fokus selama onCreate / Start / Resume () biasanya mengalami masalah.

Harap dicatat bahwa ini adalah pseudo-code dan tidak diuji, tetapi ini adalah arah yang mungkin Anda coba.

Paman Kode Monyet
sumber
Setelah dipikir-pikir ... coba gunakan hal-hal View.post () terlebih dahulu daripada mematikan status Aktivitas yang disimpan. Itu mungkin melakukan trik untuk Anda semua dengan sendirinya.
Paman Kode Monyet
Sayangnya saya tidak lagi memiliki cara mudah untuk menguji ini untuk kami. Sejak itu saya memutuskan untuk meninggalkan model kode asli dan menggunakan HTML5 / CSS3 untuk aplikasi seluler, dan dengan demikian telah melengkapi kembali sistem saya. Tapi terima kasih atas jawaban yang tampaknya sangat mendalam. Saya memilihnya.
InteXX
1
android:focusableInTouchMode="true"
android:focusable="true"
android:clickable="true"

Tambahkan mereka ke ViewGroup Anda yang menyertakan EditTextView Anda. Ini berfungsi dengan baik untuk Constraint Layout saya. Semoga bantuan ini

Tánh Lee
sumber
0

Coba yang berikut ini (menelepon 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();
    }

}
5chw4hn
sumber