1 package domain.css.cn.com.btmscss.xxtx.view; 2 3 import android.content.Context; 4 import android.util.AttributeSet; 5 import android.util.Log; 6 import android.view.MotionEvent; 7 import android.view.View; 8 import android.view.ViewConfiguration; 9 import android.view.animation.Animation; 10 import android.view.animation.RotateAnimation; 11 import android.widget.AbsListView; 12 import android.widget.ImageView; 13 import android.widget.ListView; 14 import android.widget.ProgressBar; 15 import android.widget.TextView; 16 17 import java.text.SimpleDateFormat; 18 19 import domain.css.cn.com.btmscss.R; 20 21 /** 22 * Created by keranbin on 2015/12/30. 23 */ 24 public class ZdyListView extends ListView implements AbsListView.OnScrollListener { 25 private static final String TAG = "DbLbListView"; 26 27 private int firstVisibleItemPosition; // 屏幕显示在第一个的item的索引 28 private int downY; // 按下时y轴的偏移量 29 private int headerViewHeight; // 头布局的高度 30 private View headerView; // 头布局的对象 31 32 private final int DOWN_PULL_REFRESH = 0; // 下拉刷新状态 33 private final int RELEASE_REFRESH = 1; // 松开刷新 34 private final int REFRESHING = 2; // 正在刷新中 35 private int currentState = DOWN_PULL_REFRESH; // 头布局的状态: 默认为下拉刷新状态 36 37 private Animation upAnimation; // 向上旋转的动画 38 private Animation downAnimation; // 向下旋转的动画 39 40 private ImageView ivArrow; // 头布局的剪头 41 private ProgressBar mProgressBar; // 头布局的进度条 42 private TextView tvState; // 头布局的状态 43 private TextView tvLastUpdateTime; // 头布局的最后更新时间 44 45 private OnRefreshListener onRefreshListener; 46 private boolean isScrollToBottom; // 是否滑动到底部 47 private View footerView; // 脚布局的对象 48 private int footerViewHeight; // 脚布局的高度 49 private boolean isLoadingMore = false; // 是否正在加载更多中 50 51 private int mLastX = 0; 52 private int mLastY = 0; 53 54 private int mLastXIntercept=0; 55 private int mLastYIntercept=0; 56 57 58 public ZdyListView(Context context) { 59 super(context); 60 initView(context); 61 } 62 63 public ZdyListView(Context context, AttributeSet attrs) { 64 super(context, attrs); 65 initView(context); 66 } 67 68 public ZdyListView(Context context, AttributeSet attrs, int defStyleAttr) { 69 super(context, attrs, defStyleAttr); 70 initView(context); 71 } 72 73 private void initView(Context context) { 74 initHeaderView(); 75 initFooterView(); 76 this.setOnScrollListener(this); 77 } 78 79 /** 80 * 初始化头布局 81 */ 82 private void initHeaderView() { 83 headerView = View.inflate(getContext(), R.layout.layout_listview_headview, null); 84 ivArrow = (ImageView) headerView.findViewById(R.id.iv_listview_header_arrow); 85 mProgressBar = (ProgressBar) headerView.findViewById(R.id.pb_listview_header); 86 tvState = (TextView) headerView.findViewById(R.id.tv_listview_header_state); 87 tvLastUpdateTime = (TextView) headerView.findViewById(R.id.tv_listview_header_last_update_time); 88 89 // 设置最后刷新时间 90 tvLastUpdateTime.setText("最后刷新时间: " + getLastUpdateTime()); 91 92 headerView.measure(0, 0); // 系统会帮我们测量出headerView的高度 93 headerViewHeight = headerView.getMeasuredHeight(); 94 headerView.setPadding(0, -headerViewHeight, 0, 0); 95 this.addHeaderView(headerView, null, false); // 向ListView的顶部添加一个view对象 96 initAnimation(); 97 98 } 99 100 /** 101 * 初始化脚布局 102 */ 103 private void initFooterView() { 104 footerView = View.inflate(getContext(), R.layout.layout_listview_footerview, null); 105 footerView.measure(0, 0); 106 footerViewHeight = footerView.getMeasuredHeight(); 107 footerView.setPadding(0, -footerViewHeight, 0, 0); 108 this.addFooterView(footerView); 109 } 110 111 112 /** 113 * 获得系统的最新时间 114 * 115 * @return 116 */ 117 private String getLastUpdateTime() { 118 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 119 return sdf.format(System.currentTimeMillis()); 120 } 121 122 123 private void initAnimation() { 124 upAnimation = new RotateAnimation(0f, -180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 125 upAnimation.setDuration(500); 126 upAnimation.setFillAfter(true); // 动画结束后, 停留在结束的位置上 127 128 downAnimation = new RotateAnimation(-180f, -360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); 129 downAnimation.setDuration(500); 130 downAnimation.setFillAfter(true); // 动画结束后, 停留在结束的位置上 131 } 132 133 134 @Override 135 public boolean onInterceptTouchEvent(MotionEvent ev) { 136 int intercepter = 0; 137 int x = (int) ev.getX(); 138 int y = (int) ev.getY(); 139 switch (ev.getAction()) { 140 case MotionEvent.ACTION_DOWN: { 141 mLastXIntercept=x; 142 mLastYIntercept=y; 143 mLastX=x; 144 mLastY=y; 145 intercepter=0; 146 break; 147 } 148 case MotionEvent.ACTION_MOVE:{ 149 int deltaX=x-mLastXIntercept; 150 int deltaY=y-mLastYIntercept; 151 switch (currentState){ 152 153 } 154 } 155 case MotionEvent.ACTION_UP:{ 156 intercepter=0; 157 mLastXIntercept=mLastYIntercept=0; 158 break; 159 } 160 default:break; 161 162 163 } 164 return super.onInterceptTouchEvent(ev); 165 } 166 167 @Override 168 public boolean onTouchEvent(MotionEvent ev) { 169 switch (ev.getAction()) { 170 case MotionEvent.ACTION_DOWN:{} 171 downY = (int) ev.getY(); 172 break; 173 case MotionEvent.ACTION_MOVE: 174 int moveY = (int) ev.getY(); 175 // 移动中的y - 按下的y = 间距. 176 int diff = (moveY - downY) / 2; 177 // -头布局的高度 + 间距 = paddingTop 178 int paddingTop = -headerViewHeight + diff; 179 // 如果: -头布局的高度 > paddingTop的值 执行super.onTouchEvent(ev); 180 if (firstVisibleItemPosition == 0 && -headerViewHeight < paddingTop) { 181 if (paddingTop > 0 && currentState == DOWN_PULL_REFRESH) { // 完全显示了. 182 Log.i(TAG, "松开刷新"); 183 currentState = RELEASE_REFRESH; 184 refreshHeaderView(); 185 } else if (paddingTop < 0 && currentState == RELEASE_REFRESH) { // 没有显示完全 186 Log.i(TAG, "下拉刷新"); 187 currentState = DOWN_PULL_REFRESH; 188 refreshHeaderView(); 189 } 190 // 下拉头布局 191 headerView.setPadding(0, paddingTop, 0, 0); 192 return true; 193 } 194 break; 195 case MotionEvent.ACTION_UP: 196 // 判断当前的状态是松开刷新还是下拉刷新 197 if (currentState == RELEASE_REFRESH) { 198 Log.i(TAG, "刷新数据."); 199 // 把头布局设置为完全显示状态 200 headerView.setPadding(0, 0, 0, 0); 201 // 进入到正在刷新中状态 202 currentState = REFRESHING; 203 refreshHeaderView(); 204 if (onRefreshListener != null) { 205 onRefreshListener.onDownPullRefresh(); // 调用使用者的监听方法 206 } 207 } else if (currentState == DOWN_PULL_REFRESH) { 208 // 隐藏头布局 209 headerView.setPadding(0, -headerViewHeight, 0, 0); 210 } 211 break; 212 default: 213 break; 214 } 215 return super.onTouchEvent(ev); 216 } 217 218 219 /** 220 * 根据currentState刷新头布局的状态 221 */ 222 private void refreshHeaderView() { 223 switch (currentState) { 224 case DOWN_PULL_REFRESH: // 下拉刷新状态 225 tvState.setText("下拉刷新"); 226 ivArrow.startAnimation(downAnimation); // 执行向下旋转 227 break; 228 case RELEASE_REFRESH: // 松开刷新状态 229 tvState.setText("松开刷新"); 230 ivArrow.startAnimation(upAnimation); // 执行向上旋转 231 break; 232 case REFRESHING: // 正在刷新中状态 233 ivArrow.clearAnimation(); 234 ivArrow.setVisibility(View.GONE); 235 mProgressBar.setVisibility(View.VISIBLE); 236 tvState.setText("正在刷新中..."); 237 break; 238 default: 239 break; 240 } 241 } 242 243 /** 244 * 当滚动状态改变时回调 245 */ 246 @Override 247 public void onScrollStateChanged(AbsListView view, int scrollState) { 248 if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) { 249 // 判断当前是否已经到了底部 250 if (isScrollToBottom && !isLoadingMore) { 251 isLoadingMore = true; 252 // 当前到底部 253 Log.i(TAG, "加载更多数据"); 254 footerView.setPadding(0, 0, 0, 0); 255 this.setSelection(this.getCount()); 256 257 if (onRefreshListener != null) { 258 onRefreshListener.onLoadingMore(); 259 } 260 } 261 } 262 } 263 264 /** 265 * 当滚动时调用 266 * 267 * @param firstVisibleItem 当前屏幕显示在顶部的item的position 268 * @param visibleItemCount 当前屏幕显示了多少个条目的总数 269 * @param totalItemCount ListView的总条目的总数 270 */ 271 @Override 272 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 273 firstVisibleItemPosition = firstVisibleItem; 274 if (getLastVisiblePosition() == (totalItemCount - 1)) { 275 isScrollToBottom = true; 276 } else { 277 isScrollToBottom = false; 278 } 279 } 280 281 /** 282 * 隐藏头布局 283 */ 284 public void hideHeaderView() { 285 headerView.setPadding(0, -headerViewHeight, 0, 0); 286 ivArrow.setVisibility(View.VISIBLE); 287 mProgressBar.setVisibility(View.GONE); 288 tvState.setText("下拉刷新"); 289 tvLastUpdateTime.setText("最后刷新时间: " + getLastUpdateTime()); 290 currentState = DOWN_PULL_REFRESH; 291 } 292 293 294 /** 295 * 隐藏脚布局 296 */ 297 public void hideFooterView() { 298 footerView.setPadding(0, -footerViewHeight, 0, 0); 299 isLoadingMore = false; 300 } 301 302 /** 303 * 设置刷新监听事件 304 * 305 * @param onRefreshListener 306 */ 307 public void setOnRefreshListener(OnRefreshListener onRefreshListener) { 308 this.onRefreshListener = onRefreshListener; 309 } 310 311 312 public interface OnRefreshListener { 313 /** 314 * 下拉刷新 315 */ 316 void onDownPullRefresh(); 317 318 /** 319 * 上拉加载更多 320 */ 321 void onLoadingMore(); 322 } 323 }
为什么还要自己实现下拉刷新。
SwipeRefreshLayout要求的sdk版本有点高,项目得兼容低版本的手机
@不打伞的可燃冰:
这个是在android.support.v4包里面的哦。