博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android之下拉刷新的ListView
阅读量:5126 次
发布时间:2019-06-13

本文共 10743 字,大约阅读时间需要 35 分钟。

不废话,代码里面注释很详细,直接上代码:

自定义的RefreshableListView代码:

1 public class RefreshableListView extends ListView implements OnScrollListener {  2     private View header; // ListView顶部布局  3     private LayoutInflater inflater;  4     private int headerHeight; // 顶部布局Header的高度  5     private int firstVisisblePosition; // 当前第一个可见的Item的位置  6     private int scrollState; // ListView当前的滚动状态  7   8     private boolean remarkTop; // 标记,当前是在ListView的最顶端按下的  9     private int startY; // 手指按下时的Y值 10  11     private int state; // 指示当前的状态 12     private final int STATE_NORMAL = 0; // 正常状态 13     private final int STATE_PULL = 1; // 提示“下拉可以刷新”的状态 14     private final int STATE_TOREFRESH = 2; // 提示“松开手指刷新”的状态 15     private final int STATE_REFRESHING = 3; // 正在刷新的状态 16  17     // Header布局中的四个控件 18     private TextView refreshTip; // 显示“下拉可以刷新”/“松开手指刷新”的TextView 19     private TextView timeTip; // 显示上次刷新的时间的TextView 20     private ImageView arrowImg; // 向上/向下的箭头的ImageView 21     private ProgressBar progressBar; // 刷新数据时用到的ProgressBar 22  23     private ListViewRefreshListener listener; // 刷新数据的接口 24  25     // 自定义控件都必须实现以下三个构造方法(一个参数、两个参数、三个参数的构造方法) 26     // 我们在一个参数的构造方法中调用两个参数的构造方法,在两个参数的构造方法中调用三个参数的构造方法,这样不管我们用哪个构造方法,最终的调用代码是一样的 27     // 一个参数的构造方法:这个方法是在Activity中根据上下文环境直接生成控件时调用的 28     public RefreshableListView(Context context) { 29         this(context, null); 30     } 31  32     // 两个参数的构造方法:这个方法是在使用了系统属性,没有使用自定义属性时调用的 33     public RefreshableListView(Context context, AttributeSet attrs) { 34         this(context, attrs, 0); 35     } 36  37     // 三个参数的构造方法:这个方法是在使用了自定义属性时调用的 38     public RefreshableListView(Context context, AttributeSet attrs, int defStyleAttr) { 39         super(context, attrs, defStyleAttr); 40         initView(context); 41         // 找到Header中的控件 42         refreshTip = (TextView) header.findViewById(R.id.control_header_refreshtip); 43         timeTip = (TextView) header.findViewById(R.id.control_header_timetip); 44         arrowImg = (ImageView) header.findViewById(R.id.control_header_refresharrow); 45         progressBar = (ProgressBar) header.findViewById(R.id.control_header_progressbar); 46     } 47  48     // 初始化界面,添加顶部布局文件到ListView中 49     private void initView(Context context) { 50         inflater = LayoutInflater.from(context); 51         header = inflater.inflate(R.layout.sideworks_layout_header, null); 52         // 测量顶部布局header的高度 53         measureView(context); 54         headerHeight = header.getMeasuredHeight(); 55         setViewTopPadding(-headerHeight); // 设置ListView的上缩进:是负值,表示将header布局缩到屏幕外面去 56         // 把顶部布局添加到ListView的最上面 57         this.addHeaderView(header); 58         // 设置向下滑动时逐渐显示顶部布局(接口回掉方法) 59         this.setOnScrollListener(this); 60     } 61  62     // 测量控件的宽高(通知父佈局:我佔用的寬和高) 63     private void measureView(Context context) { 64         ViewGroup.LayoutParams lp = header.getLayoutParams(); // 获取header布局的宽高属性 65         if (lp == null) { 66             lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 67         } 68         int width = ViewGroup.getChildMeasureSpec(0, 0, lp.width); 69         int height; // 不能用getChildMeasureSpec方法获取高度的原因是ListView的高度不确定,而宽度是确定的 70         int tempHeight = lp.height; 71         if (tempHeight > 0) { // 大于0说明定义了ListView的高度,所以我们用精确布局模式EXACTLY 72             height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY); 73         } else { // 如果不大于0,则表示没有定义ListView的高度,即UNSPECIFIED 74             height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); 75         } 76         header.measure(width, height); // 这行代码很容易报错:NullPointerException,所以SDK17以前的版本必须将布局的最外层设置为LinearLayout 77     } 78  79     // 设置ListView的TopPadding属性 80     private void setViewTopPadding(int topPadding) { 81         this.setPadding(this.getPaddingLeft(), topPadding, this.getPaddingRight(), this.getPaddingBottom()); 82         this.invalidate(); // invalidate()方法的作用是请求对该控件进行重绘 83     } 84  85     @Override 86     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 87         this.firstVisisblePosition = firstVisibleItem; 88     } 89  90     @Override 91     public void onScrollStateChanged(AbsListView view, int scrollState) { 92         this.scrollState = scrollState; 93     } 94  95     @Override 96     public boolean onTouchEvent(MotionEvent ev) { 97         switch (ev.getAction()) { 98         case MotionEvent.ACTION_DOWN: 99             if (firstVisisblePosition == 0) {100                 remarkTop = true;101                 startY = (int) ev.getY(); // 如果按下时是处在ListView最上面的Item,则记录当前的Y坐标值102             }103             break;104         case MotionEvent.ACTION_MOVE:105             onMove(ev);106             break;107         case MotionEvent.ACTION_UP:108             if (state == STATE_TOREFRESH) { // 滑动到了“松开手指刷新数据”的高度109                 state = STATE_REFRESHING;110                 refreshViewByState();111                 listener.refreshListView(); // 调用接口,刷新数据112             } else if (state == STATE_PULL) { // 还是处在“下拉刷新数据”的高度113                 state = STATE_NORMAL;114                 remarkTop = false;115                 refreshViewByState();116             }117             break;118         }119         return super.onTouchEvent(ev);120     }121 122     // 判断移动过程中的操作123     private void onMove(MotionEvent ev) {124         if (!remarkTop) { // 如果按下地点不是ListView的第一个Item,则不做处理,正常滑动125             return;126         }127         int tempY = (int) ev.getY(); // 当前移动到了什么位置(Y坐标值)128         int space = tempY - startY; // 判断当前移动了多大距离(即header布局被拉下来多少),向下拉时是正值129         int topPadding = space - headerHeight; // 当前还在屏幕外面的header布局的高度130         switch (state) {131         case STATE_NORMAL:132             if (space > 0) {133                 state = STATE_PULL;134                 refreshViewByState();135             }136             break;137         case STATE_PULL:138             setViewTopPadding(topPadding);139             if (space > headerHeight && scrollState == SCROLL_STATE_TOUCH_SCROLL) { // 滑动过header高度的一半并且仍然在滑动140                 state = STATE_TOREFRESH;141                 refreshViewByState();142             }143             break;144         case STATE_TOREFRESH:145             setViewTopPadding(topPadding);146             if (space < headerHeight) {147                 state = STATE_PULL;148                 refreshViewByState();149             } else if (space <= 0) {150                 state = STATE_NORMAL;151                 remarkTop = false;152                 refreshViewByState();153             }154             break;155         }156     }157 158     // 根据当前状态,改变界面显示159     private void refreshViewByState() {160         // 箭头反转的两个动画161         RotateAnimation anim1 = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);162         anim1.setDuration(500);163         anim1.setFillAfter(true);164         RotateAnimation anim2 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);165         anim2.setDuration(500);166         anim2.setFillAfter(true);167 168         switch (state) {169         case STATE_NORMAL:170             setViewTopPadding(-headerHeight);171             arrowImg.clearAnimation();172             break;173         case STATE_PULL:174             arrowImg.setVisibility(View.VISIBLE);175             progressBar.setVisibility(View.GONE);176             refreshTip.setText("下拉可以刷新!");177             arrowImg.clearAnimation();178             arrowImg.setAnimation(anim2);179             break;180         case STATE_TOREFRESH:181             arrowImg.setVisibility(View.VISIBLE);182             progressBar.setVisibility(View.GONE);183             refreshTip.setText("松开立即刷新!");184             arrowImg.clearAnimation();185             arrowImg.setAnimation(anim1);186             break;187         case STATE_REFRESHING:188             setViewTopPadding(0);189             arrowImg.setVisibility(View.GONE);190             progressBar.setVisibility(View.VISIBLE);191             refreshTip.setText("正在刷新......");192             arrowImg.clearAnimation();193             break;194         }195     }196 197     public void onRefreshComplete() {198         state = STATE_NORMAL;199         remarkTop = false;200         refreshViewByState();201         String time = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());202         timeTip.setText(time);203     }204 205     // 刷新数据的接口,要通过接口回掉的方式更新数据206     public interface ListViewRefreshListener {207         public void refreshListView();208     }209 210     public void setListViewRefreshListener(ListViewRefreshListener listener) {211         this.listener = listener;212     }213 }

header布局界面sideworks_layout_header.xml代码:

1 
8 9
13 14
23 24
32 33
40 41 42
49 50
57
58 59 60

主界面布局activity_main.xml代码:

1 
5 6
11 12

主界面MainActivity.java代码:

1 public class MainActivity extends Activity implements ListViewRefreshListener { 2     private RefreshableListView testList; 3     public static List
dataList; 4 public static ArrayAdapter
listAdapter; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main);10 initView();11 }12 13 private void initView() {14 testList = (RefreshableListView) findViewById(R.id.control_main_listview);15 testList.setListViewRefreshListener(this);16 dataList = getData();17 listAdapter = new ArrayAdapter
(this, android.R.layout.simple_expandable_list_item_1, dataList);18 testList.setAdapter(listAdapter);19 }20 21 private List
getData() {22 dataList = new ArrayList
();23 for (int i = 0; i < 10; i++) {24 dataList.add("This is a test data.");25 }26 return dataList;27 }28 29 @Override30 public void refreshListView() {31 // 延时两秒后显示两条新数据:This is a new data.32 new Handler().postDelayed(new Runnable() {33 public void run() {34 for (int i = 0; i < 2; i++) {35 dataList.add(0, "This is a new data.");36 }37 listAdapter.notifyDataSetChanged();38 testList.onRefreshComplete();39 }40 }, 2000);41 }42 }

 

转载于:https://www.cnblogs.com/blog-wzy/p/5313189.html

你可能感兴趣的文章
tr命令
查看>>
字符串表达式
查看>>
shell中的一些关键字
查看>>
条件表达式
查看>>
整数比较操作符和逻辑操作符
查看>>
fragment间的数据传递
查看>>
下载评书
查看>>
学数学——林群讲的东西
查看>>
(爬虫)随机生成一个header
查看>>
一闪一闪亮晶晶
查看>>
网页状态码
查看>>
绘制UML图的工具
查看>>
物理引擎 书籍搜集
查看>>
excel绘制多列 其中一列作为横坐标 ; 数值拟合
查看>>
git add命令行添加文件、文件夹以及撤销文件add的方法
查看>>
windows下的文件管理工具--total commander
查看>>
sizeof(类名字)
查看>>
四元数
查看>>
功率谱密度如何理解
查看>>
git clean解决 GIT error: The following untracked working tree files would be overwritten
查看>>