распечатать иерархию представлений на устройстве - PullRequest
5 голосов
/ 03 июля 2011

Отладка моего приложения со странными результатами на телефонах Samsung, к которым у меня нет физического доступа.Я хотел бы попросить пользователя запустить инструментальное приложение, чтобы помочь отладке.Мое приложение получает view, в котором есть неизвестная (для меня ;-) иерархия (ViewGroups и т. Д.).Есть ли способ "пройтись" по View и распечатать в строку / ddms все компоненты View (и т. Д. ViewGroups и т. Д.)?

Это было бы сроднив инструмент HierarchyViewer - если бы у меня был доступ к устройству на уровне adb.

Обновление: я полагаю, я мог бы использовать метод

void dumpViewHierarchyWithProperties(Context context, ViewGroup group, BufferedWriter out, int level)

из ViewDebug.java источников ОС Android...

У кого-нибудь есть идеи получше?

Спасибо!

Ответы [ 5 ]

32 голосов
/ 03 сентября 2011

Вот функция полезности, которую я только что сделал для этой цели:

public static void printViewHierarchy(ViewGroup vg, String prefix) {
    for (int i = 0; i < vg.getChildCount(); i++) {
        View v = vg.getChildAt(i);
        String desc = prefix + " | " + "[" + i + "/" + (vg.getChildCount()-1) + "] "+ v.getClass().getSimpleName() + " " + v.getId();
        Log.v("x", desc);

        if (v instanceof ViewGroup) {
            printViewHierarchy((ViewGroup)v, desc);
        }
    }
}
10 голосов
/ 18 января 2017

Я создал служебный метод, который возвращает печатную форму иерархии с удобочитаемым идентификатором вида. Вот пример вывода:

[LinearLayout] no_id
  [CardView] com.example:id/card_view
    [RelativeLayout] no_id
      [LinearLayout] com.example:id/image_container
        [AppCompatImageView] com.example:id/incident_icon
        [CustomTextView] com.example:id/road_number
      [RelativeLayout] no_id
        [CustomTextView] com.example:id/distance_to_user
        [CustomTextView] com.example:id/obstruction_title
        [CustomTextView] com.example:id/road_direction
        [CustomTextView] com.example:id/obstruction_description
        [AppCompatImageView] com.example:id/security_related

Вот служебный метод:

public static String getViewHierarchy(@NonNull View v) {
    StringBuilder desc = new StringBuilder();
    getViewHierarchy(v, desc, 0);
    return desc.toString();
}

private static void getViewHierarchy(View v, StringBuilder desc, int margin) {
    desc.append(getViewMessage(v, margin));
    if (v instanceof ViewGroup) {
        margin++;
        ViewGroup vg = (ViewGroup) v;
        for (int i = 0; i < vg.getChildCount(); i++) {
            getViewHierarchy(vg.getChildAt(i), desc, margin);
        }
    }
}

private static String getViewMessage(View v, int marginOffset) {
    String repeated = new String(new char[marginOffset]).replace("\0", "  ");
    try {
        String resourceId = v.getResources() != null ? (v.getId() > 0 ? v.getResources().getResourceName(v.getId()) : "no_id") : "no_resources";
        return repeated + "[" + v.getClass().getSimpleName() + "] " + resourceId + "\n";
    } catch (Resources.NotFoundException e) {
        return repeated + "[" + v.getClass().getSimpleName() + "] name_not_found\n";
    }
}

Совет : мы используем этот метод для добавления иерархий представлений в некоторые отчеты о сбоях. В некоторых случаях это действительно полезно .

0 голосов
/ 19 марта 2019

Просто найдите пункт меню в BottomNavigationView и зарегистрируйте длинный щелчок.

View itemBag = bottomNavigationView.findViewById(R.id.action_bag);
    if (itemBag != null) {
      itemBag.setOnLongClickListener(BottomNavigationActivity.this::onLongClick);
    }

private boolean onLongClick(View v) {
    switch (v.getId()) {
      case R.id.action_bag: {
        showToastMessage(R.string.menu_shopping_bag);
      }
      break;
    }
    return false;
  }
0 голосов
/ 23 февраля 2019

почти то же самое с этим ответом , но с Kotlin:

fun getViewTree(root: ViewGroup): String{
    fun getViewDesc(v: View): String{
        val res = v.getResources()
        val id = v.getId()
        return "[${v::class.simpleName}]: " + when(true){
            res == null -> "no_resouces"
            id > 0 -> try{
                res.getResourceName(id)
            } catch(e: android.content.res.Resources.NotFoundException){
                "name_not_found"
            }
            else -> "no_id"
        }
    }

    val output = StringBuilder(getViewDesc(root))
    for(i in 0 until root.getChildCount()){
        val v = root.getChildAt(i)
        output.append("\n").append(
            if(v is ViewGroup){
                getViewTree(v).prependIndent("  ")
            } else{
                "  " + getViewDesc(v)
            }
        )
    }
    return output.toString()
}
0 голосов
/ 03 июля 2011

Эти представления не мои, они поступают из других приложений, поэтому я не могу коснуться кода, связанного с ними (я надуваю их из RemoteView)

Если вы получаетеa RemoteViews, и вы применяете это к чему-то в своей деятельности, у вас есть прямой доступ к полученному Views, ничем не отличающимся от того, если бы вы надували их из XML самостоятельно.Учитывая корень View, это просто вопрос прогулки с детьми (вероятно, в глубину, но это ваш звонок) и регистрации любой информации, которую вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...