1.概述
实习生进阶到项目部分会带他们做一个百思不得姐项目,那么个人主页就有类似于QQ空间下拉图片放大的效果,趁着现在还闲就实现一下效果:
2.实现
1. 效果分析
ScrollView和ListView都可以实现,关键要知道这个方法overScrollBy()这个方法是ListView,ScrollView滑动过头的时候调用,也可以说是当我们已经滑动到最上面然后向下拉的时候会调用。
2. 效果实现
2.1 覆盖overScrollBy()方法当deltaY<0的时候不断的改变图片的高度,当拉到最大的高度时开启一个放大的动画,下面请看代码:
public class ParallaxListView extends ListView {
private ImageView mImageView;
// 定义一个imageview的最大的拉伸的高度
private int mDrawableMaxHeight = -1;
// 定义ImageView 初始加载的高度
private int mImageViewHeight = -1;
// 默认的高度
private int mDefaultImageViewHeight = 0;
public ParallaxListView(Context context) {
this(context, null);
}
public ParallaxListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ParallaxListView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mDefaultImageViewHeight = (int) getResources().getDimension(
R.dimen.size_default_height);
}
/**
* 设置可拉伸的图片
*/
public void setParallaxImageView(ImageView iv) {
this.mImageView = iv;
mImageView.setScaleType(ScaleType.CENTER_CROP);
}
/**
* 设置缩放级别 -- 控制图片的最大拉伸度 在界面加载完毕的时候调用
*/
public void setZoomRatio(double zoomRatio) {
if (mImageViewHeight == -1) {
mImageViewHeight = mImageView.getHeight();
if (mImageViewHeight < 0) {
mImageViewHeight = mDefaultImageViewHeight;
}
mDrawableMaxHeight = (int) (zoomRatio*mImageViewHeight);
}
}
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,
int scrollY, int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
// ListView,ScrollView滑动过头的时候调用
// 不断的控制ImageView的高度
boolean isCollapse = resizeOverScrollBy(deltaX, deltaY, scrollX,
scrollY, scrollRangeX, scrollRangeY, maxOverScrollX,
maxOverScrollY, isTouchEvent);
// return true 下拉到某一个地方的时候不再往下拉
return isCollapse ? true : super.overScrollBy(deltaX, deltaY, scrollX,
scrollY, scrollRangeX, scrollRangeY, maxOverScrollX,
maxOverScrollY, isTouchEvent);
}
private boolean resizeOverScrollBy(int deltaX, int deltaY, int scrollX,
int scrollY, int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
// 下拉的过程当中,不断的控制ImageView的高度
/**
* deltaY 是在超出滑动的时候每秒滑动的距离 (- 往上拉 +往下拉) 大小根据用户滑动的速度决定的 一般滑动50~-50
*/
if (deltaY < 0) {
if(mDrawableMaxHeight != -1){
if(mImageView.getLayoutParams().height>=mDrawableMaxHeight){
// 当不能再往下拉的时候开启一个放大动画
mImageView.animate().scaleX(1.1f).scaleY(1.1f).setDuration(300).start();
return true;
}
}
mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY;
// 重新调整ImageView的高度
mImageView.requestLayout();
} else {
// 不松开往上拉的时候应该将图片的高度不断的减小
if (mImageView.getHeight() > mImageViewHeight) {
mImageView.getLayoutParams().height = mImageView.getHeight() - deltaY > mImageViewHeight ? mImageView
.getHeight() - deltaY
: mImageViewHeight;
mImageView.requestLayout();
return true;
}
}
return false;
}
}
2.2 当手指不松开往上滑动的时候,很大一部分想到的还是在overScrollBy()方法中写代码,但是该方法只是下拉滑动到头的时候调用,所以我们需要在onScrollChanged()里面做手脚:
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
// 监听ListView的滑动
// 如何控制图片减小的高度?---监听listView头部划出去的距离
View header = (View) mImageView.getParent();
// 头部划出去的距离 ---<0
if (header.getTop() < 0 && mImageView.getHeight() > mImageViewHeight) {// 大于初始的高度
mImageView.getLayoutParams().height = Math.max(mImageView.getHeight()
+ header.getTop(), mImageViewHeight);
// 调整ImageView所在的容器的高度
header.layout(header.getLeft(), 0, header.getRight(),
header.getHeight());
// 重新调整ImageView的高度
mImageView.requestLayout();
}
}
2.3最后当手指抬起的时候,需要覆盖onTouch()方法,判断手指抬起,执行自定义继承Animator回弹的动画:
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
// 手指松开--让拉伸的图片动画的减少高度
// 自定义动画
if (mImageViewHeight - 1 < mImageView.getHeight()) {
ResetAnimimation animation = new ResetAnimimation(mImageView,
mImageViewHeight);
animation.setDuration(300);
mImageView.startAnimation(animation);
mImageView.animate().scaleX(1.0f).scaleY(1.0f).setDuration(350).start();
}
}
return super.onTouchEvent(ev);
}
public class ResetAnimimation extends Animation {
int targetHeight;
int originalHeight;
int extraHeight;
View mView;
protected ResetAnimimation(View view, int targetHeight) {
// 图片动画的减小高度
this.mView = view;
// 动画执行之后的高度
this.targetHeight = targetHeight;
// 动画执行之前的高度
originalHeight = view.getHeight();
// 高度差
extraHeight = this.targetHeight - originalHeight;
}
@Override
protected void applyTransformation(float interpolatedTime,Transformation t) {
/** originalHeight ~~~~ targetHeight
* 0ms ~~~~ 300ms
* 150ms ---> originalHeight - extraHeight*1/2
* interpolatedTime 变化比例(0.0~1.0)
*/
int newHeight = (int) (targetHeight - extraHeight
* (1 - interpolatedTime));
mView.getLayoutParams().height = newHeight;
mView.requestLayout();
}
}
2.4 activity中的使用,如果是ListView那么需要给它添加 addHeaderView(View view),设置setParallaxImageView(ImageView iv),控制最大高度即可:
public class MainActivity extends Activity {
private ParallaxListView mPlv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPlv = (ParallaxListView) findViewById(R.id.parallax_listview);
View header = View.inflate(this, R.layout.listview_header, null);
mPlv.addHeaderView(header);
// 设置下拉放大图片
mPlv.setParallaxImageView((ImageView)header.findViewById(R.id.image_view));
ArrayAdapter<String> adapter= new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
new String[]{"星期一 上班","星期二 打撸","星期三 约会","星期四 看电影","星期五 逛街","星期六 旅游","星期天 你懂的"});
mPlv.setAdapter(adapter);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus){
// 当界面第一次显示,调用onWindowFocusChanged
// 设置图片的缩放级别
mPlv.setZoomRatio(2.5);
}
}
}
这个效果相对来讲其实比较简单,如果想要把它变成ScrollView效果,只需要改变继承类即可
附源码地址:http://download.youkuaiyun.com/detail/z240336124/9591321