原理:
addHeaderView里做的事:
1.测量出header的宽高,调用了measureView方法
2.设置LayoutParams,宽:MATCH_PARENT,高:10
3.设置topMargin的值为负的header的高度,即将header隐藏在屏幕最上方
onInterceptTouchEvent:
如果滑动距离为零,让onInterceptTouchEvent处理。屏幕没有滑动效果。
onTouchEvent:
如果滑动距离大于零,让onTouchEvent处理。在滑动过程中不断的计算header的topMargin,让屏幕有滑动效果。
代码:
/**
* android回弹效果 by haidaye
*/
public class HaidayeView extends LinearLayout {
private int mLastMotionY;
/**
* 头部view
*/
private View mHeaderView;
private LayoutInflater mInflater;
private ScrollView mScrollView;
/**
* 头部view的高
*/
private int mHeaderViewHeight;
public HaidayeView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public HaidayeView(Context context) {
super(context);
init();
}
private void init() {
// Load all of the animations we need in code rather than through XML
mInflater = LayoutInflater.from(getContext());
// header view 在此添加,保证是第一个添加到linearlayout的最上端
addHeaderView();
}
private void addHeaderView() {
// header view
mHeaderView = mInflater.inflate(R.layout.header, this, false);
measureView(mHeaderView);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
mHeaderViewHeight);
// 设置topMargin的值为负的header View高度,即将其隐藏在最上方
params.topMargin = -(mHeaderViewHeight);
addView(mHeaderView, params);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
initContentAdapterView();
}
private void initContentAdapterView() {
mScrollView = (ScrollView) getChildAt(1);
}
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);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
int y = (int) e.getRawY();
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
// 首先拦截down事件,记录y坐标
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
// deltaY > 0 是向下运动,< 0是向上运动
int deltaY = y - mLastMotionY;
if (isRefreshViewScroll(deltaY)) {
return true;
}
mLastMotionY = y;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
}
return false;
}
/*
* 如果在onInterceptTouchEvent()方法中没有拦截(即onInterceptTouchEvent()方法中 return
* false)则由PullToRefreshView 的子View来处理;否则由下面的方法来处理(即由HaidayeView自己来处理)
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// onInterceptTouchEvent已经记录
// mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
int deltaY = y - mLastMotionY;
headerPrepareToRefresh(deltaY);
mLastMotionY = y;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
int topMargin = getHeaderTopMargin();
setHeaderTopMargin(-mHeaderViewHeight);
break;
case MotionEvent.ACTION_POINTER_DOWN://设置多点触控
this.mLastMotionY = y;
break;
}
return super.onTouchEvent(event);
}
/**
* 是否应该到了父View,即PullToRefreshView滑动
*
* @param deltaY , deltaY > 0 是向下运动,< 0是向上运动
* @return
*/
private boolean isRefreshViewScroll(int deltaY) {
// 对于ScrollView
if (mScrollView != null) {
// 子scroll view滑动到最顶端
View child = mScrollView.getChildAt(0);
if (deltaY > 0 && mScrollView.getScrollY() == 0) {
return true;
} else if (deltaY < 0
&& child.getMeasuredHeight() <= getHeight()
+ mScrollView.getScrollY()) {
return true;
}
}
return false;
}
/**
* header 准备刷新,手指移动过程,还没有释放
*
* @param deltaY ,手指滑动的距离
*/
private void headerPrepareToRefresh(int deltaY) {
int newTopMargin = changingHeaderViewTopMargin(deltaY);
}
private int changingHeaderViewTopMargin(int deltaY) {
LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
float newTopMargin = params.topMargin + deltaY * 0.3f;
params.topMargin = (int) newTopMargin;
mHeaderView.setLayoutParams(params);
invalidate();
return params.topMargin;
}
/**
* 设置header view 的topMargin的值
*/
private void setHeaderTopMargin(int topMargin) {
LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
params.topMargin = topMargin;
mHeaderView.setLayoutParams(params);
invalidate();
}
private int getHeaderTopMargin() {
LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
return params.topMargin;
}
}