刚做android的候在制定控件宽高时都习惯用wrap_content,match_parent属性或是直接写一个固定的值,但是在很多情况下,这种做法无法实现屏幕的适配问题。比如一个布局,上面是一个titleBar,下面是一个bottomTab,中间是一个ListView,若用上述的做法,或许在一种分辨率下可以把控件契合的很完美,但是可能换了个分辨率之后,中间的ListView就突然变“短”了或者最下面一部分被bottomTab遮盖了。诚然用weight属性可以解决类似的问题,但是在很多情况下我们还是需要在代码中动态的设置ListView的高度。
下面就给出一个简单的例子:
xml布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<TextView
android:id="@+id/topBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#00ff00"
android:gravity="center"
android:text="TitleBar"
android:textSize="20sp" />
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/topBar" >
</ListView>
<TextView
android:id="@+id/bottomTab"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="#ff0000"
android:gravity="center"
android:text="BottomTab"
android:textSize="20sp" />
</RelativeLayout>
java代码:
public class MainActivity extends Activity {
private ListView list;
private List<String> data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏
setContentView(R.layout.activity_main);
initView();
getData();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,data);
list.setAdapter(adapter);
}
private void getData() {
data = new ArrayList<String>();
for (int i = 0; i < 50; i++) {
String item = "第" + i + "行";
data.add(item);
}
}
private void initView() {
list = (ListView) findViewById(R.id.list);
}
}
非常基础的一个小例子,效果如下图:
已经拉到最底部,可是总共50行数据却只能显示49行!也就是说有1行被bottomTab遮盖了,解决的思路就是将listView的高度设置成屏幕高度-标题栏状态栏高度-topTitle高度-bottomTab高度,有些人可能会使用weight属性来解决问题,但到底是几比几比几只能一点一点去测试,个人不推荐这种做法。
首先是测量屏幕高度,这个很简单,网上有很多相关代码:
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
totalHeight = metric.heightPixels;
状态栏和标题栏(应用默认)高度:
View v = getWindow().findViewById(Window.ID_ANDROID_CONTENT);///获得根视图
int topHeight = v.getTop();///状态栏标题栏的总高度
其次是测量底部高度,因为底部高度已经给了一个固定值50dp,所以我们也可以非常方便的获取到:
bottomHeight = bottomTab.getLayoutParams().height;
重点是顶部布局,顶部使用的是wrap_content,我们无法直接使用top.getHeight()或者top.getMeasuredHeight()去获取顶部高度,所以在此引出measure()方法:
titleBar.measure(0, 0);
titleHeight = titleBar.getMeasuredHeight();
最后我们设置listview的高度:
list.getLayoutParams().height = totalHeight-topHeight -titleHeight-bottomHeight;
总结一下,代码如下:
private View bottomTab,titleBar;
private int totalHeight, titleHeight, bottomHeight;// 屏幕高度,titleBar高度,bottomTab高度
private void setListViewHeight() {
// 测量屏幕高度
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
totalHeight = metric.heightPixels;
Log.i("info", "totalHeight>"+totalHeight);
//标题栏和状态栏高度
View v = getWindow().findViewById(Window.ID_ANDROID_CONTENT);///获得根视图
int topHeight = v.getTop();///状态栏标题栏的总高度
Log.i("info", "topHeight>"+topHeight);</span>
//底部高度
bottomHeight = bottomTab.getLayoutParams().height;
Log.i("info", "bottomHeight>"+bottomHeight);
//顶部高度
Log.i("info", "bottomHeightWithoutMeasure>"+titleBar.getMeasuredHeight());
titleBar.measure(0, 0);
titleHeight = titleBar.getMeasuredHeight();
Log.i("info", "bottomHeightWithMeasure>"+titleHeight);
//设置listview高度
list.getLayoutParams().height = totalHeight-topHeight-titleHeight-bottomHeight;
Log.i("info", "listHeight>"+list.getLayoutParams().height );
}
效果图:
ok,最后一行成功显示出来!
我们来看看Log输出:
问题解决。