Как получить размеры представления?

У меня есть представление, состоящее из tablelayout, tablerows и textviews. Я хочу, чтобы это выглядело как сетка. Мне нужно получить высоту и ширину этой сетки. Методы getheight() и getwidth() всегда возвращают 0. Это происходит, когда я форматирую сетку динамически, а также когда я использую xml-версию.

Как получить размеры для представления?


Вот моя тестовая программа, которую я использовал в Debug для проверки результатов:

import android.app.Activity;
import android.os.Bundle;
import android.widget.TableLayout;
import android.widget.TextView;

public class appwig extends Activity {  
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.maindemo);  //<- includes the grid called "board"
      int vh = 0;   
      int vw = 0;

      //Test-1 used the xml layout (which is displayed on the screen):
      TableLayout tl = (TableLayout) findViewById(R.id.board);  
      tl = (TableLayout) findViewById(R.id.board);
      vh = tl.getHeight();     //<- getHeight returned 0, Why?  
      vw = tl.getWidth();     //<- getWidth returned 0, Why?   

      //Test-2 used a simple dynamically generated view:        
      TextView tv = new TextView(this);
      tv.setHeight(20);
      tv.setWidth(20);
      vh = tv.getHeight();    //<- getHeight returned 0, Why?       
      vw = tv.getWidth();    //<- getWidth returned 0, Why?

    } //eof method
} //eof class

Ответ 1

Я считаю, что OP давно ушел, но в случае, если этот ответ сможет помочь будущим искателям, я решил опубликовать решение, которое я нашел. Я добавил этот код в свой метод onCreate():

EDITED: 07/05/11, чтобы включить код из комментариев:

final TextView tv = (TextView)findViewById(R.id.image_test);
ViewTreeObserver vto = tv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        LayerDrawable ld = (LayerDrawable)tv.getBackground();
        ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
        ViewTreeObserver obs = tv.getViewTreeObserver();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            obs.removeOnGlobalLayoutListener(this);
        } else {
            obs.removeGlobalOnLayoutListener(this);
        }
    }

});

Сначала я получаю окончательную ссылку на мой TextView (для доступа к методу onGlobalLayout()). Затем я получаю ViewTreeObserver из моего TextView и добавляю OnGlobalLayoutListener, переопределяя onGLobalLayout (здесь не похоже на метод суперкласса...) и добавление моего кода, который требует знания измерения взгляда на этого слушателя. Все работает так, как ожидалось для меня, поэтому я надеюсь, что это поможет.

Ответ 2

Я просто добавлю альтернативное решение, переопределяю ваш метод onWindowFocusChanged, и вы сможете получить значения getHeight(), getWidth() оттуда.

@Override
public void onWindowFocusChanged (boolean hasFocus) {
        // the height will be set at this point
        int height = myEverySoTallView.getMeasuredHeight(); 
}

Ответ 3

Вы пытаетесь получить ширину и высоту элементов, которые еще не были нарисованы.

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

И, возможно, я ошибаюсь, но setWidth() не всегда соблюдается, Layout определяет его дочерние элементы и решает, как их измерять (вызов child.measure()), поэтому, если вы установили setWidth(), вы не гарантированно получить эту ширину после того, как элемент будет нарисован.

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

Найдите Activity жизненный цикл для нахождения наилучшего момента.

http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

Я считаю, что хорошей практикой является использование OnGlobalLayoutListener следующим образом:

yourView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (!mMeasured) {
                // Here your view is already layed out and measured for the first time
                mMeasured = true; // Some optional flag to mark, that we already got the sizes
            }
        }
    });

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

Ответ 4

Используйте метод View post, подобный этому

post(new Runnable() {   
    @Override
    public void run() {
        Log.d(TAG, "width " + MyView.this.getMeasuredWidth());
        }
    });

Ответ 5

Я попытался использовать onGlobalLayout() для выполнения пользовательского форматирования TextView, но, как заметил @George Bailey, onGlobalLayout() действительно вызывается дважды: один раз на начальном пути макета и второй раз после изменения текста.

View.onSizeChanged() работает лучше для меня, потому что, если я изменяю текст там, метод вызывается только один раз (во время прохода макета), Для этого требуется подклассификация TextView, но на уровне API 11+ View. addOnLayoutChangeListener() можно использовать, чтобы избежать субклассификации.

Еще одна вещь, чтобы получить правильную ширину представления в View.onSizeChanged(), значение layout_width должно быть установлено на match_parent, а не wrap_content.

Ответ 6

Я думаю, это то, что вам нужно посмотреть: используйте onSizeChanged() вашего представления. Вот фрагмент расширенного кода о том, как использовать onSizeChanged() для динамического отображения макета или просмотра высоты и ширины http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html

Ответ 7

Как F.X. Вы можете использовать OnLayoutChangeListener для представления, которое вы хотите отслеживать

view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        // Make changes
    }
});

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

Ответ 8

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

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

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

Ответ 9

Вы должны взглянуть на жизненный цикл View: http://developer.android.com/reference/android/view/View.html Как правило, вы не должны знать ширину и высоту, пока ваша активность не появится в состоянии onResume.

Ответ 10

ViewTreeObserver и onWindowFocusChanged() вообще не нужны.

Если вы раздуваете TextView как макет и/или помещаете в него некоторый контент и устанавливаете LayoutParams, то вы можете использовать getMeasuredHeight() и getMeasuredWidth().

НО вы должны быть осторожны с LinearLayouts (может быть, и другими ViewGroups). Проблема в том, что вы можете получить ширину и высоту после onWindowFocusChanged(), но если вы попытаетесь добавить в нее несколько видов, то вы не сможете получить эту информацию до тех пор, пока все не будет нарисовано. Я пытался добавить несколько TextViews в LinearLayouts, чтобы имитировать FlowLayout (стиль обертки), и поэтому не мог использовать Listeners. Как только процесс запущен, он должен продолжаться синхронно. Поэтому в таком случае вы можете захотеть сохранить ширину в переменной, чтобы использовать ее позже, так как при добавлении представлений в макет вам может понадобиться.

Ответ 11

Вы можете использовать широковещательную рассылку, которая вызывается в OnResume()

Например:

int vh = 0;   
int vw = 0;

public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.maindemo);  //<- includes the grid called "board"

      registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                TableLayout tl = (TableLayout) findViewById(R.id.board);  
                tl = (TableLayout) findViewById(R.id.board);
                vh = tl.getHeight();       
                vw = tl.getWidth();               
            }
      }, new IntentFilter("Test"));
}

protected void onResume() {
        super.onResume();

        Intent it = new Intent("Test");
        sendBroadcast(it);

}

Вы не можете получить высоту представления в OnCreate(), onStart() или даже в onResume() по той причине, что kcoppock ответил

Ответ 12

Простой ответ: Это работало для меня без проблем. Кажется, ключ состоит в том, чтобы убедиться, что представление имеет фокус, прежде чем вы получитеHeight и т.д. Сделайте это, используя метод hasFocus(), а затем используя метод getHeight() в этом порядке. Требуется всего 3 строки кода.

ImageButton myImageButton1 =(ImageButton)findViewById(R.id.imageButton1); myImageButton1.hasFocus();

int myButtonHeight = myImageButton1.getHeight();

Log.d("Button Height: ", ""+myButtonHeight );//Not required

Надеюсь, что это поможет.

Ответ 14

КОРРЕКЦИЯ: Я узнал, что вышеупомянутое решение ужасно. Особенно, когда ваш телефон работает медленно. И здесь я нашел другое решение: вычислить значение px элемента, включая поля и прокладки: dp to px:   fooobar.com/info/2415/...

или dimens.xml to px:   fooobar.com/info/29379/...

sp для px:   fooobar.com/info/32453/... (отмените решение)

или уменьшается до px:   fooobar.com/info/29379/...

и что он.