Android - dapatkan anak-anak di dalam Tampilan?

169

Diberi Tampilan, bagaimana saya bisa mendapatkan pandangan anak di dalamnya?

Jadi saya punya tampilan kustom dan debugger menunjukkan bahwa di bawah ini mChildrenada 7 tampilan lainnya. Saya perlu cara untuk mengakses pandangan ini tetapi sepertinya tidak ada API publik untuk melakukan ini.

ada saran?

EDIT:

Tampilan kustom saya berasal dari AdapterView

aryaxt
sumber

Jawaban:

313
for(int index = 0; index < ((ViewGroup) viewGroup).getChildCount(); index++) {
    View nextChild = ((ViewGroup) viewGroup).getChildAt(index);
}

Akankah itu berhasil?

Alexander Kulyakhtin
sumber
2
Apa cara terbaik untuk melakukan ini secara rekursif dan dengan demikian menghasilkan objek tampilan heirarki JSON?
jimbob
Dengan asumsi View induk dinamaiviewGroup
Prime624
57

Jika Anda tidak hanya ingin mendapatkan semua anak langsung tetapi semua anak-anak dan sebagainya, Anda harus melakukannya secara rekursif:

private ArrayList<View> getAllChildren(View v) {

    if (!(v instanceof ViewGroup)) {
        ArrayList<View> viewArrayList = new ArrayList<View>();
        viewArrayList.add(v);
        return viewArrayList;
    }

    ArrayList<View> result = new ArrayList<View>();

    ViewGroup vg = (ViewGroup) v;
    for (int i = 0; i < vg.getChildCount(); i++) {

        View child = vg.getChildAt(i);

        ArrayList<View> viewArrayList = new ArrayList<View>();
        viewArrayList.add(v);
        viewArrayList.addAll(getAllChildren(child));

        result.addAll(viewArrayList);
    }
    return result;
}

Untuk menggunakan hasilnya Anda bisa melakukan sesuatu seperti ini:

    // check if a child is set to a specific String
    View myTopView;
    String toSearchFor = "Search me";
    boolean found = false;
    ArrayList<View> allViewsWithinMyTopView = getAllChildren(myTopView);
    for (View child : allViewsWithinMyTopView) {
        if (child instanceof TextView) {
            TextView childTextView = (TextView) child;
            if (TextUtils.equals(childTextView.getText().toString(), toSearchFor)) {
                found = true;
            }
        }
    }
    if (!found) {
        fail("Text '" + toSearchFor + "' not found within TopView");
    }
IHeartAndroid
sumber
8
Panggilan ini tidak menyimpan, misalnya anak bisa dari tipe View dan bukan dari ViewGroup, sehingga panggilan rekursif getAllChildren dapat menyebabkan pengecualian, karena para pemain gagal. Jadi Anda harus menambahkan if (! (V instanceof ViewGroup)) kembali; di hadapan para pemeran
Phil
2
Saran kecil: ganti loop Anda dengan for (int i = 0, n = vg.getChildCount(); i < n; i++) Di Android, mengakses variabel lokal alih-alih memanggil metode cenderung lebih cepat. Dengan cara ini, suatu metode dipanggil hanya satu kali per kelompok tampilan dan kemudian dijalankan berikutnya variabel lokal digunakan.
ArtOfWarfare
Saya mengubah kode karena saran dari Phil Diegmann. Semoga ini membantu. Bekerja untukku.
IHeartAndroid
1
Keren. Saya hanya akan menyarankan menambahkan 'includeViewGroups' boolean dan hanya jika itu benar, iewArrayList.add (v); Ini berguna untuk iterasi di Adaptor (dan saya hanya perlu daun). Terima kasih!
JRun
20

Anda selalu dapat mengakses tampilan anak melalui View.findViewById () http://developer.android.com/reference/android/view/View.html#findViewById(int ).

Misalnya, dalam suatu kegiatan / tampilan:

...
private void init() {
  View child1 = findViewById(R.id.child1);
}
...

atau jika Anda memiliki referensi ke tampilan:

...
private void init(View root) {
  View child2 = root.findViewById(R.id.child2);
}
jonson
sumber
Saya tidak memiliki akses ke id, UI dihasilkan melalui kode, saya menulis otomasi menggunakan robotium, sehingga hal-hal yang dapat saya lakukan terbatas
aryaxt
@ Jonons, tidak berguna sama sekali jika Anda perlu mendapatkan semua anak.
Pacerier
Juga quora.com/unanswered/…
Pacerier
17

Saya hanya akan memberikan jawaban ini sebagai alternatif algoritma rekursif @ IHeartAndroid untuk menemukan semua anak Viewdalam hierarki tampilan. Perhatikan bahwa pada saat penulisan ini, solusi rekursif cacat karena akan berisi duplikat dalam hasilnya.

Bagi mereka yang memiliki kesulitan membungkus kepala mereka di sekitar rekursi, inilah alternatif non-rekursif. Anda mendapatkan poin bonus karena menyadari ini juga merupakan alternatif pencarian pertama untuk pendekatan mendalam-pertama dari solusi rekursif.

private List<View> getAllChildrenBFS(View v) {
    List<View> visited = new ArrayList<View>();
    List<View> unvisited = new ArrayList<View>();
    unvisited.add(v);

    while (!unvisited.isEmpty()) {
        View child = unvisited.remove(0);
        visited.add(child);
        if (!(child instanceof ViewGroup)) continue;
        ViewGroup group = (ViewGroup) child;
        final int childCount = group.getChildCount();
        for (int i=0; i<childCount; i++) unvisited.add(group.getChildAt(i));
    }

    return visited;
}

Beberapa tes cepat (tidak formal) menunjukkan alternatif ini juga lebih cepat, meskipun itu kemungkinan besar berkaitan dengan jumlah ArrayListcontoh baru yang diciptakan oleh jawaban lain. Juga, hasil dapat bervariasi berdasarkan seberapa vertikal / horizontal hierarki tampilan.

Diposting silang dari: Android | Dapatkan semua elemen anak-anak dari ViewGroup

MH.
sumber
7

Berikut ini adalah saran: Anda bisa mendapatkan ID(ditentukan misalnya oleh android:id="@+id/..My Str..) yang dihasilkan Rdengan menggunakan nama yang diberikan (misalnya My Str). Potongan kode yang menggunakan getIdentifier()metode akan menjadi:

public int getIdAssignedByR(Context pContext, String pIdString)
{
    // Get the Context's Resources and Package Name
    Resources resources = pContext.getResources();
    String packageName  = pContext.getPackageName();

    // Determine the result and return it
    int result = resources.getIdentifier(pIdString, "id", packageName);
    return result;
}

Dari dalam Activity, contoh penggunaan yang digabungkan dengan findViewByIdadalah:

// Get the View (e.g. a TextView) which has the Layout ID of "UserInput"
int rID = getIdAssignedByR(this, "UserInput")
TextView userTextView = (TextView) findViewById(rID);
vanangelov
sumber
3

Sebagai pembaruan bagi mereka yang menemukan pertanyaan ini setelah 2018, jika Anda menggunakan Kotlin, Anda cukup menggunakan properti ekstensi KTX Android ViewGroup.children untuk mendapatkan urutan anak-anak langsung View.

Chuck Stein
sumber
0

Untuk menyegarkan tata letak tabel (TableLayout) saya akhirnya harus menggunakan pendekatan rekursif yang disebutkan di atas untuk mendapatkan semua anak-anak anak-anak dan sebagainya.

Situasi saya agak disederhanakan karena saya hanya perlu bekerja dengan LinearLayout dan kelas-kelas itu diperluas seperti TableLayout. Dan saya hanya tertarik menemukan anak-anak TextView. Tapi saya pikir itu masih berlaku untuk pertanyaan ini.

Kelas terakhir berjalan sebagai utas terpisah, yang artinya dapat melakukan hal-hal lain di latar belakang sebelum mengurai untuk anak-anak. Kode ini kecil dan sederhana dan dapat ditemukan di github: https://github.com/jkincali/Android-LinearLayout-Parser

jkincali
sumber
0

Metode ini mengambil semua tampilan di dalam tata letak, ini mirip dengan jawaban Alexander Kulyakhtin. Perbedaannya adalah, ia menerima semua jenis tata letak induk & mengembalikan Daftar tampilan Array.

public List<View> getAllViews(ViewGroup layout){
        List<View> views = new ArrayList<>();
        for(int i =0; i< layout.getChildCount(); i++){
            views.add(layout.getChildAt(i));
        }
        return views;
}
NJY404
sumber