先来看下仿照QQ空间顶部图片过度下拉时,顶部图片放大回弹的效果,完整项目:https://github.com/buder-cp/CustomView/tree/master/buder_DN_view/buderdn20
业务逻辑包括:顶部图片可以下拉,当过度下拉时会有顶部图片放大的效果,在松手时会有顶部图片回弹效果。
我们看下大致看下需要重写哪些方法才能完成上面的需求。
- 首先肯定要有onTouchEvent,因为需要在手指按下去或者离开时处理业务逻辑;
- 这里我们继承的是ListView,我们在向下滑动时会触发ListView父类中的onScrollChanged方法,该方法是响应view内部滚动内容的滑动而调用,通常是在触发了scrollBy或者scrollTo后调用的,可以不用像上一篇自定义RecyclerView那样重写很多onTouchEvent、scrollBy滑动和内部item相互处理的细节,因为在ListView中已经实现好了。
- overScrollBy方法:以标准行为滚动视图,滚动到正常内容边界之外时会触发。意思就是在滑动到最大滑动距离后还继续向下滑动时触发
public boolean onTouchEvent(MotionEvent ev)
protected void onScrollChanged(int l, int t, int oldl, int oldt)
protected boolean overScrollBy(int deltaX, int deltaY, int scroll)
过度滑动时,改变顶部图片高度
根据业务逻辑,在上滑和下拉时需要改变顶部图片的高度:
/**
* 上滑下拉时,改变图片的高度
*/
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
Log.i(TAG, "overScrollBy: " + deltaY);
if (deltaY < 0) {
//- 下拉
mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY;
mImageView.requestLayout();
} else {
//+ 上拉
mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY;
mImageView.requestLayout();
}
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
手指抬起时,触发缩放动画:
//松手时触发缩放动画
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP) {
ResetAnimation resetAnimation = new ResetAnimation(mImageViewHeight);
resetAnimation.setInterpolator(new OvershootInterpolator());
resetAnimation.setDuration(700);
mImageView.startAnimation(resetAnimation);
}
return super.onTouchEvent(ev);
}
public class ResetAnimation extends Animation {
//需要偏移回去的高度
private int extraHeight;
private int currentHeight;
public ResetAnimation(int targetHeight) {
currentHeight = mImageView.getHeight();
extraHeight = mImageView.getHeight() - targetHeight;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mImageView.getLayoutParams().height = (int) (currentHeight - extraHeight * interpolatedTime);
mImageView.requestLayout();
super.applyTransformation(interpolatedTime, t);
}
}
QQHeaderScrollView整体代码如下:
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.OvershootInterpolator;
import android.view.animation.Transformation;
import android.widget.ImageView;
import android.widget.ListView;
public class QQHeaderScrollView extends ListView {
private static final String TAG = "david";
private ImageView mImageView;
private int mImageViewHeight;//初始高度
public void setZoomImageView(ImageView iv) {
mImageView = iv;
}
public QQHeaderScrollView(Context context) {
super(context);
}
public QQHeaderScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mImageViewHeight = context.getResources().getDimensionPixelSize(R.dimen.size_default_height);
}
public QQHeaderScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//松手时触发缩放动画
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if (action == MotionEvent.ACTION_UP) {
ResetAnimation resetAnimation = new ResetAnimation(mImageViewHeight);
resetAnimation.setInterpolator(new OvershootInterpolator());
resetAnimation.setDuration(700);
mImageView.startAnimation(resetAnimation);
}
return super.onTouchEvent(ev);
}
public class ResetAnimation extends Animation {
//需要偏移回去的高度
private int extraHeight;
private int currentHeight;
public ResetAnimation(int targetHeight) {
currentHeight = mImageView.getHeight();
extraHeight = mImageView.getHeight() - targetHeight;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mImageView.getLayoutParams().height = (int) (currentHeight - extraHeight * interpolatedTime);
mImageView.requestLayout();
super.applyTransformation(interpolatedTime, t);
}
}
/**
* 上滑下拉时,改变图片的高度
*/
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
Log.i(TAG, "overScrollBy: " + deltaY);
if (deltaY < 0) {
//- 下拉
mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY;
mImageView.requestLayout();
} else {
//+ 上拉
mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY;
mImageView.requestLayout();
}
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
// @Override
// protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// View header = (View) mImageView.getParent();
// Log.i(TAG, "onSizeChanged: " + header.getTop());
// //ListView会滑出去的高度(负数)
// int deltaY = header.getTop();
// //只有image的高度大于 原始的高度,那我们就缩小
// if (mImageView.getHeight() > mImageViewHeight) {
// mImageView.getLayoutParams().height = mImageView.getHeight() + deltaY;
// header.layout(header.getLeft(), 0, header.getRight(), header.getHeight());
// mImageView.requestLayout();
// }
// super.onSizeChanged(w, h, oldw, oldh);
// }
}
完整项目