整理了下以前写的小项目,ListView的下拉刷新,虽然小但还是想纪念下。。适合新手看,大神略过。。。
效果图:
代码: 实体类
package com.example.listviewrefreshdemo;/** * @author 超超boy */public class ApkEntity { private String name; private String des; private String info; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDes() { return des; } public void setDes(String des) { this.des = des; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
MainActivity:
package com.example.listviewrefreshdemo;import java.util.ArrayList;import com.example.listviewrefreshdemo.RefreshListView.IReflashListener;import android.app.Activity;import android.os.Bundle;import android.os.Handler;/** * @author 超超boy */public class MainActivity extends Activity implements IReflashListener{ ArrayListapk_list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setData(); showList(apk_list); } MyAdapter adapter; RefreshListView listview; private void showList(ArrayList apk_list) { if (adapter == null) { listview = (RefreshListView) findViewById(R.id.listview); listview.setIReflashListener(this); adapter = new MyAdapter(this, apk_list); listview.setAdapter(adapter); } else { adapter.onDateChange(apk_list); } } private void setData() { apk_list = new ArrayList (); for (int i = 0; i < 10; i++) { ApkEntity entity = new ApkEntity(); entity.setName("默认数据"); entity.setDes("这是一个神奇的应用"); entity.setInfo("50w用户"); apk_list.add(entity); } } private void setReflashData() { for (int i = 0; i < 2; i++) { ApkEntity entity = new ApkEntity(); entity.setName("刷新数据"); entity.setDes("这是一个神奇的应用"); entity.setInfo("50w用户"); apk_list.add(i,entity); } } @Override public void onReflash() { // TODO Auto-generated method stub\ Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { // TODO Auto-generated method stub //获取最新数据 setReflashData(); //通知界面显示 showList(apk_list); //通知listview 刷新数据完毕; listview.reflashComplete(); } }, 2000); } /** * 回掉方法 */ /*public void onReflash() { //获取最新数据 setReflashData(); //通知界面显示 showList(apk_list); //通知listview刷新数据完毕 listview.reflashComplete(); }*/}
RefreshListView:
package com.example.listviewrefreshdemo;import java.text.SimpleDateFormat;import java.util.Date;import android.R.anim;import android.R.interpolator;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.ImageView;import android.widget.ListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ProgressBar;import android.widget.TextView;/** * @author 超超boy */public class RefreshListView extends ListView implements OnScrollListener{ LayoutInflater inflater; View header; int headerHeight; //顶部布局文件的高度 int firstVisibleItem; //当前第一个可见的item的位置 int scrollState; //listview当前滚动状态 boolean isRemark; //标记,当前是在listview的最顶部摁下的 int startY; //摁下时的Y值 int state; //当前的状态 final int NONE = 0;// 正常状态; final int PULL = 1;// 提示下拉状态; final int RELESE = 2;// 提示释放状态; final int REFLASHING = 3;// 刷新状态; IReflashListener reflashListener; public RefreshListView(Context context) { super(context); initView(context); } public RefreshListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); } public RefreshListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } /** * 初始化界面,添加顶部布局文件到ListView * @param context */ private void initView(Context context){ inflater = LayoutInflater.from(context); header =inflater.inflate(R.layout.header, null); measureView(header); headerHeight = header.getMeasuredHeight(); Log.i("tag", "headerHeight="+headerHeight); topPadding(-headerHeight); //负的高度,把它能没啦 this.addHeaderView(header); this.setOnScrollListener(this); } /** * 通知父布局,占用的宽高。 * @param view */ private void measureView(View view){ ViewGroup.LayoutParams p = view.getLayoutParams(); if(p == null){ p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } //spec:header的左右边距,padding内边距,childDimension字布局的宽度 int width = ViewGroup.getChildMeasureSpec(0, 0, p.width); int height; int tempHeight = p.height; if(tempHeight > 0){ //高度不是空,需要填充这个布局 //EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小; height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY); }else{ //UNSPECIFIED(未指定),父元素不对子元素施加任何束缚,子元素可以得到任意想要的大小; height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } view.measure(width, height); } /** * 设置header布局的上边距 * @param topPadding */ private void topPadding(int topPadding){ //header的上边距 header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom()); header.invalidate(); } /** * 取得当前的滚动状态 */ public void onScrollStateChanged(AbsListView view, int scrollState) { this.scrollState = scrollState; } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.firstVisibleItem = firstVisibleItem; //当前第一个可见的item的位置 } /** * 触摸事件 */ public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //下拉 if (firstVisibleItem == 0) { //在界面最顶端 isRemark = true; //标记,当前是在listview的最顶部摁下的 startY = (int) ev.getY(); } break; case MotionEvent.ACTION_MOVE: onMove(ev); break; case MotionEvent.ACTION_UP: //抬起 if (state == RELESE) { //释放 state = REFLASHING; //正在刷新 // 加载最新数据; reflashViewByState(); reflashListener.onReflash(); } else if (state == PULL) { //下拉过程中,没到一定距离的时候 state = NONE; // 正常状态; isRemark = false; //在顶部的标记 reflashViewByState(); } break; } return super.onTouchEvent(ev); } /** * 判断移动过程的操作 * @param ev */ private void onMove(MotionEvent ev) { if(!isRemark){ //不在顶的时候移动 return; } //移动的过程中状态是不断改变的 int tempY = (int) ev.getY(); int sapce = tempY-startY; //移动的距离 int topPadding = sapce - headerHeight; //移动过程中不断设置topPadding switch (state) { case NONE: // 正常状态; if(sapce>0){ state = PULL; // 提示下拉状态 reflashViewByState(); } break; case PULL: // 提示下拉状态; topPadding(topPadding); //不断设置上边距 if(sapce > headerHeight+30 && scrollState == SCROLL_STATE_TOUCH_SCROLL){ state = RELESE; // 提示释放状态; reflashViewByState(); } break; case RELESE: // 提示释放状态; topPadding(topPadding); if(sapce
适配器:
package com.example.listviewrefreshdemo;import java.util.ArrayList;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;/** * @author 超超boy */public class MyAdapter extends BaseAdapter { ArrayListapk_list; LayoutInflater inflater; public MyAdapter(Context context, ArrayList apk_list) { this.apk_list = apk_list; this.inflater = LayoutInflater.from(context); } public void onDateChange(ArrayList apk_list) { this.apk_list = apk_list; this.notifyDataSetChanged(); //更新数据 } @Override public int getCount() { // TODO Auto-generated method stub return apk_list.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return apk_list.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ApkEntity entity = apk_list.get(position); ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); convertView = inflater.inflate(R.layout.item_layout, null); holder.name_tv = (TextView) convertView .findViewById(R.id.item3_apkname); holder.des_tv = (TextView) convertView .findViewById(R.id.item3_apkdes); holder.info_tv = (TextView) convertView .findViewById(R.id.item3_apkinfo); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } holder.name_tv.setText(entity.getName()); holder.des_tv.setText(entity.getDes()); holder.info_tv.setText(entity.getInfo()); return convertView; } class ViewHolder { TextView name_tv; TextView des_tv; TextView info_tv; }}
activity_main.xml:
布局文件还有header.xml和item_layout.xml,就不粘贴了,想看的可以去下我的源代码,下边有下载链接。。
二、代码逻辑
1.自定义状态:PULL下拉状态,RELESE释放状态,REFLASHING刷新状态
2. AbsListView的触摸事件:
下拉的时候设置startY(开始滑动时的位置),之后就是不断的滑动过程,滑动的过程中,用自定义的onMove方法改变状态和header界面(下拉刷新,释放刷新,刷新中);
刷新:
case MotionEvent.ACTION_UP: //抬起
if (state == RELESE) { //释放 state = REFLASHING; //正在刷新 reflashViewByState();// 加载最新数据;reflashListener.onReflash(); //在回调接口刷新 }
3.自定义的move时判断状态信息:
下拉->释放:sapce > headerHeight+30 判断距离,距离够了就改变状态:释放状态,释放更新
int sapce = tempY-startY; //移动的距离 int topPadding = sapce - headerHeight; //移动过程中不断设置topPadding switch (state) { case NONE: // 正常状态; if(sapce>0){ state = PULL; // 提示下拉状态 reflashViewByState(); } break; case PULL: // 提示下拉状态; topPadding(topPadding); //不断设置上边距 if(sapce > headerHeight+30 && scrollState == SCROLL_STATE_TOUCH_SCROLL){ state = RELESE; // 提示释放状态; reflashViewByState(); } break; case RELESE: // 提示释放状态; topPadding(topPadding); if(sapce
ok。。代码很简单。。。
Demo源代码下载:
附一篇很好的博文::http://blog.csdn.net/leehong2005/article/details/12567757
转发请注明出处: