1 public class RefreshListView extends ListView implements OnScrollListener {
2
3 private View mHeaderView;//头布局
4 private View mFooterView;//脚布局
5 private ImageView mArrowView;//刷新箭头
6 private ProgressBar mProgressBar;//进度条
7 private TextView mTitle;//显示的刷新状态标题
8 private TextView mLastRefreshTime;//上一次刷新的时间
9 private RotateAnimation mRotateUpAnim;//向上旋转的动画
10 private RotateAnimation mRotateDownAnim;//向下旋转的动画
11 private float startY;//按下的起始y坐标
12 private int mFirstVisiblePos;//记录第一个可见的item位置
13 private int mHeaderViewHeight;//头布局测量所得的高度
14 private int mFooterViewHeight;//脚布局测量所得的高度
15 private static final int PULL_TO_REFRESH = 0;//下拉刷新
16 private static final int RELEASE_TO_REFRESH = 1;//释放刷新
17 private static final int RELEASING = 2;//正在刷新
18 private int mCurrentState = PULL_TO_REFRESH;//记录当前的刷新状态
19 private boolean isLoadingMore;//记录上拉加载的状态
20 private OnRefreshListener mOnRefreshListener;//下拉刷新接口
21 private OnLoadMoreListener mOnLoadMoreListener;//上拉加载接口
22
23 public RefreshListView(Context context) {
24 super(context);
25 init();
26
27 }
28
29 public RefreshListView(Context context, AttributeSet attrs) {
30 super(context, attrs);
31 init();
32 }
33
34 public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
35 super(context, attrs, defStyleAttr);
36 init();
37 }
38
39 private void initHeaderView() {
40 //初始化相关布局控件
41 mHeaderView = View.inflate(getContext(), R.layout.layout_header_list, null);
42 mArrowView = (ImageView) mHeaderView.findViewById(R.id.iv_arrow);
43 mProgressBar = (ProgressBar) mHeaderView.findViewById(R.id.pb);
44 mTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
45 mLastRefreshTime = (TextView) mHeaderView.findViewById(R.id.tv_desc_last_refresh);
46 mLastRefreshTime.setText(getLastRefreshTime());
47 //提前手动测量,获取mHeaderView的实际高度
48 mHeaderView.measure(0, 0); 49 //获取测量的高度
50 mHeaderViewHeight = mHeaderView.getMeasuredHeight();
51 //通过设置padding隐藏头布局
52 mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
53 //将头布局增加到ListView中,注意这里必须在setAdapter之前
54 this.addHeaderView(mHeaderView);
55 }
56
57 /**
58 * 初始化操作
59 */
60 private void init() {
61 initHeaderView();
62 initFooterView();
63 initAnimation();
64 //设置滑动监听
65 this.setOnScrollListener(this);
66 }
67
68 private void initFooterView() {
69 //原理和上面添加头布局一样,不做解释了
70 mFooterView = View.inflate(getContext(), R.layout.layout_footer_list, null);
71 mFooterView.measure(0, 0);
72 mFooterViewHeight = mFooterView.getMeasuredHeight();
73 mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
74 this.addFooterView(mFooterView);
75 }
76
77 /**
78 * 初始化下拉刷新的时候,左边箭头的执行动画
79 */
80 private void initAnimation() {
81 // 向上旋转,围绕自己的中心逆时针旋转180度
82 mRotateUpAnim = new RotateAnimation(0f, -180f, Animation.RELATIVE_TO_SELF, 0.5f,
83 Animation.RELATIVE_TO_SELF, 0.5f);
84 mRotateUpAnim.setDuration(3000);//设置动画持续的时间
85 mRotateUpAnim.setFillAfter(true);//设置动画结束停留在结束的位置
86 // 向下旋转,围绕自己的中心逆时针旋转180度
87 mRotateDownAnim = new RotateAnimation(-180f, -360f, Animation.RELATIVE_TO_SELF,
88 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
89 mRotateDownAnim.setDuration(3000);
90 mRotateDownAnim.setFillAfter(true);
91
92 }
93
94 /**
95 * 重写ListView的onTouchEvent方法,处理我们的滑动事件
96 */
97 @Override
98 public boolean onTouchEvent(MotionEvent ev) {
99 switch (ev.getAction()) {
100 case MotionEvent.ACTION_DOWN:
101 //记录下x坐标
102 startY = ev.getY();
103 break;
104 case MotionEvent.ACTION_MOVE:
105 //记录下滑动时的y坐标
106 float endY = ev.getY();
107 //如果当前已经是正在刷新的状态或者正在加载更多的状态,不做处理
108 if (mCurrentState == RELEASING || isLoadingMore) {
109 return super.onTouchEvent(ev);//执行父类的逻辑,我们这边不进行处理
110 }
111 //滑动的距离
112 float dy = endY - startY;
113 //第一个可见item的position是0.且滑动距离大于0,慢慢显示头布局
114 if (dy > 0 && mFirstVisiblePos == 0) {
115 //更新头布局的padding。 topPadding=(-自身高度+滑动的距离)
116 int paddingTop = (int) (dy - mHeaderViewHeight);
117 mHeaderView.setPadding(0, paddingTop, 0, 0);
118 //头布局已经完全显示,并且当前的状态不是释放刷新,切换
119 if (paddingTop > 0 && mCurrentState != RELEASE_TO_REFRESH) {
120 mCurrentState = RELEASE_TO_REFRESH;
121 updateHeaderView();
122 } else if (paddingTop < 0 && mCurrentState != PULL_TO_REFRESH) {
123 //头布局没有完全显示,并且现在不是下拉刷新的状态
124 mCurrentState = PULL_TO_REFRESH;
125 updateHeaderView();
126
127
128 }
129 return true;//事件已经被我们消费处理
130 }
131
132 break;
133 case MotionEvent.ACTION_UP:
134 //抬起,根据当前的状态
135 if (mCurrentState == PULL_TO_REFRESH) {
136 //头布局没有完全显示,则恢复原样
137 mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
138 } else if (mCurrentState == RELEASE_TO_REFRESH) {
139 //释放刷新,头布局完全显示了
140 mHeaderView.setPadding(0, 0, 0, 0);
141 mCurrentState = RELEASING;//正在刷新中
142 updateHeaderView();
143 }
144 break;
145 default:
146 break;
147 }
148 return super.onTouchEvent(ev);
149 }
150
151 /**
152 * 更新头布局.根据状态值来切换
153 */
154 private void updateHeaderView() {
155 switch (mCurrentState) {
156 case PULL_TO_REFRESH://切换成下拉刷新
157 mTitle.setText("下拉刷新");
158 mArrowView.startAnimation(mRotateDownAnim);
159 break;
160 case RELEASE_TO_REFRESH://切换成释放刷新
161 mTitle.setText("释放刷新");
162 mArrowView.startAnimation(mRotateUpAnim);
163 break;
164 case RELEASING://切换成正在刷新
165 mArrowView.clearAnimation();//这里要清除动画
166 mArrowView.setVisibility(INVISIBLE);
167 mProgressBar.setVisibility(VISIBLE);
168 mTitle.setText("正在刷新中");
169 //回调刷新接口方法进行刷新
170 if (mOnRefreshListener != null) {
171 mOnRefreshListener.onRefresh();
172 }
173 break;
174 default:
175 break;
176 }
177 }
178
179 /**
180 * 刷新完成
181 */
182 public void onRefreshComplete() {
183 //还原最初的状态
184 mCurrentState = PULL_TO_REFRESH;
185 mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
186 mArrowView.setVisibility(VISIBLE);
187 mProgressBar.setVisibility(INVISIBLE);
188 String lastRefreshTime = getLastRefreshTime();
189 mLastRefreshTime.setText(lastRefreshTime);
190 }
191
192 /**
193 * 上拉加载完成
194 */
195 public void onLoadMoreComplete() {
196 //还原最初的状态
197 isLoadingMore = false;
198 mFooterView.setPadding(0, 0, 0, 0);
199 }
200
201 /**
202 * 获取上一次刷新的时间
203 */
204 private String getLastRefreshTime() {
205 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
206 return format.format(new Date());
207 }
208
209
210 /**
211 * 对外暴露设置刷新接口的方法
212 */
213 public void setOnRefreshListener(OnRefreshListener mOnRefreshListener) {
214 this.mOnRefreshListener = mOnRefreshListener;
215 }
216
217 public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
218 this.mOnLoadMoreListener = mOnLoadMoreListener;
219 }
220
221 /**
222 * 滑动状态改变
223 */
224 @Override
225 public void onScrollStateChanged(AbsListView view, int scrollState) {
226 if (isLoadingMore || mCurrentState == RELEASING) {
227 //正在加载更多,或者刷新状态。不做处理
228 return;
229 }
230 if (scrollState == SCROLL_STATE_IDLE && getLastVisiblePosition() == getCount() - 1) {
231 //空闲状态且到了最后一个item,执行上拉加载
232 isLoadingMore = true;
233 mFooterView.setPadding(0, 0, 0, 0);235 setSelection(getCount() - 1);//跳转到最后一条使其显示加载更多
236 if (mOnLoadMoreListener != null) {
237 mOnLoadMoreListener.onLoadMore();
238 }
239 }
240
241 }
242
243 /**
244 * 滑动过程
245 */
246 @Override
247 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
248 int totalItemCount) {
249 //记录第一个可见item的position
250 mFirstVisiblePos = firstVisibleItem;252
253 }
254
255 /**
256 * 刷新接口
257 */
258 public interface OnRefreshListener {
259
260 void onRefresh();
261 }
262
263 /**
264 * 加载更多接口
265 */
266 public interface OnLoadMoreListener {
267
268 void onLoadMore();
269 }
270 }