Взгляды детей Занимает слишком много времени, чтобы рисовать

У меня есть дизайн макета Android, в котором у меня есть AppBar макет, который будет содержать Toolbar и еще один LinearLayout дизайн с кругом Drawable как TextView, который с той же высоты. Поэтому, когда я пытаюсь получить Toolbar или же AppBar высота / ширина возвращается только 0.

activity_main.xml:

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="enterAlways" />
       <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:layout_gravity="center_horizontal"
            android:background="@color/colorPrimary"
            android:orientation="horizontal"
            app:layout_scrollFlags="enterAlways">

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/marked_questions"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_default"
                    android:text="18" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Marked" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/correct"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_6"
                    android:text="18"

                    />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Correct" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/wrong"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_wrong"
                    android:text="18" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Wrong" />
            </LinearLayout>


            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/conflicts"
                    style="@style/textview_summary_omr_toolbar_count"
                    android:background="@drawable/bg_percentage_3"
                    android:text="0" />

                <TextView
                    style="@style/textview_heading_summary_omr_toolbar"
                    android:text="Conflicts" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_gravity="center_horizontal"
                android:layout_marginLeft="2dp"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    style="@style/textview_summary_omr_toolbar_count"
                    android:text="Score:"
                    android:textColor="@android:color/white" />

                <TextView
                    android:id="@+id/marks_scored"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:gravity="center"
                    android:text="18/30"
                    android:textColor="@android:color/white"
                    android:textSize="18sp" />

            </LinearLayout>


        </LinearLayout>
    </android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>

MainActivity.java: здесь я инициализирую Toolbar а также AppBar и попробуйте напечатать ширину и высоту обоих в логах, что возвращает мне ноль.

public class MainActivity extends AppCompatActivity {
  private Toolbar toolbar;
  private AppBarLayout app_bar;
protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       app_bar = (AppBarLayout) findViewById(R.id.app_bar);
       toolbar = (Toolbar) findViewById(R.id.toolbar);
       logToolbarLayoutParams();

}
private void logToolbarLayoutParams() {
        Log.d(TAG,"Toolbar width/Height"+this.toolbar.getWidth()+"/"+this.toolbar.getHeight());
        Log.d(TAG,"App_bar width/height"+this.app_bar.getWidth()+"/"+this.app_bar.getHeight());

}

Я также упомянул этот вопрос в stackru.

final AppBarLayout app_bar = (AppBarLayout) findViewById(R.id.app_bar);
                ViewTreeObserver vto = app_bar.getViewTreeObserver();
                vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        app_bar.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        Log.d(TAG, "Global layout");
                        logToolbarLayoutParams();
            }
        });

Если я добавлю следующий код в моем MainActivity это дает мне правильную высоту и ширину Toolbar, Из вопроса о стековом потоке, о котором я упоминал ранее, я узнал, что на экране не отображались виды, поэтому мне придется подождать. Но мое сомнение в том, что дизайн, который я указал, не сложен? почему рисование на экране занимает много времени? я что-то пропустил?

Я использовал Hierarchy Viewer, чтобы узнать, что заставляет дочерний макет загружаться медленно. Я обнаружил, что я использую несколько LinearLayout где одинокий RelativeLayout может быть использован для получения той же структуры. Я изменил свой дизайн макета следующим образом. Тем не менее, я сталкиваюсь с той же проблемой.

обновлено: activity_main.xml:

<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="enterAlways" />
   <RelativeLayout
         android:id="@+id/summary_bottom_sheet"
         android:layout_width="match_parent"
         android:layout_height="?actionBarSize"
         android:layout_gravity="center_horizontal"
         android:background="@color/colorPrimary">


         <TextView
             android:id="@+id/marked_questions"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_alignParentLeft="true"
             android:layout_alignParentStart="true"
             android:background="@drawable/bg_percentage_default"
             android:text="18" />

         <TextView
             android:id="@+id/marked_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/marked_questions"
             android:layout_toRightOf="@+id/marked_questions"
             android:text="Marked" />


         <TextView
             android:id="@+id/correct"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/marked_textview"
             android:layout_toRightOf="@+id/marked_textview"
             android:background="@drawable/bg_percentage_6"
             android:text="18"

             />

         <TextView
             android:id="@+id/correct_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/correct"
             android:layout_toRightOf="@+id/correct"
             android:text="Correct" />


         <TextView
             android:id="@+id/wrong"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/correct_textview"
             android:layout_toRightOf="@+id/correct_textview"
             android:background="@drawable/bg_percentage_wrong"
             android:text="18" />

         <TextView
             android:id="@+id/wrong_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/wrong"
             android:layout_toRightOf="@+id/wrong"
             android:text="Wrong" />


         <TextView
             android:id="@+id/conflicts"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_toEndOf="@+id/wrong_textview"
             android:layout_toRightOf="@+id/wrong_textview"
             android:background="@drawable/bg_percentage_3"
             android:text="0" />

         <TextView
             android:id="@+id/conflicts_textview"
             style="@style/textview_heading_summary_omr_toolbar"
             android:layout_toEndOf="@+id/conflicts"
             android:layout_toRightOf="@+id/conflicts"
             android:text="Conflicts" />


         <TextView
             android:id="@+id/score_textview"
             style="@style/textview_summary_omr_toolbar_count"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_toEndOf="@+id/conflicts_textview"
             android:layout_toRightOf="@+id/conflicts_textview"
             android:background="@null"
             android:gravity="center"
             android:text="Score:"
             android:textColor="@android:color/white" />

         <TextView
             android:id="@+id/marks_scored"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_centerVertical="true"
             android:layout_gravity="center_vertical"
             android:layout_toEndOf="@+id/score_textview"
             android:layout_toRightOf="@+id/score_textview"
             android:gravity="center"
             android:text="18/30"
             android:textColor="@android:color/white"
             android:textSize="18sp" />
   </RelativeLayout>
 </android.support.design.widget.AppBarLayout>
 </android.support.design.widget.CoordinatorLayout>

Ниже приведен просмотрщик иерархии Hierarchy_viewer Изображение, которое я получаю

5 ответов

Решение

Вы думаете об этом неправильно. В вашем макете нет ничего плохого (поскольку это касается вашего вопроса). Чтобы доказать это, полностью измените свой макет и попробуйте снова

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
    Log.d("SomeTag", "w: " + recyclerView.getWidth() + ", h: " + recyclerView.getHeight());
    Log.d("SomeTag", "mw: " + recyclerView.getMeasuredWidth() + ", mh: " + recyclerView.getMeasuredHeight());
}

Выход для представления только с 1 дочерним элементом все еще

12-14 10:17:04,902 3004-3004 /? D / SomeTag: w: 0, h: 0

12-14 10:17:04,902 3004-3004/? D/SomeTag: mw: 0, mh: 0

Таким образом, в вашем макете нет ничего плохого (за исключением того, что у вас есть неправильный номер. Вы вызываете метод logToolbarLayoutParams, но вы вообще не обращаетесь к параметрам макета. Вы пытаетесь получить свойства объекта представления до того, как произошел проход макета.. Может это твое замешательство). Так что вам не хватает понимания системы макетов Android, групп просмотра и представлений. Romain Guy в один прекрасный момент на Devoxx говорил о том, как создать собственный FlowLayout. Либо сайт не работает, либо видео отключено, но вот код в GitHub. Если вы посмотрите на метод onLayout, вы увидите, что ViewGroup проходит по всем дочерним элементам и вызывает child.layout(). До тех пор, пока этот метод не будет вызван, методы view.getWidth и view.getHeight будут возвращать 0. И этот метод вызывается ОС всякий раз, когда она планирует это. Таким образом, в основном вы пытаетесь получить доступ к ширине и высоте сразу же до того, как ОС запланирует макет. Создайте собственную группу просмотра, добавьте несколько точек разрыва и сделайте это.

toolbar.getWidth() скажет вам ширину вида после того, как он был измерен и выложен.
После надувания вида его ширина и высота всегда будут 0 потому что ни measure() ни layout() произошло

protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   toolbar = (Toolbar) findViewById(R.id.toolbar);

   // check after inflation -> will be 0
   logToolbarLayoutParams();
}

onGlobalLayout() сообщает правильные данные, потому что, как следует из названия, оба onMeasure() а также onLayout() были вызваны. Размеры вида известны. Это не означает, что вид был нарисован. onDraw() это третий и последний шаг.

Это также не имеет никакого значения, насколько сложен ваш макет или какие виды вы используете. Проходы измерения и компоновки не происходят сразу после надувания представления.


Чтобы получить и работать с правильными размерами вашего взгляда, у вас есть 3 варианта:

  1. использование ViewTreeObserver.OnGlobalLayoutListener#onGlobalLayout() как вы уже предложили
  2. Проверьте размер позднее, когда вы можете быть уверены, что представление было нарисовано (например, при взаимодействии с пользователем, в OnClickListener)
  3. Перейти на заказ и создать свой собственный View, Там вы получите возможность справиться со всеми onMeasure, onLayout, а также onDraw сам!

Рисование представлений занимает значительное время, но мы можем уменьшить его, удалив вложенную компоновку, и сделать иерархию представлений плоской, используя RelativeLayout или Constrain.

Найти оверрейд. Выберите "Показать области перерисовки" в параметрах отладки графического редактора отладки в настройках.

Изучите эту и эту важную статью на developer.android по теме оптимизации раскладок.

Я только что решил ту же проблему в том же случае. Все решения с ViewTreeObserver.OnGlobalLayoutListener() выглядит грязно и не работает для меня. Самый простой способ узнать ширину и высоту на текущем экране выглядит так:

toolbar.post(new Runnable() {
        @Override
        public void run() {
            int headerWidth = toolbar.getWidth();
            int headerHeight = toolbar.getHeight();
            // do whatever you want ...
        }
    });

view.post() добавит ваш код в конец в очередь сообщений представления, когда все размеры будут уже рассчитаны. Имхо, это очевидно и более понятно, тогда OnGlobalLayoutListener(), Надеюсь, это поможет вам.

Во всяком случае, это решение просто "с задержкой получения размеров", как OnGlobalLayoutListener(), Но это нормальное поведение системы, для отображения представлений на экране требуется некоторое время. Наилучший способ - не ожидать вычисленных измерений - вместо этого вы должны координировать все отношения между представлениями в XML-файлах. Атрибуты как WRAP_CONTENT а также MATCH_PARENT это самый простой способ решить подобные проблемы

Вы пытаетесь получить ширину и высоту вида до его прикрепления к экрану, вы можете создать собственный вид и то, что вам нужно в методе onAttach

Другие вопросы по тегам