概念介绍
1、onInterceptTouchEvent()是用于处理事件(重点onInterceptTouchEvent这个事件是从父控件开始往子控件传的,直到有拦截或者到没有这个事件的view,然后就往回从子到父控件,这次是onTouch的)(类似于预处理,当然也可以不处理)并改变事件的传递方向,也就是决定是否允许Touch事件继续向下(子控件)传递,一但返回True(代表事件在当前的viewGroup中会被处理),则向下传递之路被截断(所有子控件将没有机会参与Touch事件),同时把事件传递给当前的控件的onTouchEvent()处理;返回false,则把事件交给子控件的onInterceptTouchEvent()
2、onTouchEvent()用于处理事件(重点onTouch这个事件是从子控件回传到父控件的,一层层向下传),返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还允许Touch事件继续向上(父控件)传递。返回false,则向上传递给父控件,详细一点就是这个touch事件就给了父控件,那么后面的up事件就是到这里touch触发,不会在传给它的子控件。如果父控件依然是false,那touch的处理就给到父控件的父控件,那么up的事件处理都在父控件的父控件,不会触发下面的。
思路:
监听手势,记录下拉的距离,将滑动的值(可以几分之一)+头部原始值 从新付给头部参数
先看效果
详细步骤:
1.onInterceptTouchEvent部分,当手指按下记录当前的坐标值,返回false 意思是将事件传给子view,当开始拉动时,拦截事件,事件不传递给子view,记录最新的坐标值 mLastMotionY = y; 当手指离开屏幕时,取消拦截,将事件传递给子view
mLastMotionX = x;
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (!isPullToZoomEnabled() || isHideHeader()) {
return false;
}
final int action = event.getAction();
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mIsBeingDragged = false;
return false;
}
if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) {
return true;
}
switch (action) {
case MotionEvent.ACTION_MOVE: {
if (isReadyForPullStart()) {
final float y = event.getY(), x = event.getX();
final float diff, oppositeDiff, absDiff;
// We need to use the correct values, based on scroll
// direction
diff = y - mLastMotionY;
oppositeDiff = x - mLastMotionX;
absDiff = Math.abs(diff);
if (absDiff > mTouchSlop && absDiff > Math.abs(oppositeDiff)) {
if (diff >= 1f && isReadyForPullStart()) {
mLastMotionY = y;
mLastMotionX = x;
mIsBeingDragged = true;
}
}
}
break;
}
case MotionEvent.ACTION_DOWN: {
if (isReadyForPullStart()) {
mLastMotionY = mInitialMotionY = event.getY();
mLastMotionX = mInitialMotionX = event.getX();
mIsBeingDragged = false;
}
break;
}
}
return mIsBeingDragged;
}
2.onTouchEvent 部分,手指按下记录初始坐标值(并消耗事件),手指滑动记录最新的坐标值,同时调用pullEvent()函数来刷新界面
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
if (!isPullToZoomEnabled() || isHideHeader()) {
return false;
}
if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE: {
if (mIsBeingDragged) {
mLastMotionY = event.getY();
mLastMotionX = event.getX();
pullEvent();
isZooming = true;
return true;
}
break;
}
case MotionEvent.ACTION_DOWN: {
if (isReadyForPullStart()) {
mLastMotionY = mInitialMotionY = event.getY();
mLastMotionX = mInitialMotionX = event.getX();
return true;
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
if (mIsBeingDragged) {
mIsBeingDragged = false;
// If we're already refreshing, just scroll back to the top
if (isZooming()) {
smoothScrollToTop();
if (onPullZoomListener != null) {
onPullZoomListener.onPullZoomEnd();
}
isZooming = false;
return true;
}
return true;
}
break;
}
}
return false;
}
取竖直方向滑动的距离的1/2,传递给相头部和需要放大的图片 重新设置值
private void pullEvent() {
final int newScrollValue;
final float initialMotionValue, lastMotionValue;
initialMotionValue = mInitialMotionY;
lastMotionValue = mLastMotionY;
newScrollValue = Math.round(Math.min(initialMotionValue - lastMotionValue, 0) / FRICTION);
pullHeaderToZoom(newScrollValue);
if (onPullZoomListener != null) {
onPullZoomListener.onPullZooming(newScrollValue);
}
}
头部设置新的高度,同时图片同上设置新的高度
@Override
protected void pullHeaderToZoom(int newScrollValue) {
Log.d(TAG, "pullHeaderToZoom --> newScrollValue = " + newScrollValue);
Log.d(TAG, "pullHeaderToZoom --> mHeaderHeight = " + mHeaderHeight);
if (mScalingRunnable != null && !mScalingRunnable.isFinished()) {
mScalingRunnable.abortAnimation();
}
ViewGroup.LayoutParams localLayoutParams = mHeaderContainer.getLayoutParams();
localLayoutParams.height = Math.abs(newScrollValue) + mHeaderHeight;
mHeaderContainer.setLayoutParams(localLayoutParams);
if (isCustomHeaderHeight) {
ViewGroup.LayoutParams zoomLayoutParams = mZoomView.getLayoutParams();
zoomLayoutParams.height = Math.abs(newScrollValue) + mHeaderHeight;
mZoomView.setLayoutParams(zoomLayoutParams);
}
}
大概的思路如上