一、问题分析
在上一篇中,我们将头布局加到了ListView上。但是没有隐藏他。你可能会想,隐藏还不简单,直接给它设置为GONE属性不就可以了吗,在需要的时候再设定为可见。没错,这正是ListView实现分页加载时候的做法。但是实现分页加载时,只需要上拉一下,并没有和用户过多的互动。而实现下拉刷新时,一般的做法是,用户在下拉的时候,头布局会慢慢显示,以至于有一种被拉出来的感觉。而分页加载的做法确是只要发现用户下拉,就一下子全部显示出来了。所以这种做法显然不是我们想要的效果。
那么,我们根据我们想要的效果,就不难想到,我们需要一个方法,一个可以随着用户往下拉的幅度,而让头布局也慢慢跟随显示出来的方法。在这里,采用的方法就是隐藏头布局高度的方法,即即时设置它的paddingTop。这样,刚开始直接设定paddiingTop为高度的负值,就是全部隐藏的效果,然后随着用户下拉,不断传入用户下拉的幅度作为改变paddingTop的依据,这样子头布局就会慢慢被拉出来了。
思路有了,那么问题来了。第一,要获取头布局自身的高度。第二,要编写这个方法。代码里解释的很清晰了。我们直接看下面的代码吧。对于初学者,这是很大的技巧,应该认真学习。
二、实现头布局隐藏
废话不多说,需要注意的东西在代码注释里写的很清楚了。再次编写MyListView类,如下:
1 package com.fuly.load; 2 3 import android.content.Context; 4 import android.util.AttributeSet; 5 import android.view.LayoutInflater; 6 import android.view.View; 7 import android.view.ViewGroup; 8 import android.widget.ListView; 9 10 public class MyListView extends ListView{ 11 12 private View header;//头布局 13 14 private int headerHeight;//头布局自身的高度 15 16 //三个构造方法都要重写 17 public MyListView(Context context) { 18 super(context); 19 initView( context); 20 21 } 22 public MyListView(Context context, AttributeSet attrs) { 23 super(context, attrs); 24 initView( context); 25 26 } 27 public MyListView(Context context, AttributeSet attrs, int defStyle) { 28 super(context, attrs, defStyle); 29 initView( context); 30 31 } 32 33 public void initView(Context context){ 34 35 header = LayoutInflater.from(context).inflate(R.layout.header, null); 36 //这里需要注意,在获取高度时必须首先通知父布局header要占多大高和宽。 37 //因为此时父布局还不知道header的尺寸呢,否则你获取的高度只能为0. 38 notifyView(header); 39 headerHeight = header.getMeasuredHeight();//获取header的高度 40 41 //不能使用header.getHeight。我也不明白为什么不能使用这个方法。 42 //希望有人帮忙解答 43 // headerHeight = header.getHeight(); 44 paddingTop(-headerHeight); 45 //将头布局加进去 46 this.addHeaderView(header); 47 } 48 49 50 51 52 /** 53 * 该方法为通知父布局,子布局view的宽度和高度 54 * @param view:子布局 55 */ 56 private void notifyView(View view){ 57 58 ViewGroup.LayoutParams p = view.getLayoutParams(); 59 60 if(p == null){ 61 p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 62 63 } 64 65 //spec表示当前子view左右边距,padding表示子view的左右内边距 66 //childDimension:子view的宽度 67 int width = ViewGroup.getChildMeasureSpec(0, 0, p.width); 68 69 int height; 70 int tempHeight = p.height; 71 if(tempHeight>0){ 72 //子布局高度不为空,需要填充这个布局 73 height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY); 74 }else{ 75 //高度为0,则不需要填充 76 height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 77 } 78 79 //然后告诉父布局,子布局的高度和宽度 80 view.measure(width, height); 81 } 82 83 84 //该方法设定header的paddingTop 85 private void paddingTop(int pt){ 86 header.setPadding(header.getPaddingLeft(), pt, header.getPaddingRight(), header.getPaddingBottom()); 87 header.invalidate(); 88 } 89 90 91 92 93 }
我再强调一遍吧。在获得header自身高度的时候,由于渲染header为view的时候并没有通知父布局它有多大。因此在获取之前,需要通知父布局它要占的宽和高。否则取到的高度永远是0.
好了,运行程序,发现头布局被隐藏了。一个难啃的难题解决了。下一篇文章中,我们就开始实现下拉刷新吧。