Android中ListView下拉刷新的实现

ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考。那我就不解释,直接上代码了。

这里需要自己重写一下ListView,重写代码如下:

  1 package net.loonggg.listview;

  2 

  3 import java.util.Date;

  4 

  5 import android.content.Context;

  6 import android.util.AttributeSet;

  7 import android.view.LayoutInflater;

  8 import android.view.MotionEvent;

  9 import android.view.View;

 10 import android.view.ViewGroup;

 11 import android.view.animation.LinearInterpolator;

 12 import android.view.animation.RotateAnimation;

 13 import android.widget.AbsListView;

 14 import android.widget.ImageView;

 15 import android.widget.LinearLayout;

 16 import android.widget.ListView;

 17 import android.widget.ProgressBar;

 18 import android.widget.TextView;

 19 import android.widget.AbsListView.OnScrollListener;

 20 

 21 public class MyListView extends ListView implements OnScrollListener {

 22 

 23     private final static int RELEASE_To_REFRESH = 0;// 下拉过程的状态值

 24     private final static int PULL_To_REFRESH = 1; // 从下拉返回到不刷新的状态值

 25     private final static int REFRESHING = 2;// 正在刷新的状态值

 26     private final static int DONE = 3;

 27     private final static int LOADING = 4;

 28 

 29     // 实际的padding的距离与界面上偏移距离的比例

 30     private final static int RATIO = 3;

 31     private LayoutInflater inflater;

 32 

 33     // ListView头部下拉刷新的布局

 34     private LinearLayout headerView;

 35     private TextView lvHeaderTipsTv;

 36     private TextView lvHeaderLastUpdatedTv;

 37     private ImageView lvHeaderArrowIv;

 38     private ProgressBar lvHeaderProgressBar;

 39 

 40     // 定义头部下拉刷新的布局的高度

 41     private int headerContentHeight;

 42 

 43     private RotateAnimation animation;

 44     private RotateAnimation reverseAnimation;

 45 

 46     private int startY;

 47     private int state;

 48     private boolean isBack;

 49 

 50     // 用于保证startY的值在一个完整的touch事件中只被记录一次

 51     private boolean isRecored;

 52 

 53     private OnRefreshListener refreshListener;

 54 

 55     private boolean isRefreshable;

 56 

 57     public MyListView(Context context) {

 58         super(context);

 59         init(context);

 60     }

 61 

 62     public MyListView(Context context, AttributeSet attrs) {

 63         super(context, attrs);

 64         init(context);

 65     }

 66 

 67     private void init(Context context) {

 68         setCacheColorHint(context.getResources().getColor(R.color.transparent));

 69         inflater = LayoutInflater.from(context);

 70         headerView = (LinearLayout) inflater.inflate(R.layout.lv_header, null);

 71         lvHeaderTipsTv = (TextView) headerView

 72                 .findViewById(R.id.lvHeaderTipsTv);

 73         lvHeaderLastUpdatedTv = (TextView) headerView

 74                 .findViewById(R.id.lvHeaderLastUpdatedTv);

 75 

 76         lvHeaderArrowIv = (ImageView) headerView

 77                 .findViewById(R.id.lvHeaderArrowIv);

 78         // 设置下拉刷新图标的最小高度和宽度

 79         lvHeaderArrowIv.setMinimumWidth(70);

 80         lvHeaderArrowIv.setMinimumHeight(50);

 81 

 82         lvHeaderProgressBar = (ProgressBar) headerView

 83                 .findViewById(R.id.lvHeaderProgressBar);

 84         measureView(headerView);

 85         headerContentHeight = headerView.getMeasuredHeight();

 86         // 设置内边距,正好距离顶部为一个负的整个布局的高度,正好把头部隐藏

 87         headerView.setPadding(0, -1 * headerContentHeight, 0, 0);

 88         // 重绘一下

 89         headerView.invalidate();

 90         // 将下拉刷新的布局加入ListView的顶部

 91         addHeaderView(headerView, null, false);

 92         setOnScrollListener(this);

 93         // 设置旋转动画事件

 94         animation = new RotateAnimation(0, -180,

 95                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,

 96                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);

 97         animation.setInterpolator(new LinearInterpolator());

 98         animation.setDuration(250);

 99         animation.setFillAfter(true);

100 

101         reverseAnimation = new RotateAnimation(-180, 0,

102                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,

103                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);

104         reverseAnimation.setInterpolator(new LinearInterpolator());

105         reverseAnimation.setDuration(200);

106         reverseAnimation.setFillAfter(true);

107 

108         // 一开始的状态就是下拉刷新完的状态,所以为DONE

109         state = DONE;

110         // 是否正在刷新

111         isRefreshable = false;

112     }

113 

114     @Override

115     public boolean onTouchEvent(MotionEvent ev) {

116         if (isRefreshable) {

117             switch (ev.getAction()) {

118             case MotionEvent.ACTION_DOWN:

119                 if (!isRecored) {

120                     isRecored = true;

121                     startY = (int) ev.getY();// 手指按下时记录当前位置

122                 }

123                 break;

124             case MotionEvent.ACTION_UP:

125                 if (state != REFRESHING && state != LOADING) {

126                     if (state == PULL_To_REFRESH) {

127                         state = DONE;

128                         changeHeaderViewByState();

129                     }

130                     if (state == RELEASE_To_REFRESH) {

131                         state = REFRESHING;

132                         changeHeaderViewByState();

133                         onLvRefresh();

134                     }

135                 }

136                 isRecored = false;

137                 isBack = false;

138 

139                 break;

140 

141             case MotionEvent.ACTION_MOVE:

142                 int tempY = (int) ev.getY();

143                 if (!isRecored) {

144                     isRecored = true;

145                     startY = tempY;

146                 }

147                 if (state != REFRESHING && isRecored && state != LOADING) {

148                     // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动

149                     // 可以松手去刷新了

150                     if (state == RELEASE_To_REFRESH) {

151                         setSelection(0);

152                         // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步

153                         if (((tempY - startY) / RATIO < headerContentHeight)// 由松开刷新状态转变到下拉刷新状态

154                                 && (tempY - startY) > 0) {

155                             state = PULL_To_REFRESH;

156                             changeHeaderViewByState();

157                         }

158                         // 一下子推到顶了

159                         else if (tempY - startY <= 0) {// 由松开刷新状态转变到done状态

160                             state = DONE;

161                             changeHeaderViewByState();

162                         }

163                     }

164                     // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态

165                     if (state == PULL_To_REFRESH) {

166                         setSelection(0);

167                         // 下拉到可以进入RELEASE_TO_REFRESH的状态

168                         if ((tempY - startY) / RATIO >= headerContentHeight) {// 由done或者下拉刷新状态转变到松开刷新

169                             state = RELEASE_To_REFRESH;

170                             isBack = true;

171                             changeHeaderViewByState();

172                         }

173                         // 上推到顶了

174                         else if (tempY - startY <= 0) {// 由DOne或者下拉刷新状态转变到done状态

175                             state = DONE;

176                             changeHeaderViewByState();

177                         }

178                     }

179                     // done状态下

180                     if (state == DONE) {

181                         if (tempY - startY > 0) {

182                             state = PULL_To_REFRESH;

183                             changeHeaderViewByState();

184                         }

185                     }

186                     // 更新headView的size

187                     if (state == PULL_To_REFRESH) {

188                         headerView.setPadding(0, -1 * headerContentHeight

189                                 + (tempY - startY) / RATIO, 0, 0);

190 

191                     }

192                     // 更新headView的paddingTop

193                     if (state == RELEASE_To_REFRESH) {

194                         headerView.setPadding(0, (tempY - startY) / RATIO

195                                 - headerContentHeight, 0, 0);

196                     }

197 

198                 }

199                 break;

200 

201             default:

202                 break;

203             }

204         }

205         return super.onTouchEvent(ev);

206     }

207 

208     // 当状态改变时候,调用该方法,以更新界面

209     private void changeHeaderViewByState() {

210         switch (state) {

211         case RELEASE_To_REFRESH:

212             lvHeaderArrowIv.setVisibility(View.VISIBLE);

213             lvHeaderProgressBar.setVisibility(View.GONE);

214             lvHeaderTipsTv.setVisibility(View.VISIBLE);

215             lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);

216 

217             lvHeaderArrowIv.clearAnimation();// 清除动画

218             lvHeaderArrowIv.startAnimation(animation);// 开始动画效果

219 

220             lvHeaderTipsTv.setText("松开刷新");

221             break;

222         case PULL_To_REFRESH:

223             lvHeaderProgressBar.setVisibility(View.GONE);

224             lvHeaderTipsTv.setVisibility(View.VISIBLE);

225             lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);

226             lvHeaderArrowIv.clearAnimation();

227             lvHeaderArrowIv.setVisibility(View.VISIBLE);

228             // 是由RELEASE_To_REFRESH状态转变来的

229             if (isBack) {

230                 isBack = false;

231                 lvHeaderArrowIv.clearAnimation();

232                 lvHeaderArrowIv.startAnimation(reverseAnimation);

233 

234                 lvHeaderTipsTv.setText("下拉刷新");

235             } else {

236                 lvHeaderTipsTv.setText("下拉刷新");

237             }

238             break;

239 

240         case REFRESHING:

241 

242             headerView.setPadding(0, 0, 0, 0);

243 

244             lvHeaderProgressBar.setVisibility(View.VISIBLE);

245             lvHeaderArrowIv.clearAnimation();

246             lvHeaderArrowIv.setVisibility(View.GONE);

247             lvHeaderTipsTv.setText("正在刷新...");

248             lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);

249             break;

250         case DONE:

251             headerView.setPadding(0, -1 * headerContentHeight, 0, 0);

252 

253             lvHeaderProgressBar.setVisibility(View.GONE);

254             lvHeaderArrowIv.clearAnimation();

255             lvHeaderArrowIv.setImageResource(R.drawable.arrow);

256             lvHeaderTipsTv.setText("下拉刷新");

257             lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);

258             break;

259         }

260     }

261 

262     // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height

263     private void measureView(View child) {

264         ViewGroup.LayoutParams params = child.getLayoutParams();

265         if (params == null) {

266             params = new ViewGroup.LayoutParams(

267                     ViewGroup.LayoutParams.FILL_PARENT,

268                     ViewGroup.LayoutParams.WRAP_CONTENT);

269         }

270         int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0,

271                 params.width);

272         int lpHeight = params.height;

273         int childHeightSpec;

274         if (lpHeight > 0) {

275             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,

276                     MeasureSpec.EXACTLY);

277         } else {

278             childHeightSpec = MeasureSpec.makeMeasureSpec(0,

279                     MeasureSpec.UNSPECIFIED);

280         }

281         child.measure(childWidthSpec, childHeightSpec);

282     }

283 

284     public void setonRefreshListener(OnRefreshListener refreshListener) {

285         this.refreshListener = refreshListener;

286         isRefreshable = true;

287     }

288 

289     public interface OnRefreshListener {

290         public void onRefresh();

291     }

292 

293     public void onRefreshComplete() {

294         state = DONE;

295         lvHeaderLastUpdatedTv.setText("最近更新:" + new Date().toLocaleString());

296         changeHeaderViewByState();

297     }

298 

299     private void onLvRefresh() {

300         if (refreshListener != null) {

301             refreshListener.onRefresh();

302         }

303     }

304 

305     public void setAdapter(LvAdapter adapter) {

306         lvHeaderLastUpdatedTv.setText("最近更新:" + new Date().toLocaleString());

307         super.setAdapter(adapter);

308     }

309 

310     @Override

311     public void onScrollStateChanged(AbsListView view, int scrollState) {

312 

313     }

314 

315     @Override

316     public void onScroll(AbsListView view, int firstVisibleItem,

317             int visibleItemCount, int totalItemCount) {

318         if (firstVisibleItem == 0) {

319             isRefreshable = true;

320         } else {

321             isRefreshable = false;

322         }

323 

324     }

325 

326 }
View Code

重写完ListView之后,在布局文件中是这么使用的,头部下拉刷新的布局文件lv_header.xml的代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>

 2 <!-- ListView的头部 -->

 3 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

 4     android:layout_width="fill_parent"

 5     android:layout_height="wrap_content"

 6     android:background="#000000" >

 7 

 8     <!-- 内容 -->

 9 

10     <RelativeLayout

11         android:id="@+id/head_contentLayout"

12         android:layout_width="fill_parent"

13         android:layout_height="wrap_content"

14         android:paddingLeft="30dp" >

15 

16         <!-- 箭头图像、进度条 -->

17 

18         <FrameLayout

19             android:layout_width="wrap_content"

20             android:layout_height="wrap_content"

21             android:layout_alignParentLeft="true"

22             android:layout_centerVertical="true" >

23 

24             <!-- 箭头 -->

25 

26             <ImageView

27                 android:id="@+id/lvHeaderArrowIv"

28                 android:layout_width="wrap_content"

29                 android:layout_height="wrap_content"

30                 android:layout_gravity="center"

31                 android:src="@drawable/arrow" />

32 

33             <!-- 进度条 -->

34 

35             <ProgressBar

36                 android:id="@+id/lvHeaderProgressBar"

37                 style="?android:attr/progressBarStyleSmall"

38                 android:layout_width="wrap_content"

39                 android:layout_height="wrap_content"

40                 android:layout_gravity="center"

41                 android:visibility="gone" />

42         </FrameLayout>

43 

44         <!-- 提示、最近更新 -->

45 

46         <LinearLayout

47             android:layout_width="wrap_content"

48             android:layout_height="wrap_content"

49             android:layout_centerHorizontal="true"

50             android:gravity="center_horizontal"

51             android:orientation="vertical" >

52 

53             <!-- 提示 -->

54 

55             <TextView

56                 android:id="@+id/lvHeaderTipsTv"

57                 android:layout_width="wrap_content"

58                 android:layout_height="wrap_content"

59                 android:text="下拉刷新"

60                 android:textColor="@color/white"

61                 android:textSize="20sp" />

62 

63             <!-- 最近更新 -->

64 

65             <TextView

66                 android:id="@+id/lvHeaderLastUpdatedTv"

67                 android:layout_width="wrap_content"

68                 android:layout_height="wrap_content"

69                 android:text="上次更新"

70                 android:textColor="@color/gold"

71                 android:textSize="10sp" />

72         </LinearLayout>

73     </RelativeLayout>

74 

75 </LinearLayout>
View Code

在Main.xml中进行设置,代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>

 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

 3     android:layout_width="fill_parent"

 4     android:layout_height="fill_parent"

 5     android:background="#000000"

 6     android:orientation="vertical" >

 7 

 8     <net.loonggg.listview.MyListView

 9         android:id="@+id/lv"

10         android:layout_width="fill_parent"

11         android:layout_height="fill_parent" />

12 

13 </LinearLayout>
View Code

然后就是在MainActivity中实现,代码如下:

 1 package net.loonggg.listview;

 2 

 3 import java.util.ArrayList;

 4 import java.util.List;

 5 

 6 import net.loonggg.listview.MyListView.OnRefreshListener;

 7 import android.app.Activity;

 8 import android.os.AsyncTask;

 9 import android.os.Bundle;

10 import android.view.View;

11 

12 public class MainActivity extends Activity {

13     private List<String> list;

14     private MyListView lv;

15     private LvAdapter adapter;

16 

17     @Override

18     protected void onCreate(Bundle savedInstanceState) {

19         super.onCreate(savedInstanceState);

20         setContentView(R.layout.activity_main);

21         lv = (MyListView) findViewById(R.id.lv);

22         list = new ArrayList<String>();

23         list.add("loonggg");

24         list.add("我们都是开发者");

25         list.add("我们都是开发者");

26         list.add("我们都是开发者");

27         list.add("我们都是开发者");

28         list.add("我们都是开发者");

29         list.add("我们都是开发者");

30         list.add("我们都是开发者");

31         list.add("我们都是开发者");

32         list.add("我们都是开发者");

33         list.add("我们都是开发者");

34         list.add("我们都是开发者");

35         list.add("我们都是开发者");

36         list.add("我们都是开发者");

37         list.add("我们都是开发者");

38         list.add("我们都是开发者");

39         list.add("我们都是开发者");

40         adapter = new LvAdapter(list, this);

41         lv.setAdapter(adapter);

42 

43         lv.setonRefreshListener(new OnRefreshListener() {

44 

45             @Override

46             public void onRefresh() {

47                 new AsyncTask<Void, Void, Void>() {

48                     protected Void doInBackground(Void... params) {

49                         try {

50                             Thread.sleep(1000);

51                         } catch (Exception e) {

52                             e.printStackTrace();

53                         }

54                         list.add("刷新后添加的内容");

55                         return null;

56                     }

57 

58                     @Override

59                     protected void onPostExecute(Void result) {

60                         adapter.notifyDataSetChanged();

61                         lv.onRefreshComplete();

62                     }

63                 }.execute(null, null, null);

64             }

65         });

66     }

67 }
View Code

这里还需要为ListView设置一下Adapter,自定义的Adapter如下:

 1 package net.loonggg.listview;

 2 

 3 import java.util.List;

 4 

 5 import android.content.Context;

 6 import android.view.View;

 7 import android.view.ViewGroup;

 8 import android.widget.BaseAdapter;

 9 import android.widget.TextView;

10 

11 public class LvAdapter extends BaseAdapter {

12     private List<String> list;

13     private Context context;

14 

15     public LvAdapter(List<String> list, Context context) {

16         this.list = list;

17         this.context = context;

18     }

19 

20     @Override

21     public int getCount() {

22         return list.size();

23     }

24 

25     @Override

26     public Object getItem(int position) {

27         return list.get(position);

28     }

29 

30     @Override

31     public long getItemId(int position) {

32         return position;

33     }

34 

35     @Override

36     public View getView(int position, View convertView, ViewGroup parent) {

37         TextView tv = new TextView(context.getApplicationContext());

38         tv.setText(list.get(position));

39         return tv;

40     }

41 

42 }
View Code

到这里就完了,代码中的解释非常详细,具体的我就不多说了,也不解释了,自己看看并研究吧!

你可能感兴趣的:(ListView)