뷰의 치수를 검색하는 방법은 무엇입니까?


209

보기로 구성되어 TableLayout, TableRow and TextView있습니다. 그리드처럼 보이기를 원합니다. 이 그리드의 높이와 너비를 가져와야합니다. 방법 getHeight()getWidth()항상 내가이 XML 버전을 사용할 때 동적으로도 그리드를 포맷 할 때 발생 0으로 돌아갑니다.

뷰의 치수를 검색하는 방법은 무엇입니까?


결과를 확인하기 위해 디버그에서 사용한 테스트 프로그램은 다음과 같습니다.

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

getWidth / Height를 사용하는 대신 레이아웃이 활동에 적용된 후 getMeasuredWidth / Height를 사용하십시오.
bhups

9
얘들 아, 모든 사람은 상관이 호출입니다 getHeight()getWidth()활동의 라이프 사이클, 즉, 자신을 측정하기 위해 뷰를 요청했다 후에서 이런 종류의 물건을 onResume()하고 그게 다에요. 아직 배치되지 않은 객체의 크기를 알기를 기 대해서는 안됩니다. 아래 제시된 마법이 필요하지 않습니다.
클래스 스태커

2
전화 getHeight()/Width()onResume()걸면> 0보다 큰 값을 얻지 못했습니다.
Darpan

@ClassStacker 조각은 어떻습니까?
zdd

@zdd 완전히 새로운 질문을하고 의견에 여기에 참조를 게시하십시오.
클래스 스태커

답변:


418

OP가 오랫동안 사라 졌다고 생각하지만이 답변이 향후 검색자를 도울 수있는 경우 내가 찾은 솔루션을 게시 할 것이라고 생각했습니다. 이 코드를 onCreate()메소드에 추가했습니다 .

편집 : 의견의 코드를 포함하도록 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, 오버라이드 (override) onGLobalLayout이 청취자로보기의 측정 값을 알 필요 내 코드를 추가 (... 여기에 호출하는 슈퍼 클래스의 방법이 될 것 같지 않습니다). 모든 것이 예상대로 작동하므로 이것이 도움이되기를 바랍니다.


23
@George 베일리 : 나는 최근에 여러 통화를 극복하기 위해 다른 사람 포스트 (나는 YMMV 그래서, 그것을 자신을 테스트하지 않았습니다) 본 적이 한 일이었다 (onGlobalLayout 내 ()) : tv.getViewTreeObserver().removeGlobalOnLayoutListener(this);리스너가 처음 후에 제거해야한다 그런 식으로 발생합니다.
Kevin Coppock

3
나도 도와주고 싶어 다음과 같은 작업이 필요할 수 있습니다. mView.getViewTreeObserver (). removeGlobalOnLayoutListener (globalLayoutListener); 보기의 크기를 한 번만 조정하려면 도움이
되길

7
질문은 매우 오래되었지만 사용하는 것도 addOnLayoutChangeListener효과적입니다! :)
FX

7
또한 API 16부터는 다음이 필요합니다. if (android.os.Build.VERSION.SDK_INT> = 16) {view.getViewTreeObserver (). removeOnGlobalLayoutListener (this); } else {view.getViewTreeObserver (). removeGlobalOnLayoutListener (this); }
에디슨

2
removeGlobalOnLayoutListener는 더 이상 사용되지 않으므로 Eclipse에서 여전히 경고를 제공합니다. 이것이 정상입니까? 시간이 지남에 따라 더 이상 사용되지 않는 코드 경고가 온통 범람 할 것입니다.
Jonny

82

대안 솔루션을 추가하고 활동의 onWindowFocusChanged 메소드를 재정의하면 getHeight (), getWidth () 값을 얻을 수 있습니다.

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

4
문서를 인용하자면, "이 활동이 사용자에게 표시되는지 여부를 나타내는 가장 좋은 지표입니다."
카메론 로웰 팔머

6
조각을 사용해야하는 경우에는 작동하지 않습니다 ViewTreeObserver.
Mihir 2016 년

OP는 구체적으로 어떻게 볼 수 있는지 물었습니다
JustDanyul

scrollview 총 높이와 최대 Scrollview.getScrolly ()는 동일합니까? 즉 내 경우에는 위의 방법으로 높이가 702이고 getScrolly ()에서 최대 값은 523입니다.
Hitesh Dhamshaniya

이 방법은 다른 xml 파일에서 View가 포함 된 경우에도 작동하지 않습니다.
Jay Donga

19

아직 그려지지 않은 요소의 너비와 높이를 얻으려고합니다.

디버그를 사용하고 어느 시점에서 멈 추면 장치 화면이 여전히 비어 있습니다. 요소가 아직 그려지지 않았기 때문에 아직 너비와 높이를 얻을 수 없기 때문입니다. 있다.

그리고, 내가 틀렸을 수도 있지만 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()배치 할 수 있으며 뷰가 배치 될 때 호출됩니다.


불행히도 OnResume에서도 작동하지 않습니다. 최종 차원은 OnResume 호출 후 적어도 에뮬레이터에서 설정됩니다.
jki

끔찍한 연습입니다 !!! 이 청취자는 계속해서 전화를 걸어 공연을 죽일 것입니다. 플래그를 사용하는 대신 리스너의 등록을 취소하십시오.
bluewhile

15

이와 같이 View의 post 메소드를 사용하십시오.

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

1
그것은 효과가 있지만 실제로는 왜 토론하지 않습니까? Btw, 이것은 레이아웃이 발생할 때까지 runnable이 실행되지 않기 때문에 작동합니다.
노먼 H

7

나는 onGlobalLayout()몇 가지 사용자 정의 형식을 수행하는 데 사용하려고TextView 있지만, @George 베일리 눈치로, onGlobalLayout()실제로 두 번 호출되어 초기 레이아웃 경로에 한 번, 그리고 두 번째 텍스트를 수정 한 후.

View.onSizeChanged()거기에서 텍스트를 수정하면 메소드가 한 번만 호출되기 때문에 (레이아웃 패스 중에) 더 잘 작동합니다. 이를 위해서는 서브 클래 싱이 필요합니다.TextView 했지만 API 레벨 11+ View. addOnLayoutChangeListener()에서는 서브 클래 싱을 피할 수 있습니다.

한 가지 더,에 뷰의 정확한 폭을 얻기 위하여 View.onSizeChanged()layout_width에 설정해야합니다 match_parent,하지 wrap_content.


2

생성자 또는 실제 그림을 얻기 전에 실행되는 다른 방법으로 크기를 얻으려고합니까?

모든 구성 요소가 실제로 측정되기 전에 치수를 얻지 못합니다 (xml이 디스플레이 크기, 부모 위치 등을 알지 못하기 때문에)

onSizeChanged () 후에 값을 가져 오거나 (0으로 호출 할 수 있음) 실제 이미지를 얻을 때까지 기다리십시오.


원래 질문과 코드를 더 명확하게 업데이트했습니다. 감사합니다.

2

FX가 언급했듯이, 당신은 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
    }
});

초기 레이아웃 만 원하는 경우 콜백에서 리스너를 제거 할 수 있습니다.



1

ViewTreeObserver그리고 onWindowFocusChanged()전혀 그렇게 필요하지 않습니다.

당신이 팽창하면 TextView레이아웃 및 / 또는 일부 내용을 넣어 설정 LayoutParams후 사용할 수 있습니다 getMeasuredHeight()getMeasuredWidth().

하지만 당신은해야 조심LinearLayouts (아마도 다른 ViewGroups). 문제는 너비와 높이를 얻을 수 onWindowFocusChanged()있지만 뷰를 추가하려고하면 모든 것이 그려 질 때까지 해당 정보를 얻을 수 없다는 것입니다. 여러 개의 추가려고 TextViewsLinearLayouts모방 A와 FlowLayout(배치 스타일) 등 사용할 수 없습니다 Listeners. 프로세스가 시작되면 동 기적으로 계속 진행해야합니다. 따라서 이러한 경우 레이아웃에 뷰를 추가 할 때 너비를 나중에 사용할 수 있도록 변수에 너비를 유지해야 할 수 있습니다.


1

제안 된 솔루션이 작동하더라도 다음 문서를 기반으로하므로 모든 경우에 가장 적합한 솔루션이 아닐 수 있습니다. ViewTreeObserver.OnGlobalLayoutListener

글로벌 레이아웃 상태 또는 뷰 트리 내에서 뷰의 가시성이 변경 될 때 호출 될 콜백에 대한 인터페이스 정의.

즉, 여러 번 호출되고 항상 뷰가 측정되는 것은 아닙니다 (높이와 너비가 결정됨)

다른 방법은 ViewTreeObserver.OnPreDrawListener뷰를 그릴 준비가되어 있고 모든 측정 값이있는 경우에만 호출되는 사용 방법입니다.

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

    @Override
    public void onPreDraw() {
        tv.getViewTreeObserver().removeOnPreDrawListener(this);
        // Your view will have valid height and width at this point
        tv.getHeight();
        tv.getWidth();
    }

});


0

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);

}

kcoppock이 응답 한 이유로 OnCreate (), onStart () 또는 onResume ()에서 뷰의 높이를 얻을 수 없습니다.


0

height 및 width를 요청하는 시점까지 view가 작성되지 않았으므로 height 및 width는 0입니다. 가장 간단한 해결책은

view.post(new Runnable() {
    @Override
    public void run() {
        view.getHeight(); //height is ready
        view.getWidth(); //width is ready
    }
});

이 방법은 짧고 선명하므로 다른 방법에 비해 좋습니다.


-1

간단한 응답 : 문제없이 작동했습니다. 열쇠는 getHeight 등 전에 View에 포커스가 있는지 확인하는 것 같습니다. hasFocus () 메서드를 사용한 다음 getHeight () 메서드를 순서대로 사용하여이 작업을 수행하십시오. 3 줄의 코드 만 필요합니다.

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

int myButtonHeight = myImageButton1.getHeight();

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

도움이 되길 바랍니다.


-3

보기에 getMeasuredWidth () 및 getMeasuredHeight ()를 사용하십시오.

개발자 안내서 :보기


4
이러한 방법 이전에 언급 한 바와 같이에만 유효한 결과 반환 efter 크기가 meassured되었습니다. Activity 내에서 이것은 onWindowFocusChanged os 메소드가 호출 될 때 적용됩니다.
slott

-8

수정 : 위의 해결책이 끔찍하다는 것을 알았습니다. 특히 휴대 전화가 느릴 때. 그리고 여기에서 또 다른 해결책을 찾았습니다. 여백과 패딩을 포함하여 요소의 px 값을 계산하십시오 .dp ~ px : https : //.com/a/6327095/1982712

또는 dimens.xml에서 px로 : https://stackoverflow.com/a/16276351/1982712

sp to px : https://stackoverflow.com/a/9219417/1982712 (솔루션 반전)

또는 dimens to px : https://stackoverflow.com/a/16276351/1982712

그리고 그게 다야.


10
일반적으로 임의로 선택한 밀리 ​​초 후에 모든 것이 올바르게 설정되기를 희망하는 것은 좋지 않습니다. 장치는 수도 OS의 다음 버전에서하지 작업, ... 천천히, 다른 프로세스 / 스레드, 디버거에서 작동하지 않을 수 있습니다 실행 될 수있을
크리스토퍼 존슨
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.