测量View(三):获得测量宽高及真实宽高
测量View(一):创建View并测量 http://www.jianshu.com/p/4fb206b947ee
测量View(二):测量宽高及真实宽高 http://www.jianshu.com/p/18540e62ae3a
现在我们可以解决在 测量View(一):创建View并测量 中的问题了
调用View的measure 及 layout方法便可获得测量宽高及真实宽高
方法1:View.post()
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
//将View加到根视图中
mRoot.addView(view);
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
Paste_Image.png
结果怎么还是0.
查看addView()代码:
public void addView(View child, int index, LayoutParams params) {
...
requestLayout();
...
}
之前学习自定义View时,认为父布局requestLayout后会重新遍历子布局的measure及layout方法
既然调用了measure, layout方法,为何获取不到测量的宽高,真实的宽高。
以下这篇分析了requestLayout方法
http://www.jianshu.com/p/effe9b4333de
简单说就是调用requestLayout后,遍历子布局的操作是在分线程进行的。
知道了原因,上代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
mRoot.addView(view);
view.post(new Runnable() {
@Override
public void run() {
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
});
}
Paste_Image.png
问题解决
方法2:onWindowFocusChanged()
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
mRoot.addView(view);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
onWindowFocusChanged()方法在View的onSizeChanged()后调用。此时View的宽高都已确认
此时获得宽高肯定没问题。
方法3:onClick()中获得宽高
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
mRoot.addView(view);
mRoot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
});
}
Paste_Image.png
没毛病,以上三种方法都是打时间差
方法4 网上有一种方法:手动measure()
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
mRoot.addView(view);
view.measure(0, 0);
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
这里的mesure(0, 0)相当于:
int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);//0
int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);//0
view.measure(widthSpec, heightSpec);
但是sorry,结果还是0
Paste_Image.png查看原代码:调用了View的onMeasure()方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
getSuggestedMinimumWidth()
protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
getSuggestedMinimumHeight()
protected int getSuggestedMinimumHeight() {
return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());
}
以上发现View的宽高与mMinWidth 及 背景的宽高有关系
修改代码:
设置最小宽高
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
view.setMinimumWidth(100);
view.setMinimumHeight(200);
mRoot.addView(view);
view.measure(0, 0);
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
Paste_Image.png
设置背景图片
(1)png图片
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
//drawable-mdpi中的png图片48 * 48
view.setBackgroundResource(R.drawable.ic_launcher);
mRoot.addView(view); //加不加都行
Drawable background = view.getBackground();
int intrinsicWidth = background.getIntrinsicWidth();
int intrinsicHeight = background.getIntrinsicHeight();
view.measure(0, 0);
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
Paste_Image.png
(2)xml自定义Drawable
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
// drawable-mdpi中自定义的GradientDrawable
// <?xml version="1.0" encoding="utf-8"?>
// <shape xmlns:android="http://schemas.android.com/apk/res/android">
// <solid android:color="@color/colorPrimary" />
// <size
// android:width="100dp"
// android:height="100dp" />
// </shape>
view.setBackgroundResource(R.drawable.bitmap);
mRoot.addView(view); //加不加都行
Drawable background = view.getBackground();
int intrinsicWidth = background.getIntrinsicWidth();
int intrinsicHeight = background.getIntrinsicHeight();
view.measure(0, 0);
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
Paste_Image.png
(3)代码定义ShapeDrawable
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoot = (LinearLayout) findViewById(R.id.root);
view = new View(this);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
view.setLayoutParams(layoutParams);
ShapeDrawable drawable = new ShapeDrawable();
drawable.setIntrinsicHeight(100);
drawable.setIntrinsicWidth(100);
view.setBackgroundDrawable(drawable);
mRoot.addView(view);//加不加都可以
Drawable background = view.getBackground();
int intrinsicWidth = background.getIntrinsicWidth();
int intrinsicHeight = background.getIntrinsicHeight();
view.measure(0, 0);
int width = view.getWidth();
int height = view.getHeight();
int measuredWidthAndState = view.getMeasuredWidthAndState();
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
int measuredHeightAndState = view.getMeasuredHeightAndState();
}
Paste_Image.png
测试手机当前的density为3.0 densityDpi为480
手动测量得到测量的宽高,而真实的宽高都是0,没毛病
注意:所有的View在measure()时都与最小宽高及背景有关吗?答案是否.要看具体的View中onMeasure()方法的定义
以上measure方法可以将View加到主布局中,也可以不加,都可以获得测量宽高