Android--简单的自定义ListView下拉刷新
2017-01-11 15:40 It一zhai男 阅读(4216) 评论(0) 编辑 收藏 举报ListView下拉刷新一般要注意以下几点:
1. listview的头布局
2. 注意标志的应用,即刷新的几个状态,分别是下拉刷新,松开刷新和正在刷新
3. 注意几个动画效果,即箭头旋转,刷新图标旋转等
先上效果图:
下面,我们来分别介绍。
先来说说这个demo里用到的几个方法。
(1)public boolean onTouchEvent(MotionEvent ev):这个方法是手势触摸事件。这里主要用到了MotionEvent.ACTION_DOWN(手势按下)、MotionEvent.ACTION_MOVE(手势滑动)和MotionEvent.ACTION_UP(手指抬起手势)。
下拉刷新,是先将listview的头部隐藏,然后用手势拖动屏幕刷新。那么,listview的头部如何隐藏呢?这里用的是header.setPadding(0,-headerViewHeight,0,0)来隐藏头部,这里不细说,等下介绍。如图1所示,要让listview的头部跟着手势一起向下滑动,则需要记录手指移动的距离。所以,当MotionEvent.ACTION_DOWN(手势按下)触发时,需要一个downY记录手势按下时y的偏移值,然后随着手势的滑动即MotionEvent.ACTION_MOVE(手势滑动)触发时,又需要一个moveY记录移动的偏移值,然后paddingTop=moveY-downY得到的就是手指滑动的距离。然后用paddingTop-headerViewHeight(相减的值设为x)得到头部的顶部到屏幕的顶部距离。如果想x>0则说明头部完全显示,如果x<0则头部没有完全显示。
这里要设置几个标志位
PULL_DOWN_REFRESH(下拉刷新):当头部未完全显示时为下拉刷新状态。
RELEASE_REFRESH(释放刷新):当头部完全显示时为释放刷新状态。
REFRESHING(正在刷新):当手势抬起,并头部完全显示时为正在刷新。
其他的都比较简单,在程序里都有注释,这里就不再赘述了。上代码:
RefreshListView.java
package com.example.yds.pulldowntest; 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.animation.Animation; import android.view.animation.RotateAnimation; import android.widget.ImageView; import android.widget.ListView; import android.widget.AbsListView; import android.widget.TextView; import org.w3c.dom.Text; /** * Created by yds on 2017/1/10. */ public class RefreshListView extends ListView implements AbsListView.OnScrollListener { //头布局视图 private View header; //头布局高度 private int headerViewHeight; //按下时y的偏移量 private int downY; //移动时y的偏移量 private int moveY; //距离顶部的距离 private int paddingTop; //listview第一个可见的item项 private int firstVisibleItemPosition; //下拉刷新 private final int PULL_DOWN_REFRESH = 0; //释放刷新 private final int RELEASE_REFRESH = 1; //正在刷新 private final int REFRESHING = 2; //当前状态,默认为下拉刷新 private int currentState = PULL_DOWN_REFRESH; //刷新列表构造函数 private Context context; //刷新监听 private OnRefreshListener mOnRefreshListener; private ImageView refresh; private RotateAnimation animation; //图片向上旋转 private Animation upAnimation; //图片向下旋转 private Animation downAnimation; //箭头 private ImageView row; //提示文本 private TextView header_tv; public RefreshListView(Context context, AttributeSet attrs) { super(context, attrs); //初始化头布局 initHeaderView(); //滑动监听 this.setOnScrollListener(this); this.context = context; } /**滚动状态改变时调用,一般用于列表视图和网格视图 * * @param view * @param scrollState 有三种值,分别是SCROLL_STATE_IDLE,SCROLL_STATE_TOUCH_SCROLL,SCROLL_STATE_FLING * SCROLL_STATE_IDLE:当屏幕停止滚动时 * SCROLL_STATE_TOUCH_SCROLL:当屏幕以触屏方式滚动并且手指还在屏幕上时 * SCROLL_STATE_FLING:当用户之前滑动屏幕并抬起手指,屏幕以惯性滚动 */ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState==SCROLL_STATE_IDLE||scrollState == SCROLL_STATE_FLING){ } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { firstVisibleItemPosition = firstVisibleItem; } // public void setOnRefreshListener(OnRefreshListener listener){ // // } public void setOnRefreshListener(OnRefreshListener listener){ mOnRefreshListener = listener; } private void initHeaderView(){ //头布局文件 header = LayoutInflater.from(getContext()).inflate(R.layout.header,null); //测量头布局,绘制一个视图一般经过measure,layout,draw header.measure(0,0); //头布局高度 headerViewHeight = header.getMeasuredHeight(); //设置间隔 header.setPadding(0,-headerViewHeight,0,0); //加载头布局 this.addHeaderView(header); refresh = (ImageView) header.findViewById(R.id.refresh); row = (ImageView) header.findViewById(R.id.row); header_tv = (TextView) header.findViewById(R.id.header_tv); initAnimation(); } private void initAnimation(){ animation = new RotateAnimation(0f,360f, Animation.RELATIVE_TO_SELF,0.48f,Animation.RELATIVE_TO_SELF,0.47f); animation.setDuration(500); animation.setRepeatCount(5); upAnimation = new RotateAnimation(0f,180f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f); upAnimation.setDuration(300); upAnimation.setFillAfter(true); downAnimation = new RotateAnimation(180f,360f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f); downAnimation.setDuration(300); downAnimation.setFillAfter(true); // refresh.setAnimation(animation); } /** * 触摸事件 * @param ev * @return */ @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()){ //手指按下 case MotionEvent.ACTION_DOWN: //记录按下时y的偏移量 downY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE://手指滑动 //记录移动时的y值偏移 moveY = (int) ev.getY(); //可以看成头布局距离屏幕顶部的距离,这里除以2是控制手指滑动 paddingTop = (moveY - downY)/2-headerViewHeight; if(firstVisibleItemPosition==0&&-headerViewHeight<paddingTop){//必须的条件 //如果paddingTop>0就说明完全显示了,但还要判断当前状态是否是下拉刷新状态,因为正在刷新状态也是完全显示 if(paddingTop>0&¤tState == PULL_DOWN_REFRESH){//完全显示 header_tv.setText("松开刷新"); //将当前状态置为释放刷新 currentState = RELEASE_REFRESH; changeHeaderByViewState(); }else if(paddingTop<0&¤tState == RELEASE_REFRESH){//没有完全显示,currentState=RELEASE_REFRESH原因是可以先滑到完全显示后再往上滑到不完全显示 currentState = PULL_DOWN_REFRESH; header_tv.setText("下拉刷新"); changeHeaderByViewState(); } header.setPadding(0,paddingTop,0,0); } break; case MotionEvent.ACTION_UP: if(currentState == RELEASE_REFRESH){//完全显示 header.setPadding(0,0,0,0); currentState = REFRESHING; changeHeaderByViewState(); if (mOnRefreshListener!=null){ mOnRefreshListener.downPullRefresh(); } }else if(currentState == PULL_DOWN_REFRESH){//未完全显示 //当手指松开时,若头部未完全显示则隐藏头部 header.setPadding(0,-headerViewHeight,0,0); } break; } return super.onTouchEvent(ev); } private void changeHeaderByViewState(){ switch (currentState){ case PULL_DOWN_REFRESH: row.startAnimation(downAnimation); break; case RELEASE_REFRESH: row.startAnimation(upAnimation); break; case REFRESHING: row.clearAnimation(); row.setVisibility(View.GONE); header_tv.setText("正在刷新"); refresh.clearAnimation(); refresh.setVisibility(View.VISIBLE); refresh.startAnimation(animation); break; } } public void hideHeaderView(){ header.setPadding(0,-headerViewHeight,0,0); refresh.setVisibility(View.GONE); currentState = PULL_DOWN_REFRESH; header_tv.setText("下拉刷新"); row.setVisibility(View.VISIBLE); } }
MainActivity.java
package com.example.yds.pulldowntest; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.widget.TextView; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MainActivity extends Activity implements OnRefreshListener{ private TextView log_tv; private RefreshListView listView; private PullDownAdapter adapter; private Map<String,Object>map; List<Map<String,Object>>list = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); log_tv = (TextView) findViewById(R.id.log_tv); listView = (RefreshListView) findViewById(R.id.listview); for (int i = 0 ;i < 5 ; i++){ map = new HashMap<>(); map.put("name","this "+i); list.add(map); } adapter = new PullDownAdapter(this,list); listView.setOnRefreshListener(this); listView.setAdapter(adapter); log_tv.setText(list.get(0).get("name").toString()+"this is null?"+list.get(1).get("name").toString()); } @Override public void downPullRefresh() { new AsyncTask<Void,Void,Void>(){ @Override protected Void doInBackground(Void... params) { SystemClock.sleep(2800); map = list.get(0); map.put("name","这是刷新后的数据"); list.add(map); return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); adapter.notifyDataSetChanged(); listView.hideHeaderView(); } }.execute(new Void[]{}); } }
源码下载地址:
http://download.csdn.net/detail/u013293125/9734831