Android - завести дітей всередині перегляду?


169

Дано подання, як я можу отримати уявлення про дитини всередині нього?

Таким чином, у мене є спеціальний перегляд, і налагоджувальне програмне забезпечення показує, що під ним mChildrenіснує ще 7 переглядів. Мені потрібен спосіб отримати доступ до цих поглядів, але, схоже, немає публічного API для цього.

будь-які пропозиції?

Редагувати:

Мій власний вид успадковується від AdapterView

Відповіді:


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

Це зробить?


2
Який найкращий спосіб зробити це рекурсивно і тим самим генерувати об’єкт JSON виду перегляду?
jimbob

Припустимо, що батьківський вид названийviewGroup
Prime624

57

Якщо ви хочете не тільки всіх дітей, але і дітей тощо, це потрібно робити рекурсивно:

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

Для використання результату ви можете зробити щось подібне:

    // 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
Цей виклик не є збереженням, оскільки, наприклад, дочірня може мати тип View, а не ViewGroup, тому рекурсивний виклик getAllChildren може спричинити виняток, оскільки виступ не вдається. Тому слід додати повернення if (! (V instanceof ViewGroup)); перед акторським складом
Phil Phil

2
Невелика пропозиція: замініть свій цикл for (int i = 0, n = vg.getChildCount(); i < n; i++) на Android, доступ до локальних змінних замість виклику методу, як правило, набагато швидший. Таким чином, метод викликається лише один раз у групі перегляду, а потім на наступних запусках використовується локальна змінна.
ArtOfWarfare

Я змінив код через пропозицію Філа Дігмана. Сподіваюся, це допомагає. Працює для мене.
IHeartAndroid

1
Класно. Я б тільки запропонував додати логічне "includeViewGroups" і лише якщо це правда, iewArrayList.add (v); Це корисно для ітерації в адаптері (і мені потрібні лише листя). Дякую!
JRun

20

Ви завжди можете отримати доступ до дитячих подань через View.findViewById () http://developer.android.com/reference/android/view/View.html#findViewById(int ).

Наприклад, у межах діяльності / перегляду:

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

або якщо у вас є посилання на вид:

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

У мене немає доступу до ідентифікаторів, інтерфейс користувача генерується за допомогою коду, я пишу автоматизацію за допомогою robotium, тому речі, які я можу зробити, обмежені
aryaxt

@jonson, зовсім не корисно, якщо вам потрібно завести всіх дітей.
Pacerier


17

Я просто надам цю відповідь як альтернативний рекурсивний алгоритм @ IHeartAndroid для виявлення всіх дітей Viewу ієрархії перегляду. Зауважимо, що на момент написання цього запису рекурсивне рішення є помилковим у тому, що воно буде містити дублікати у своєму результаті.

Для тих, хто має проблеми з обгортанням голови навколо рекурсії, ось нерекурсивна альтернатива. Ви отримуєте бонусні бали, усвідомлюючи це, також є альтернативою пошуку на широті в першу чергу на підході до рекурсивного рішення.

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

Кілька швидких тестів (нічого формального) припускають, що ця альтернатива також є швидшою, хоча це, швидше за все, пов'язане з кількістю нових ArrayListпримірників, які створює інша відповідь. Також результати можуть змінюватися залежно від того, наскільки вертикальною / горизонтальною є ієрархія перегляду.

Перехресне повідомлення від: Android | Отримати всі дитячі елементи ViewGroup


7

Ось пропозиція: ви можете отримати ID(вказаний, наприклад, android:id="@+id/..My Str..), який був створений Rза допомогою даного імені (наприклад My Str). Фрагмент коду з використанням getIdentifier()методу буде:

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

Зсередини Activity, прикладом використання в поєднанні 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

Як оновлення для тих, хто стикається з цим питанням після 2018 року, якщо ви використовуєте Kotlin, ви можете просто скористатися властивістю розширення Android KTX ViewGroup.children, щоб отримати послідовність найближчих дітей View.


0

Для того, щоб оновити макет таблиці (TableLayout), мені в кінцевому підсумку довелося використовувати рекурсивний підхід, згаданий вище, щоб отримати всіх дітей дітей тощо.

Моя ситуація була дещо спрощеною, тому що мені потрібно було працювати лише з LinearLayout і з тими класами, розширеними з неї, як TableLayout. І мені було цікаво лише знайти TextView дітей. Але я думаю, що це все ще застосовне до цього питання.

Заключний клас працює як окрема нитка, а це означає, що він може робити інші речі у фоновому режимі, перш ніж розбирати для дітей. Код невеликий і простий і його можна знайти на веб- сайті github: https://github.com/jkincali/Android-LinearLayout-Parser


0

Цей метод займає всі погляди всередині макета, це схоже на відповідь Олександра Куляхтіна. Різниця полягає в тому, що він приймає будь-який тип батьківських макетів і повертає список переглядів масивів.

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.