Android: far entrare i bambini in una vista?


169

Vista vista come posso ottenere le viste figlio al suo interno?

Quindi ho una vista personalizzata e il debugger mostra che sotto mChildrenci sono altre 7 viste. Ho bisogno di un modo per accedere a queste visualizzazioni ma non sembra che ci sia un'API pubblica per farlo.

eventuali suggerimenti?

MODIFICARE:

La mia vista personalizzata eredita da AdapterView

Risposte:


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

Lo farà?


2
Qual è il modo migliore per farlo in modo ricorsivo e quindi generare un oggetto JSON della gerarchia della vista?
Jimbob,

Supponendo che il genitore View sia chiamatoviewGroup
Prime624

57

Se non vuoi solo ottenere tutti i bambini diretti ma tutti i bambini e così via, devi farlo in modo ricorsivo:

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

Per usare il risultato potresti fare qualcosa del genere:

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

8
Questa chiamata non viene salvata, poiché ad esempio figlio può essere di tipo Visualizza e non di ViewGroup, quindi la chiamata ricorsiva di getAllChildren potrebbe causare un'eccezione, poiché il cast non riesce. Quindi dovresti aggiungere un if (! (V instanceof ViewGroup)) return; prima del cast
Phil

2
Piccolo suggerimento: sostituisci il tuo ciclo for con for (int i = 0, n = vg.getChildCount(); i < n; i++) Su Android, accedere alle variabili locali invece di chiamare un metodo tende ad essere molto più veloce. In questo modo, un metodo viene chiamato solo una volta per gruppo di viste e quindi nelle esecuzioni successive viene utilizzata una variabile locale.
ArtOfWarfare il

Ho cambiato il codice a causa del suggerimento di Phil Diegmann. Spero che questo ti aiuti. Per me va bene.
IHeartAndroid

1
Freddo. Suggerirei solo di aggiungere un booleano 'includeViewGroups' e solo se è vero, iewArrayList.add (v); Questo è utile per iterare in un adattatore (e ho bisogno solo delle foglie). Grazie!
JRun

20

Puoi sempre accedere alle visualizzazioni figlio tramite View.findViewById () http://developer.android.com/reference/android/view/View.html#findViewById(int ).

Ad esempio, all'interno di un'attività / vista:

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

o se hai un riferimento a una vista:

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

Non ho accesso agli ID, l'interfaccia utente viene generata tramite codice, sto scrivendo automazione usando robotium, quindi le cose che posso fare sono limitate
aryaxt

@jonson, non è affatto utile se devi avere tutti i bambini.
Pacerier,


17

Fornirò questa risposta come un'alternativa all'algoritmo ricorsivo di IHeartAndroid per scoprire tutti i bambini Viewin una gerarchia di viste. Si noti che al momento della stesura di questo documento, la soluzione ricorsiva è viziata dal fatto che conterrà duplicati nel suo risultato.

Per coloro che hanno difficoltà ad avvolgere la testa attorno alla ricorsione, ecco un'alternativa non ricorsiva. Ottieni punti bonus se ti rendi conto che questa è anche una prima alternativa di ricerca all'approccio approfondito della soluzione ricorsiva.

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

Un paio di test rapidi (niente di formale) suggeriscono che questa alternativa è anche più veloce, sebbene ciò abbia molto probabilmente a che fare con il numero di nuove ArrayLististanze create dall'altra risposta. Inoltre, i risultati possono variare in base alla verticale / orizzontale della gerarchia della vista.

Pubblicazioni incrociate da: Android | Ottieni tutti gli elementi figlio di un ViewGroup


7

Ecco un suggerimento: è possibile ottenere il ID(specificato ad es. Da android:id="@+id/..My Str..) che è stato generato Rutilizzando il suo nome (ad es My Str.). Uno snippet di codice che utilizza il getIdentifier()metodo sarebbe quindi:

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

Dall'interno di un Activityesempio di utilizzo associato a findViewByIdsarebbe:

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

3

Come aggiornamento per coloro che incontrano questa domanda dopo il 2018, se stai usando Kotlin, puoi semplicemente utilizzare la proprietà dell'estensione Android KTX ViewGroup.children per ottenere una sequenza dei figli immediati di View.


0

Al fine di aggiornare un layout di tabella (TableLayout) ho finito per usare l'approccio ricorsivo sopra menzionato per ottenere tutti i bambini dei bambini e così via.

La mia situazione era in qualche modo semplificata perché avevo solo bisogno di lavorare con LinearLayout e quelle classi estese da essa come TableLayout. E mi interessava solo trovare i bambini TextView. Ma penso che sia ancora applicabile a questa domanda.

La classe finale viene eseguita come thread separato, il che significa che può fare altre cose in background prima di analizzare i bambini. Il codice è piccolo e semplice e può essere trovato su github: https://github.com/jkincali/Android-LinearLayout-Parser


0

Questo metodo prende tutte le viste all'interno di un layout, è simile alla risposta di Alexander Kulyakhtin. La differenza è che accetta qualsiasi tipo di layout principale e restituisce un elenco di visualizzazioni di 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.