这次就不上图了,例子太多太多了,想必大家都见过.这个功能的实现,简直是开发者必备的.
我也不过多介绍了,网上详细介绍的博客太多太多了,若想深入了解,请参考网上其他博文.
在这里,我只是按照自己的理解,模拟实现了一个,顺便代码贡献出来.
我对之详细标明的注释,想必如果不懂的同学们,看注释也应该明白,前提是,你要耐心看,因为代码有点多,但是我整理过了,还算清晰.
详细代码:
package com.jj.drag;
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.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
/***
* 自定义拖拉ListView
*
* @author zhangjia
*
*/
public class DragListView extends ListView implements OnScrollListener,
OnClickListener {
// 拖拉ListView枚举所有状态
private enum DListViewState {
LV_NORMAL, // 普通状态
LV_PULL_REFRESH, // 下拉状态(为超过mHeadViewHeight)
LV_RELEASE_REFRESH, // 松开可刷新状态(超过mHeadViewHeight)
LV_LOADING;// 加载状态
}
// 点击加载更多枚举所有状态
private enum DListViewLoadingMore {
LV_NORMAL, // 普通状态
LV_LOADING, // 加载状态
LV_OVER; // 结束状态
}
private View mHeadView;// 头部headView
private TextView mRefreshTextview; // 刷新msg(mHeadView)
private TextView mLastUpdateTextView;// 更新事件(mHeadView)
private ImageView mArrowImageView;// 下拉图标(mHeadView)
private ProgressBar mHeadProgressBar;// 刷新进度体(mHeadView)
private int mHeadViewWidth; // headView的宽(mHeadView)
private int mHeadViewHeight;// headView的高(mHeadView)
private View mFootView;// 尾部mFootView
private View mLoadMoreView;// mFootView 的view(mFootView)
private TextView mLoadMoreTextView;// 加载更多.(mFootView)
private View mLoadingView;// 加载中...View(mFootView)
private Animation animation, reverseAnimation;// 旋转动画,旋转动画之后旋转动画.
private int mFirstItemIndex = -1;// 当前视图能看到的第一个项的索引
// 用于保证startY的值在一个完整的touch事件中只被记录一次
private boolean mIsRecord = false;
private int mStartY, mMoveY;// 按下是的y坐标,move时的y坐标
private DListViewState mlistViewState = DListViewState.LV_NORMAL;// 拖拉状态.(自定义枚举)
private DListViewLoadingMore loadingMoreState = DListViewLoadingMore.LV_NORMAL;// 加载更多默认状态.
private final static int RATIO = 2;// 手势下拉距离比.
private boolean mBack = false;// headView是否返回.
private OnRefreshLoadingMoreListener onRefreshLoadingMoreListener;// 下拉刷新接口(自定义)
private boolean isScroller = true;// 是否屏蔽ListView滑动。
public DragListView(Context context) {
super(context, null);
initDragListView(context);
}
public DragListView(Context context, AttributeSet attrs) {
super(context, attrs);
initDragListView(context);
}
// 注入下拉刷新接口
public void setOnRefreshListener(
OnRefreshLoadingMoreListener onRefreshLoadingMoreListener) {
this.onRefreshLoadingMoreListener = onRefreshLoadingMoreListener;
}
/***
* 初始化ListView
*/
public void initDragListView(Context context) {
String time = "1994.12.05";// 更新时间
initHeadView(context, time);// 初始化该head.
initLoadMoreView(context);// 初始化footer
setOnScrollListener(this);// ListView滚动监听
}
/***
* 初始话头部HeadView
*
* @param context
* 上下文
* @param time
* 上次更新时间
*/
public void initHeadView(Context context, String time) {
mHeadView = LayoutInflater.from(context).inflate(R.layout.head, null);
mArrowImageView = (ImageView) mHeadView
.findViewById(R.id.head_arrowImageView);
mArrowImageView.setMinimumWidth(60);
mHeadProgressBar = (ProgressBar) mHeadView
.findViewById(R.id.head_progressBar);
mRefreshTextview = (TextView) mHeadView
.findViewById(R.id.head_tipsTextView);
mLastUpdateTextView = (TextView) mHeadView
.findViewById(R.id.head_lastUpdatedTextView);
// 显示更新事件
mLastUpdateTextView.setText("最近更新:" + time);
measureView(mHeadView);
// 获取宽和高
mHeadViewWidth = mHeadView.getMeasuredWidth();
mHeadViewHeight = mHeadView.getMeasuredHeight();
addHeaderView(mHeadView, null, false);// 将初始好的ListView add进拖拽ListView
// 在这里我们要将此headView设置到顶部不显示位置.
mHeadView.setPadding(0, -1 * mHeadViewHeight, 0, 0);
initAnimation();// 初始化动画
}
/***
* 初始化底部加载更多控件
*/
private void initLoadMoreView(Context context) {
mFootView = LayoutInflater.from(context).inflate(R.layout.footer, null);
mLoadMoreView = mFootView.findViewById(R.id.load_more_view);
mLoadMoreTextView = (TextView) mFootView
.findViewById(R.id.load_more_tv);
mLoadingView = (LinearLayout) mFootView
.findViewById(R.id.loading_layout);
mLoadMoreView.setOnClickListener(this);
addFooterView(mFootView);
}
/***
* 初始化动画
*/
private void initAnimation() {
// 旋转动画
animation = new RotateAnimation(0, -180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
animation.setInterpolator(new LinearInterpolator());// 匀速
animation.setDuration(250);
animation.setFillAfter(true);// 停留在最后状态.
// 反向旋转动画
reverseAnimation = new RotateAnimation(-180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseAnimation.setInterpolator(new LinearInterpolator());
reverseAnimation.setDuration(250);
reverseAnimation.setFillAfter(true);
}
/***
* 作用:测量 headView的宽和高.
*
* @param child
*/
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);
}
/***
* touch 事件监听
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
// 按下
case MotionEvent.ACTION_DOWN:
doActionDown(ev);
break;
// 移动
case MotionEvent.ACTION_MOVE:
doActionMove(ev);
break;
// 抬起
case MotionEvent.ACTION_UP:
doActionUp(ev);
break;
default:
break;
}
/***
* 如果是Lis