在上周工作中 使用了listview
在其item中只放了一个textview(有背景) 发现图片被拉高了
1.如下是item的布局文件
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_time"
android:layout_width="120dp"
android:layout_height="40dp"
android:background="@drawable/baby_task_point_blue"
android:gravity="center"
android:minHeight="30dp"
android:text="8:00-8:40"
android:textColor="@color/preference_nextstep_background_normal"
android:textSize="@dimen/text_normal" /></span>
2.后来就想着套一层viewgroup把背景设在viewgroup上行不行 结果还是不行
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="120dp"
android:background="@drawable/baby_task_point_blue"</span>
android:layout_height="40dp" >
<TextView android:id="@+id/tv_time"
android:layout_width="120dp"
android:layout_height="40dp"
android:gravity="center"
android:minHeight="30dp"
android:text="8:00-8:40"
android:textColor="@color/preference_nextstep_background_normal"
android:textSize="@dimen/text_normal" />
</LinearLayout>
3.几经周折 最后试了下背景设在里面
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="120dp"
android:layout_height="40dp" >
<TextView
android:id="@+id/tv_time"
android:layout_width="120dp"
android:layout_height="40dp"
android:background="@drawable/baby_task_point_blue"
android:gravity="center"
android:minHeight="30dp"
android:text="8:00-8:40"
android:textColor="@color/preference_nextstep_background_normal"
android:textSize="@dimen/text_normal" />
</LinearLayout></span>
于是乎就郁闷了 为什么只有套了一层 并且把背景设在里面才行
趁着周末就想找找原因了
思路是这样的 :
既然 linearlayout和textview都有问题 那肯定是他们的共同父类view有问题
先看view的onMeasure方法
<span style="font-size:14px;"> protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}</span>
我们知道setMeasuredDimension方法用来设置测量结果的 所以我们去看getDefaultSize方法
<span style="font-size:14px;">public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}</span>
先讲解下
①UNSPECIFIED:表示默认值,父控件没有给子view任何限制。------二进制表示:00
②EXACTLY:表示父控件给子view一个具体的值,子view要设置成这些值的大小。------二进制表示:01
③AT_MOST:表示父控件个子view一个最大的特定值,而子view不能超过这个值的大小。------二进制表示:10
假设现在图片的高度是140 而我们写的layout_height=30;
那么此时specSize=30,size=140
毫无疑问 对于第1,2种布局我们的程序走到了
<span style="font-size:14px;"> case MeasureSpec.UNSPECIFIED:
result = size;
break;</span>
而第3种布局走到了
case MeasureSpec.EXACTLY:
result = specSize;
break;
那么这是为什么呢?
逐一分析:
第一种布局:
textview作为item中中的唯一控件 它的父布局就是listview给item包裹的一个viewgroup
我们来看看这个viewgroup的设置
关于listview中添加item在如下这个方法中
private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
boolean selected) {
View child;
<span style="font-family:Roboto,sans-serif;">.......</span>
// Make a new view for this position, or convert an unused view if
// possible
//调用getView
child = obtainView(position, mIsScrap);
// This needs to be positioned and measured
setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);
return child;
}
如上listview通过obtainView得到复用的view或者调用getview产生新的view
然后在setupChild方法中把item添加到对应的viewgroup中
private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft,
boolean selected, boolean recycled) {
....
// <span style="font-family:Roboto,sans-serif;">那个viewgroup的</span><span style="font-family:Roboto,sans-serif; color:#222222"></span>LayoutParams <span style="font-family:Roboto,sans-serif; color:#222222"></span>
AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();
if (p == null) {
p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 0);
}
<span style="font-family:Roboto,sans-serif;"> .......</span>
}
看到了吧 这个viewgroup的高度WRAP_CONTENT
所以走到了
case MeasureSpec.UNSPECIFIED:
result = size;
break;
第二种布局:
同第一种布局 因为此时背景设在linearlayout上 所以当它测量高度时 也走到了
case MeasureSpec.UNSPECIFIED:
result = size;
break;
第三种布局:
此时背景设在textview中
那么当linearlayout测量高度时 走到了
case MeasureSpec.EXACTLY:
result = specSize;
break;
所以再到textview测量高度时 就一切正常了