我大部分参考了:http://blog.youkuaiyun.com/weidi1989/article/details/7909983里面的代码。
但是他里面的那个ListView类写的比较复杂,逻辑有点混乱,特别是在OnTouchEvent有很多不必要的逻辑,增加了理解代码的难度。
下面是我自己改造后的代码,供参考。。。。
package hh.HH;
import hh.apis.R;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.Inflater;
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.View.MeasureSpec;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
public class Custom_ListView_PullRefresh extends ListView implements OnScrollListener {
private final static String DEBUG_TAG = "java-hh";
private final static String DEBUG_TAG2 = "java-hh2";
public enum LOADING_STATE {
PULL_DOWN_TO_REFRESH,// 下拉刷新状态
RELEASE_TO_REFRESH,// 松开刷新状态
REFRESHING,// 正在刷新状态
LOADING,// 正在加载数据状态
DONE// 已经加载完毕状态
}
// UI Controls
private LinearLayout mHeadView;
private ProgressBar mProgressBar;// 刷新进度
private ImageView mArrowImageView;// 箭头的图片
private TextView mTipsTextview;// 提示信息“下拉刷新”的TextView
private TextView mLastUpdatedTextView;// 上次更新时间的TextView
// flag
private final int RATIO = 3;// 实际的padding的距离与界面上偏移距离的比例
private int mHeadViewWidth, mHeadViewHeight;
private int mFirstVisibleItemIndex;
private boolean mIsRecord;
private float mStartY;
private boolean mIsNeedAnimation = true;
private LOADING_STATE mState;
private RotateAnimation mAnimation;
private RotateAnimation mReverseAnimation;
// notify interface
private OnRefreshListener mOnRefreshListener;
////////////////////////////////////////////////////////////////////////////////////////
public Custom_ListView_PullRefresh(Context context) {
super(context);
// TODO Auto-generated constructor stub
initListView(context);
}
public Custom_ListView_PullRefresh(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
initListView(context);
}
public Custom_ListView_PullRefresh(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
initListView(context);
}
//////////////////////////////////////////////////////////////////////////////////
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
String strTest = String.format("FirstItem: %d," +
"VisibleItem: %d," +
"Total: %d", firstVisibleItem, visibleItemCount, totalItemCount);
//Log.d(DEBUG_TAG, strTest);
mFirstVisibleItemIndex = firstVisibleItem;// ListView第一个索引值为ListView数据中第一个可见项
}
//////////////////////////////////////////////////////////////////////////////////
@Override
public boolean onTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: { // 向下
if( mFirstVisibleItemIndex == 0 && !mIsRecord ) {
mIsRecord = true;
mStartY = ev.getY();
String strTest = String.format("在down时候记录当前位置 -- Y: %f", mStartY);
Log.v(DEBUG_TAG, strTest);
}
}
break;
case MotionEvent.ACTION_MOVE: {
float tempY = ev.getY();
String strTest = String.format("在move时候记录当前位置 -- Y: %f", tempY);
Log.v(DEBUG_TAG, strTest);
if( mFirstVisibleItemIndex == 0 && !mIsRecord ) {
mIsRecord = true;
mStartY = tempY;
Log.v(DEBUG_TAG, "move先记录mStartY");
}
if( mState != LOADING_STATE.REFRESHING ) {
float yDelta = (tempY - mStartY) / RATIO;
if( mIsRecord && yDelta > 0 ) {
switch(mState) {
case DONE: {
mState = LOADING_STATE.PULL_DOWN_TO_REFRESH;
}
break;
case PULL_DOWN_TO_REFRESH: {
mHeadView.setPadding(0, (int)(yDelta - mHeadViewHeight), 0, 0);
setSelection(0);
if( yDelta > mHeadViewHeight ) {
mState = LOADING_STATE.RELEASE_TO_REFRESH;
mIsNeedAnimation = true;
}
}
break;
case RELEASE_TO_REFRESH: {
setSelection(0);
mHeadView.setPadding(0, (int)(yDelta - mHeadViewHeight), 0, 0);
if( yDelta <= mHeadViewHeight ) {
String strTest2 = String.format("CurrentY: %f, yDelta: %f, HeadViewHeight: %d",
tempY, yDelta, mHeadViewHeight);
Log.d(DEBUG_TAG, strTest2);
mState = LOADING_STATE.PULL_DOWN_TO_REFRESH;
mIsNeedAnimation = true;
}
}
break;
}
changeHeaderViewByState();
}
}
}
break;
case MotionEvent.ACTION_UP: {
mHeadView.setPadding(0, -mHeadViewHeight, 0, 0);
setSelection(0);
switch(mState) {
case PULL_DOWN_TO_REFRESH: {
mState = LOADING_STATE.DONE;
}
break;
case RELEASE_TO_REFRESH: {
mState = LOADING_STATE.REFRESHING;
if( mOnRefreshListener != null ) {
mOnRefreshListener.onRefresh();
}
}
break;
}
changeHeaderViewByState();
mIsRecord = false;
}
break;
}
return super.onTouchEvent(ev);
}
//////////////////////////////////////////////////////////////////////////////////////////
private void initListView(Context context) {
setOnScrollListener(this);
LayoutInflater inflater = LayoutInflater.from(context);
mHeadView = (LinearLayout)inflater.inflate(R.layout.hh4_custom_listview_pullrefresh_head, null);
mArrowImageView = (ImageView) mHeadView.findViewById(R.id.head_arrowImageView);// 从头部的View获取箭头图片
mArrowImageView.setMinimumWidth(70);
mArrowImageView.setMinimumHeight(50);
mProgressBar = (ProgressBar) mHeadView.findViewById(R.id.head_progressBar);// 获取刷新进度条
mTipsTextview = (TextView) mHeadView.findViewById(R.id.head_tipsTextView);// 提示信息的TextView
mLastUpdatedTextView = (TextView) mHeadView.findViewById(R.id.head_lastUpdatedTextView);// 最后刷新时间的TextView
measureView(mHeadView);
mHeadViewHeight = mHeadView.getMeasuredHeight();// 得到mHeadView的原始高度
mHeadViewWidth = mHeadView.getMeasuredWidth();
addHeaderView(mHeadView, null, false);// 加到ListView的头部view,ListView组件提供了两个很实用的功能,那就是可以在顶部和底部添加自定义的视图
mHeadView.setPadding(0, -mHeadViewHeight, 0, 0);// 设置内容的内部偏移量
mHeadView.invalidate();
// 箭头向下动画
mAnimation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mAnimation.setInterpolator(new LinearInterpolator());
mAnimation.setDuration(250);
mAnimation.setFillAfter(true);
// 逆向箭头动画
mReverseAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mReverseAnimation.setInterpolator(new LinearInterpolator());
mReverseAnimation.setDuration(200);
mReverseAnimation.setFillAfter(true);
mState = LOADING_STATE.DONE;
mIsRecord = false;
}
private void changeHeaderViewByState() {
switch( mState ) {
case PULL_DOWN_TO_REFRESH: {
mProgressBar.setVisibility(View.GONE);// 移除进度条
mArrowImageView.setVisibility(View.VISIBLE);// 箭头图片可见
mTipsTextview.setText("下拉刷新");
if( mIsNeedAnimation ) {
mIsNeedAnimation = false;
mArrowImageView.clearAnimation();
mArrowImageView.startAnimation(mReverseAnimation);
}
}
break;
case RELEASE_TO_REFRESH: {
mProgressBar.setVisibility(View.GONE);
mArrowImageView.setVisibility(View.VISIBLE);
mTipsTextview.setText("松开刷新");
if( mIsNeedAnimation ) {
mIsNeedAnimation = false;
mArrowImageView.clearAnimation();
mArrowImageView.startAnimation(mAnimation);
}
//Log.v(DEBUG_TAG, "当前状态,松开刷新");
}
break;
case REFRESHING: {
mHeadView.setPadding(0, 0, 0, 0);// 无内部偏移
mProgressBar.setVisibility(View.VISIBLE);// 进度条可见
mArrowImageView.clearAnimation();// 先清除动画
mArrowImageView.setVisibility(View.GONE);// 再移除箭头动画
mTipsTextview.setText("正在刷新...");// 提示信息变成正在刷新...
mLastUpdatedTextView.setVisibility(View.VISIBLE);// 最后刷新时间可见
Log.v(DEBUG_TAG, "当前状态,正在刷新...");
}
break;
case DONE: { // 完成状态
mHeadView.setPadding(0, -mHeadViewHeight, 0, 0);// 无内部偏移
mProgressBar.setVisibility(View.GONE);
mArrowImageView.setVisibility(View.VISIBLE);
mArrowImageView.setImageResource(R.drawable.arrow_down);
mTipsTextview.setText("下拉刷新");
//Log.v(DEBUG_TAG, "当前状态,done");
}
break;
}
}
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
//////////////////////////////////////////////////
// 向外通知的接口
public interface OnRefreshListener {
public void onRefresh();
}
public void setOnRefreshListener(OnRefreshListener listener) {
mOnRefreshListener = listener;
}
// 刷新完成
public void onRefreshComplete() {
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
String date = format.format(new Date());
mLastUpdatedTextView.setText("最近更新:" + date);
mState = LOADING_STATE.DONE;
changeHeaderViewByState();
}
//////////////////////////////////////////////////
}
本文介绍了一种简化版的Pull-to-refresh ListView实现,通过减少不必要的逻辑和优化UI控件,提高了代码的可读性和易用性。该实现包括初始化ListView、监听滚动事件、处理触摸事件以及状态转换等功能。
1037

被折叠的 条评论
为什么被折叠?



