Android 获取 View 宽高的方法总结

Android 开发过程中或多或少都有获取View宽高的需求,如动画操作等。
为了避免获取到的View高宽为0,那我们应该选择什么方法才能正确的获取View宽高呢?


addOnGlobalLayoutListener

  • 监听 View 的全局变化事件。比如,layout 变化,draw 事件等
  • 需要及时移除该事件的监听,优化性能,注意 API 的版本兼容处理
1
2
3
4
5
6
7
8
9
10
11
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}else {
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
int width = view.getWidth();
}
});

addOnPreDrawListener

  • 利用 ViewTreeObserver 观察者类,监听 draw 事件
1
2
3
4
5
6
7
8
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
int width = view.getWidth();
return false;
}
});

view.post()

  • 当 view layout 处理完成时,自动发送消息
    1
    2
    3
    4
    5
    6
    view.post(new Runnable() {
    @Override
    public void run() {
    int width = view.getWidth();
    }
    });

onLayout()

  • 利用 View 绘制过程中的 onLayout() 方法获取宽高值(View 重写onLayout方法)
1
2
3
4
5
6
7
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);
int = view.getWidth();
}
};

addOnLayoutChangeListener

  • 监听 View 的 onLayout() 绘制过程,一旦 layout 触发变化,立即回调 onLayoutChange 方法
1
2
3
4
5
6
7
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) {
view.removeOnLayoutChangeListener(this);
int width = view.getWidth();
}
});

ViewCompat.isLaidOut(view)

  • 严格意义上讲,这不能作为获取宽高的方式之一。充其量只是一个判断条件。
  • 只有当 View 至少经历过一次 layout 时,isLaidOut() 方法才能返回 true
1
2
3
if (ViewCompat.isLaidOut(view)) {
int width = view.getWidth();
}

getMeasuredWidth

  • 原理是直接调用一个view或者viewgroup的measure方法去测量
  • 适用于需要在onCreate完成之前就获得一个view的宽和高的情况。
  • 这样做的好处是可以立即获得宽和高,坏处是多了一次测量过程。
1
2
3
4
5
6
7
8
9
10
//宽
public int getViewWidth(LinearLayout view){
view.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
return view.getMeasuredWidth();
}
//高
public int getViewHeight(LinearLayout view){
view.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
return view.getMeasuredHeight();
}

view.getLayoutParams().height/width

  • 仅限XML文件里设置了具体宽高,或代码中设置了 view.getLayoutParams().height/width 值可用
1
2
3
4
5
6
7
8
//宽
public int getViewWidth(LinearLayout view){
return view.getLayoutParams().width;
}
//高
public int getViewHeight(LinearLayout view){
return view.getLayoutParams().height;
}

onWindowFocusChanged

  • onWindowFocusChanged方法会在当前Activity得到或者失去焦点的时候进行回调,也就是说当Activity布局绘制结束或者Activity暂停的时候都会调用onWindowFocusChanged
  • 坏处就是调用的次数比较频繁( 这需要自己优化哈~ )
1
2
3
4
5
6
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
int width = view.getWidth();
int height = view.getHeight();
}