Android - coloque crianças dentro de um View?


169

Dada uma visualização, como posso obter as visualizações filho dentro dela?

Então, eu tenho uma exibição personalizada e o depurador mostra que mChildrenhá outras 7 visualizações. Eu preciso de uma maneira de acessar esses modos de exibição, mas não parece que exista uma API pública para fazer isso.

alguma sugestão?

EDITAR:

Minha visualização personalizada herda de AdapterView

Respostas:


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

Isso serve?


2
Qual é a melhor maneira de fazer isso recursivamente e, assim, gerar um objeto JSON de hierarquia de exibição?
jimbob

Supondo que o pai seja chamado ViewviewGroup
Prime624 16/01/19

57

Se você não quer apenas ter filhos diretos, mas também filhos de todos os filhos, é necessário fazê-lo recursivamente:

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

Para usar o resultado, você pode fazer algo assim:

    // 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
Esta chamada não é salva, como, por exemplo, filho pode ser do tipo View e não do ViewGroup, portanto, a chamada recursiva de getAllChildren pode causar uma exceção, pois a conversão falha. Portanto, você deve adicionar um retorno if (! (V instanceof ViewGroup)); antes do elenco
Phil

2
Pequena sugestão: substitua o loop for pelo for (int i = 0, n = vg.getChildCount(); i < n; i++) Android, acessar variáveis ​​locais em vez de chamar um método tende a ser muito mais rápido. Dessa forma, um método é chamado apenas uma vez por grupo de visualizações e, em execuções subsequentes, uma variável local é usada.
ArtOfWarfare

Eu mudei o código por causa da sugestão de Phil Diegmann. Espero que isto ajude. Funciona para mim.
IHeartAndroid

1
Legal. Eu sugeriria apenas adicionar um 'includeViewGroups' booleano e somente se for verdadeiro, iewArrayList.add (v); Isso é útil para iterar em um adaptador (e eu preciso apenas das folhas). Obrigado!
JRun

20

Você sempre pode acessar visualizações filho via View.findViewById () http://developer.android.com/reference/android/view/View.html#findViewById(int ).

Por exemplo, dentro de uma atividade / exibição:

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

ou se você tiver uma referência a uma visualização:

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

Eu não tenho acesso a ids, a interface do usuário é gerado por meio de código, estou escrevendo automação usando Robotium, então as coisas que posso fazer são limitadas
aryaxt

@ jonson, nada útil se você precisar de todas as crianças.
Pacerier 17/11/19


17

Vou apenas fornecer essa resposta como um algoritmo recursivo do @HeartAndroid alternativo para descobrir todas as crianças Viewem uma hierarquia de exibição. Observe que, no momento da redação deste artigo, a solução recursiva é falha , pois contém duplicatas em seu resultado.

Para aqueles que têm problemas para entender a recursão, aqui está uma alternativa não recursiva. Você ganha pontos de bônus para perceber isso é também um em largura alternativa de pesquisa para a profundidade-primeira abordagem da solução recursiva.

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

Alguns testes rápidos (nada formal) sugerem que essa alternativa também é mais rápida, embora isso provavelmente tenha a ver com o número de novas ArrayListinstâncias que a outra resposta cria. Além disso, os resultados podem variar de acordo com a vertical / horizontal da hierarquia de visualizações.

Publicado em: Android | Obter todos os elementos filhos de um ViewGroup


7

Aqui está uma sugestão: você pode obter o ID(especificado, por exemplo, por android:id="@+id/..My Str..), que foi gerado Rusando o seu nome (por exemplo My Str). Um trecho de código usando o getIdentifier()método seria:

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

De dentro de Activity, um exemplo de uso associado a findViewById:

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

Como uma atualização para aqueles que se deparam com essa pergunta depois de 2018, se você estiver usando o Kotlin, basta usar a propriedade de extensão Android KTX ViewGroup.children para obter uma sequência dos filhos imediatos do View.


0

Para atualizar um layout de tabela (TableLayout), acabei tendo que usar a abordagem recursiva mencionada acima para obter todos os filhos das crianças e assim por diante.

Minha situação foi um pouco simplificada, porque eu só precisava trabalhar com LinearLayout e essas classes foram estendidas, como TableLayout. E eu só estava interessado em encontrar crianças TextView. Mas acho que ainda é aplicável a essa pergunta.

A classe final é executada como um thread separado, o que significa que pode fazer outras coisas em segundo plano antes de analisar os filhos. O código é pequeno e simples e pode ser encontrado no github: https://github.com/jkincali/Android-LinearLayout-Parser


0

Este método utiliza todas as visualizações dentro de um layout, semelhante à resposta de Alexander Kulyakhtin. A diferença é que ele aceita qualquer tipo de layout pai e retorna uma lista de visualizações de matriz.

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;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.