您的位置:首页 > 移动开发 > Android开发

Android View的小结

2015-08-19 15:12 423 查看

View生命周期如下:


构造器开始->
onAttachedToWindow()->onMeasure(int,
int)->onSizeChanged(int, int, int, int)->onLayout(boolean, int, int,
int, int)->onDraw(android.graphics.Canvas)->onDetachedFromWindow()

View 的绘画流程如下:由三个函数完成:measure()、layout()、draw(),其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法。

onmensure():

Measure the view and its content to determine the measured width and the measured height. This method is invoked by
measure(int, int)

and should be overriden by subclasses to provide accurate and efficient measurement of their contents.
用于测量view,用于决定测量的with与测量的height。这个方法由measure()调用,而且这个方法由继承view的子类复写,以便于提供有效而且精确的测量值。
所以自定义view的时候应该要复写onmeasure()的方法,测量view的宽与高,然后通过setMeasuredDimension(measuredWidth, measuredHeight);的方法给出一个用于测量的精确有效的值。这样用于测量精确有效的值应该就是你的view 中getWidth() getHeight()返回的测量值。为什么要这样子做,比如说在我们xml写布局的时候,我们喜欢用mach_parent
与wrap_parent来限制宽与高,mach_parent:与父试图一样大小尺度,wrap_parent:给与足够显示大小的尺寸,还有就是给与一个精确的尺寸。

举个例子:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int withsize=MeasureSpec.getSize(widthMeasureSpec);
int heighsize=MeasureSpec.getSize(heightMeasureSpec);
Log.i("-------------", withsize+"/"+heighsize);
}
并且打印

Log.i("getwith",
getWidth()+"");

Log.i("getheigh", getHeight()+"");

xml里代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:circle="http://schemas.android.com/apk/res/com.example.cirleprogress"
android:layout_width="200dp"
android:layout_height="200dp"
>
<com.example.cirleprogress.CircleProgressView
android:layout_width="50dp"
android:layout_height="50dp"
circle:backgroundcolor="#00bcd4"

/>
</RelativeLayout>


打印结果如下:

___________
50/200
___________
50/50

___________
50/200

___________
50/50

发现打印了四次,这个待会再说,最后打印出来的结果是50/50,与我们布局里面设置的大小是一样的,这么说来,获取的数据是view的宽与高,而getheigh与getwith
打印出来都是50

我们设置xml:

<com.example.cirleprogress.CircleProgressView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
circle:backgroundcolor="#00bcd4"
/>
发现打印出来的是200/200,同理如果设置的是match_parent打印出来的也是200/200,打印getheigh与getwith 都是200.

然后我们调用方法setMeasuredDimension设置都是20

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int withsize=MeasureSpec.getSize(widthMeasureSpec);
int heighsize=MeasureSpec.getSize(heightMeasureSpec);
Log.i("-------------", withsize+"/"+heighsize);
setMeasuredDimension(20, 20);}


我们会发现

withsize+"/"+heighsize 都是200,可是getheigh与getwith 都是20

所以大概就可以知道了,我们不确定布局里面设置为确定尺度,match_parent,或者wrap_content,onmensure()的方法返回的测量值可能是不明确的,我们需要在onmenaure()方法里面使用setMeasuredDimension(int measuredWidth, int measuredHeight)来限定一个有效测量值。也可以通过此来限定view的大小范围,避免显示效果出现超出屏幕什么的,值得留意的是,自定义view的适合,如果view宽/高设置为wrap_content时其实会占满viewgroup,大概是因为其本身没有默认的大小,直接就默认占满viewgroup了,可以在onmeasure里设置当为wrap_conten时设置其默认的大小。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int withsize = MeasureSpec.getSize(widthMeasureSpec);
int heighsize = MeasureSpec.getSize(heightMeasureSpec);
int withmode = MeasureSpec.getMode(widthMeasureSpec);
int heightmode = MeasureSpec.getMode(heightMeasureSpec);

if (withmode == MeasureSpec.AT_MOST) {
withsize = 200;
}

if (heightmode == MeasureSpec.AT_MOST) {
heighsize = 200;
}
setMeasuredDimension(withsize, heighsize);<strong>
}





<strong><span style="font-size:18px;">这里注意这个measursSpec.
A MeasureSpec encapsulates the layout requirements passed from parent to child
意思就是这个东西囊括了一个layout的所有东西,通过parent传递给child。所有东西是指模式,与尺寸。模式就是指是wrap_conten,还是match_conten,还是精确值,尺寸就是宽与高的具体数据。
总共有三个模式:
AT_MOST   chile有多大就有多大,但不超父布局尺寸,是指 wrap_conten
Measure specification mode: The child can be as large as it wants up to the specified size.
EXACTLY  精确尺寸模式,精确尺寸或者match_parent
Measure specification mode: The parent has determined an exact size for the child.
UNSPECIFIED  没有指定尺寸
Measure specification mode: The parent has not imposed any constraint on the child.</span>
</strong>
<span style="font-size:18px;"><strong>最后测试发现得到:如果Vie设置的宽/高 是wrap_conten 或者是match_parent onmeasure(),返回的宽/高一定是Viewgroup的宽/高,如果viewgroup的宽/高 是wrap_conten 或者是match_parent,那么返回的是上一级Viewgroup 的宽/高,以此类推。如果Vie设置的宽/高 是小于viewgroup的宽/高,那么返回的是view设置的宽/高,如果大于parent viewgroup的宽/高 那么返回的是Viewgroup 的宽/高,以此类推最后到达的一级是屏幕的宽/高。
用于控制view 的children的位置与大小</strong></span>
Called from layout when this view should assign a size and position to each of its children
protected void onLayout(boolean changed,
int left,
int top,
int right,
int bottom)
changed - This is a new size or position for this view
left - Left position, relative to parent
top - Top position, relative to parent
right - Right position, relative to parent
bottom - Bottom position, relative to parent


接下来说一下为什么onmeasure()会调用多次,答案就是下面这句话:

A parent view may call measure() more than once on its children. For example, the parent may measure each child once with unspecified dimensions to find out how big they
want to be, then call measure() on them again with actual numbers if the sum of all the children's unconstrained sizes is too big or too small.

parent可能不止一次调用measure()来测量children,可能先用一个粗略的尺寸测量children来估算children有大多,然后再调用measure()用精确的尺寸进行测量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: