实现效果如下:
代码:
关键方法: overScrollBy 当列表被滑动到两端尽头的时候被调用。
public class ParallaxListView extends ListView {
private ImageView parallaxImageView;
private int maxHeight;
private int originH;
public ParallaxListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ParallaxListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ParallaxListView(Context context) {
super(context);
}
// 允许从外部传递视差效果的控件进来
public void setParallaxImageView(ImageView parallaxImageView) {
this.parallaxImageView = parallaxImageView;
Drawable drawable = parallaxImageView.getDrawable();
maxHeight = drawable.getIntrinsicHeight();// 获取图片的最大高度
originH = parallaxImageView.getHeight();// 获取图片的起始高度
System.out.println("ParallaxListView.setParallaxImageView,originH=" + originH);
}
@Override
// 当列表被滑动到两端尽头的时候被调用
// deltaY 两次滑动间的变化大小
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,
int scrollY, int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
System.out.println("deltaY=" + deltaY + ";scrollY=" + scrollY + ";scrollRangeY=" + scrollRangeY + ";maxOverScrollY=" + maxOverScrollY + ";isTouchEvent=" + isTouchEvent);
if (deltaY < 0 && isTouchEvent) {
int newHeight = parallaxImageView.getHeight() + Math.abs(deltaY / 2);
if (newHeight < maxHeight) {
parallaxImageView.getLayoutParams().height = newHeight;
parallaxImageView.requestLayout();
}
}
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
// 将图片从当前高度弹回最初的高度
final int currentH = parallaxImageView.getHeight();
// 动态生成一个值的变化.依据fraction动态生成 [0,100]范围的值。
ValueAnimator animator = ValueAnimator.ofFloat(0, 100);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator value) {
System.out.println("ParallaxListView.onAnimationUpdate,time=" + value.getCurrentPlayTime() + ";Fraction=" + value.getAnimatedFraction() + ";value=" + value.getAnimatedValue());
int newHeight = evaluate(value.getAnimatedFraction(), currentH, originH);
parallaxImageView.getLayoutParams().height = newHeight;
parallaxImageView.requestLayout();
}
});
animator.setDuration(200);
animator.setInterpolator(new OvershootInterpolator(4));
animator.start();
break;
default:
break;
}
return super.onTouchEvent(ev);// 一定要使用super来返回,因为列表的滚动要由ListView处理
}
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int) (startInt + fraction * (endValue - startInt));
}
}
当头部完成填充,可以正确获取imageView的高度时,把imageView设置给listView
header = View.inflate(this, R.layout.header, null);
parallaxImageView = (ImageView) header.findViewById(R.id.iv_header);
// 当布局完成之后才能获取到控件高度
header.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
header.getViewTreeObserver().removeGlobalOnLayoutListener(this);
System.out.println("MainActivity.onGlobalLayout,");
listView.setParallaxImageView(parallaxImageView);// 设置要被视差效果处理的控件
}
});
listView = (ParallaxListView) findViewById(R.id.listview);
listView.addHeaderView(header);// 将视差内容设置列表头部