整体来说逻辑上比较简单,遇到过一个小问题,就是 如果当前类不去拦截事件传递,那么自身的 onTouch方法是接收不到down事件的,所以 down事件的坐标来源可以从 dispath分发来,也可以 拦截方法中拿到。
public abstract class RefreshScrollView extends ScrollView {
protected static final String TAG = "生命周期";
protected Context mContext;
private Scroller scroller;
private LinearLayout mainView; //主布局--包含头布局和子类实现布局
private boolean loadOnce; //只执行一次
private LinearLayout headView; //下拉头
private TextView headTv; //下拉头文字
private int height; //下拉头高度,值为负数
private MarginLayoutParams headViewLayoutParams; //下拉头布局参数
private final static int REFRESH_NORMAL = 0; //默认状态
private final static int REFRESH_PULL_DOWN = 1; //正在下拉状态
private final static int REFRESH_RELEASE = 2; //释放刷新状态
private final static int REFRESH_ING = 3; //正在刷新状态
private final static int REFRESH_SUCCESS = 4; //刷新成功状态
private final static int REFRESH_ERROR = 5; //刷新失败状态
private int refreshCur = REFRESH_NORMAL; //当前状态
private static final int DEMP = 2; //阻尼系数
protected boolean refreshAble = true; //是否允许进行下拉刷新
private static final int FLAG = 101010; //刷新成功时,Msg.what = 101010
private int lastY;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FLAG:
scroller.startScroll(0, 0, 0, height, 2000);
invalidate();
refreshCur = REFRESH_NORMAL;
break;
}
}
};
public RefreshScrollView(Context context) {
super(context);
mContext = context;
scroller = new Scroller(context);
setOverScrollMode(View.OVER_SCROLL_NEVER);//魅族下拉悬停
initView();
}
/**
* 初始化布局文件
*/
private void initView() {
mainView = (LinearLayout) inflate(mContext, R.layout.market_refresh_scrollview_mainview, null);
mainView.addView(createView());
addView(mainView);
}
/**
* 布局隐藏下拉头
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed && !loadOnce) {
loadOnce = true;
headView = (LinearLayout) mainView.getChildAt(0);
headTv = (TextView) mainView.findViewById(R.id.textView);
height = -headView.getHeight();
headViewLayoutParams = (MarginLayoutParams) headView.getLayoutParams();
headViewLayoutParams.topMargin = height;
headView.setLayoutParams(headViewLayoutParams);
}
}
/**
* 下拉头显示逻辑
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = (int) ev.getY();
Log.i("Y值", "onInterceptTouchEvent: down时 lastY " + lastY);
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
int moveY = (int) (ev.getY() - lastY); //每次移动所滑动的距离
lastY = (int) ev.getY();
Log.i("Y值", "onTouchEvent: move时 moveY " + moveY);
Log.i("Y值", "onTouchEvent: move时 lastY" + lastY);
int marginTop = moveY / DEMP + headView.getTop();
Log.i("Y值", "onTouchEvent: move时 marginTop" + marginTop);
Log.i("Y值", "onTouchEvent: move时 height" + height);
//正在刷新、刷新成功、失败、Scroller动画执行时禁止下拉,所以把down时的结束动画隐藏掉
if (getScrollY() == 0 && refreshCur != REFRESH_ING && refreshCur != REFRESH_SUCCESS && refreshCur != REFRESH_ERROR && !scroller.computeScrollOffset() && marginTop > height) {
if (refreshAble) {
pullDownHeadView(marginTop);
return true;
}
}
break;
default:
if (refreshCur == REFRESH_RELEASE) {
//TODO 请求网络
refreshingHeadView();
requestNet();
}
if (refreshCur == REFRESH_PULL_DOWN) {
//TODO 隐藏下拉头
hideHeadView();
}
}
return super.onTouchEvent(ev);
}
/**
* 隐藏下拉
*/
protected void hideHeadView() {
refreshCur = REFRESH_NORMAL;
headTv.setText("下拉刷新");
headViewLayoutParams.topMargin = height;
headView.setLayoutParams(headViewLayoutParams);
}
/**
* 下拉刷新
*/
protected void pullDownHeadView(int marginTop) {
headViewLayoutParams.topMargin = marginTop;
headView.setLayoutParams(headViewLayoutParams);
if (marginTop > 0) {
refreshCur = REFRESH_RELEASE;
headTv.setText("释放刷新");
} else {
refreshCur = REFRESH_PULL_DOWN;
headTv.setText("下拉刷新");
}
}
/**
* 正在刷新
*/
protected void refreshingHeadView() {
refreshCur = REFRESH_ING;
headTv.setText("正在刷新");
headViewLayoutParams.topMargin = 0;
headView.setLayoutParams(headViewLayoutParams);
}
/**
* 刷新成功
* 由于在子类handler中需要调用此函数,需要判断是由下拉触发的此刷新成功
* 如果是onResume进行的网络请求,则不进行刷新成功动画
*/
protected void successHeadView() {
if (refreshCur == REFRESH_ING) {
refreshCur = REFRESH_SUCCESS;
headTv.setText("刷新成功");
handler.sendEmptyMessageDelayed(FLAG, 1000);
}
}
/**
* 刷新失败
*/
protected void errorHeadView() {
if (refreshCur == REFRESH_ING) {
refreshCur = REFRESH_ERROR;
headTv.setText("刷新失败");
handler.sendEmptyMessageDelayed(101010, 1000);
}
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
int marginTop = scroller.getCurrY();
headViewLayoutParams.topMargin = marginTop;
headView.setLayoutParams(headViewLayoutParams);
invalidate();
}
super.computeScroll();
}
/**************子类实现函数****************/
/**
* 子类具体View
*/
public abstract View createView();
/**
* 刷新时,请求网络
*/
protected abstract void requestNet();
/**
* 指示器文字
*/
public abstract CharSequence getTabTitle();
/**
* 项目中此方法用于开始网络请求
*/
protected abstract void onResume();
/**
* 项目中此方法用于暂停网络请求
*/
protected abstract void onPause();
/**
* 黑白版颜色
*/
protected abstract void changeDarkAndLightStyle();