Intereting Posts
Имеются ли в операционной системе Android такие файлы, как / etc / passwd, / etc / shadow и / etc / group? XML-синтаксический анализ в Android? Текст кнопки Android не центрирован при использовании API 17 для рендеринга Возможно ли потерять соединение базы данных SQLite? Отделив тесты интеграции от модульных тестов в Android Studio Как программно добавлять сертификаты в доверительный магазин и использовать их для проверки подлинности сервера DexIndexOverflowException: Невозможно объединить новый индекс 65772 в инструкцию, отличную от jumbo !: Jumbo Mode? И / или Multi-Dex? Что стоит за сценой? Java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader Изменение дизайна материала AppCompat ActionBar Color Android: Удалить ключ ввода с клавиатуры Android: сгруппированные уведомления и резюме все еще показаны отдельно на 4.4 и ниже Невозможно разрешить хост «<insert URL here>» Нет адреса, связанного с именем хоста Как вы организуете модули и компоненты Dagger 2? Совместимость Android Layout Right Align Не удалось выполнить инструменты \ android.bat: решение

GetWidth () и getHeight () из View возвращает 0

Я динамически создаю все элементы в моем проекте Android. Я пытаюсь получить ширину и высоту кнопки, чтобы я мог повернуть эту кнопку вокруг. Я просто пытаюсь научиться работать с языком Android. Однако он возвращает 0.

Я провел некоторое исследование, и я увидел, что это нужно сделать где-то иначе, чем в onCreate() . Если кто-то может дать мне пример того, как это сделать, это было бы здорово.

Вот мой текущий код:

 package com.animation; import android.app.Activity; import android.os.Bundle; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.Button; import android.widget.LinearLayout; public class AnimateScreen extends Activity { //Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout ll = new LinearLayout(this); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); layoutParams.setMargins(30, 20, 30, 0); Button bt = new Button(this); bt.setText(String.valueOf(bt.getWidth())); RotateAnimation ra = new RotateAnimation(0,360,bt.getWidth() / 2,bt.getHeight() / 2); ra.setDuration(3000L); ra.setRepeatMode(Animation.RESTART); ra.setRepeatCount(Animation.INFINITE); ra.setInterpolator(new LinearInterpolator()); bt.startAnimation(ra); ll.addView(bt,layoutParams); setContentView(ll); } 

Любая помощь приветствуется.

Solutions Collecting From Web of "GetWidth () и getHeight () из View возвращает 0"

Вы вызываете getWidth() слишком рано. Пользовательский интерфейс еще не был отмерен и выложен на экране.

Я сомневаюсь, что вы хотите делать то, что вы делаете, так или иначе – виджеты, анимированные, не меняют свои интерактивные области, поэтому кнопка будет реагировать на клики в исходной ориентации независимо от того, как она вращается.

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

Основная проблема заключается в том, что вам нужно подождать фазы рисования для фактических измерений (особенно с динамическими значениями, такими как wrap_content или match_parent ), но обычно эта фаза не была доведена до onResume() . Поэтому вам нужно обходное решение для ожидания этой фазы. Существуют разные возможные решения:

1. Слушайте события Draw / Layout: ViewTreeObserver

ViewTreeObserver запускается для разных событий рисования. Обычно OnGlobalLayoutListener – это то, что вы хотите получить для измерения, поэтому код в слушателе будет вызван после фазы компоновки, поэтому измерения будут готовы:

 view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); view.getHeight(); //height is ready } }); 

Примечание. Слушатель будет немедленно удален, потому что иначе он будет срабатывать при каждом событии макета. Если вам нужно поддерживать приложения SDK Lvl <16, используйте это, чтобы отменить регистрацию слушателя:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)

2. Добавьте runnable в очередь макета: View.post ()

Не очень хорошо известно и мое любимое решение. В основном просто используйте метод публикации «Вид» со своей собственной версией. Это в основном очереди вашего кода после измерения, макета и т. Д., Как заявляет Ромен Гай :

Очередь событий пользовательского интерфейса будет обрабатывать события по порядку. После вызова setContentView () очередь событий будет содержать сообщение с запросом на ретрансляцию, поэтому все, что вы отправляете в очередь, произойдет после прохода макета

Пример:

 final View view=//smth; ... view.post(new Runnable() { @Override public void run() { view.getHeight(); //height is ready } }); 

Преимущество над ViewTreeObserver :

  • Ваш код выполняется только один раз, и вам не нужно отключать Наблюдателя после выполнения, что может быть проблемой
  • Менее подробный синтаксис

Рекомендации:

3. Заменить метод onLayout Views

Это практично только в определенной ситуации, когда логика может быть инкапсулирована в самом представлении, иначе это довольно многословный и громоздкий синтаксис.

 view = new View(this) { @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); view.getHeight(); //height is ready } }; 

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

4. Проверьте, прошел ли этап компоновки

Если у вас есть код, который выполняется несколько раз при создании ui, вы можете использовать следующий метод поддержки v4 lib:

 View viewYouNeedHeightFrom = ... ... if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) { viewYouNeedHeightFrom.getHeight(); } 

Возвращает true, если представление прошло по крайней мере с одного макета, поскольку оно было последним прикреплено к окну или отсоединено от него.

Дополнительно: получение статически определенных измерений

Если достаточно просто получить статически определенную высоту / ширину, вы можете просто сделать это с помощью:

  • View.getMeasuredWidth()
  • View.getMeasuredHeigth()

Но помните, что это может отличаться от фактической ширины / высоты после рисования. Javadoc отлично описывает разницу:

Размер представления выражается шириной и высотой. В представлении фактически есть две пары значений ширины и высоты.

Первая пара известна как измеренная ширина и измеренная высота. Эти размеры определяют, как большой вид хочет быть внутри своего родителя (см. Макет для более подробной информации.) Измеренные размеры можно получить, вызвав getMeasuredWidth () и getMeasuredHeight ().

Вторая пара просто известна как ширина и высота, иногда ширина рисунка и высота рисунка. Эти размеры определяют фактический размер представления на экране, время рисования и после макета. Эти значения могут, но не обязательно, отличаться от измеренной ширины и высоты. Ширина и высота можно получить, вызвав getWidth () и getHeight ().

Мы можем использовать

 @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); //Here you can get the size! } 

Я использовал это решение, которое, я думаю, лучше, чем onWindowFocusChanged (). Если вы откроете DialogFragment, затем поверните телефон, onWindowFocusChanged будет вызываться только тогда, когда пользователь закрывает диалог):

  yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // Ensure you call it only once : yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this); // Here you can get the size :) } }); 

Изменить: поскольку removeGlobalOnLayoutListener устарел, вы должны теперь:

 @SuppressLint("NewApi") @SuppressWarnings("deprecation") @Override public void onGlobalLayout() { // Ensure you call it only once : if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) { container.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { container.getViewTreeObserver().removeGlobalOnLayoutListener(this); } // Here you can get the size :) } 

Как заявляет Ян в этой статье разработчиков Android :

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

В нижней строке, если вы вызываете getWidth () и т. Д. В конструкторе, он будет возвращать ноль. Процедура состоит в том, чтобы создать все элементы вашего представления в конструкторе, а затем дождаться, когда будет вызван метод OnSizeChanged (), который вы хотите увидеть, – вот когда вы впервые узнаете свой реальный размер, так что вы устанавливаете размеры ваших элементов графического интерфейса.

Имейте в виду, что onSizeChanged () иногда вызывается с параметрами zero-check для этого случая и немедленно возвращается (так что вы не получаете деления на ноль при расчете вашего макета и т. Д.). Через некоторое время он будет вызываться с реальными значениями.

Если вам нужно получить ширину какого-либо виджета перед его отображением на экране, вы можете использовать getMeasuredWidth () или getMeasuredHeight ().

 myImage.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); int width = myImage.getMeasuredWidth(); int height = myImage.getMeasuredHeight(); 

Я предпочел бы использовать OnPreDrawListener() вместо addOnGlobalLayoutListener() , поскольку он вызывается раньше.

  view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { view.getViewTreeObserver().removeOnPreDrawListener(this); // put your code here return false; } });