Взгляды детей Занимает слишком много времени, чтобы рисовать
У меня есть дизайн макета 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>
Ниже приведен просмотрщик иерархии Изображение, которое я получаю
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 варианта:
- использование
ViewTreeObserver.OnGlobalLayoutListener#onGlobalLayout()
как вы уже предложили - Проверьте размер позднее, когда вы можете быть уверены, что представление было нарисовано (например, при взаимодействии с пользователем, в
OnClickListener
) - Перейти на заказ и создать свой собственный
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