0.补一张效果图。
1.仅对ScrollView 和RecyclerView 进行顶部下拉,底部上拉实现类似小米页面,页面到达最底部,继续向下拉动时,或者页面到达最底部继续向上拉动时产生的沿着Y轴的缩放效果。
2.原理:以ScaleRecyclerView 为例,创建ScaleRecyclerView 继承至RecyclerView 。
3.重写dispatchTouchEvent()方法。当滑动调用dispatchTouchEvent时 不断检测View自身的状况。
4.在合适的时候让View进行Y轴的缩放即可。
5.这个给出ScaleRecyclerView 和ScaleScrollView 代码。
6.详细的看代码注释。
package com.yushilei.animatorscale.widget;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.yushilei.animatorscale.RAdapter;
/**
* @author by yushilei.
* @time 2016/9/8 -11:01.
* @Desc
*/
public class ScaleRecyclerView extends RecyclerView {
public ScaleRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
String TAG = "ScaleRecyView";
/**
* action down 产生的x,y坐标
*/
float lastX;
float lastY;
/**
* 当前View是否处于缩放状态
*/
boolean isScale = false;
/**
* 当前View的缩放值
*/
float mScale = 1.0f;
/**
* 产生缩放时,使用的缩放系数,该值越大缩放比率就越大
*/
float scaleRatio = 0.7f;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
float x = ev.getX();
float y = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录Down时的 x y
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
if (y - lastY > 0) {
//获取Recycler的第一个展示的View
View view = getChildAt(0);
int pos = ((RAdapter.VH) view.getTag()).getPos();
//获取该View对应在数据集合中的位置
//如果位置=0 并且该View的上边界=0 并且当前正在向下拉动
if (pos == 0 && view.getTop() >= 0) {
//计算偏移量
float distance = y - lastY;
//计算出要缩放的scale
mScale = 1 + distance * scaleRatio / getHeight();
//设置缩放的锚点
setPivotY(0f);
setPivotX(getWidth() / 2);
//进行缩放
ViewCompat.setScaleY(this, mScale);
isScale = true;
}
} else {
//获取最后一个展示的View
int count = getChildCount();
View lastView = getChildAt(count - 1);
int pos = ((RAdapter.VH) lastView.getTag()).getPos();
//判断其是否为数据集合最后一个位置
if (pos + 1 == getAdapter().getItemCount() && lastView.getBottom() <= getBottom()) {
//滑动到最底部 向上拉
float distance = y - lastY;
mScale = 1 - scaleRatio * distance / getHeight();
//设置锚点
setPivotX(getWidth() / 2);
setPivotY(getHeight());
ViewCompat.setScaleY(this, mScale);
isScale = true;
}
}
break;
case MotionEvent.ACTION_UP:
if (isScale) {
//如果已经进行了缩放,up的时候应该恢复原状,从当前scale 恢复至1.0f
ObjectAnimator animator = ObjectAnimator.ofFloat(this, "scaleY", mScale, 1.0f);
animator.setDuration(300);
animator.start();
isScale = false;
}
break;
}
return super.dispatchTouchEvent(ev);
}
}
package com.yushilei.animatorscale.widget;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;
/**
* @author by yushilei.
* @time 2016/9/8 -10:08.
* @Desc
*/
public class ScaleScrollView extends ScrollView {
public ScaleScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
float lastX;
float lastY;
String TAG = "ScaleScrollView";
boolean isScale = false;
float mScale = 1.0f;
float scaleRatio = 0.7f;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
float x = ev.getX();
float y = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
if (getScrollY() == 0 && y - lastY > 0) {
//向下拉动
float distance = y - lastY;
int height = getHeight();
mScale = 1 + distance * scaleRatio / height;
setPivotY(0f);
setPivotX(getWidth() / 2);
ViewCompat.setScaleY(this, mScale);
isScale = true;
} else {
//滑动到最底部 向上拉
int childHeight = getChildAt(0).getHeight();
int height = getHeight();
if (getScrollY() >= childHeight - height && y - lastY < 0) {
float distance = y - lastY;
mScale = 1 - scaleRatio * distance / height;
setPivotY(getHeight());
setPivotX(getWidth() / 2);
ViewCompat.setScaleY(this, mScale);
isScale = true;
}
}
break;
case MotionEvent.ACTION_UP:
if (isScale) {
ObjectAnimator animator = ObjectAnimator.ofFloat(this, "scaleY", mScale, 1.0f);
animator.setDuration(300);
animator.start();
isScale = false;
}
break;
}
return super.dispatchTouchEvent(ev);
}
}