最近项目里用到了一个开源的仿IOS可弹动的ScrollView,看源代码时发现其实实现原理是用 View动画实现的,每次都播一个动画,最后重新layout这个布局。看到使用了View动画,就有点不想用这个控件了,因为个人感觉View动画,应该是要被淘汰的技术了,于是就自己根据实现原理,重写了一个ScrollView,实现了同样的功能.
思路:利用属性动画,及其View的偏移原理即可实现同样的功能。
代码如下:
/**
* @description 仿IOS有弹性ScrollView
* @author rzq
* @date 2015年9月19日
*/
public class OverScrollView extends ScrollView
{
/**
* 动画执行时间
*/
private static final int ANIM_DURING = 300;
/**
* 最大可拖拽距离
*/
private static final int MAX_SPAN = 500;
private View mContentView;
private TimeInterpolator mInterpolator;
/**
* 是否可上下拉
*/
private boolean canPullDown;
private boolean canPullUp;
private float mDownY;
private boolean isMove;
public OverScrollView(Context context)
{
this(context, null);
}
public OverScrollView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
protected void onFinishInflate()
{
if (getChildCount() > 0)
{
mContentView = getChildAt(0);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev)
{
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
mDownY = ev.getY();
canPullDown = isCanPullDown();
canPullUp = isCanPullUp();
break;
case MotionEvent.ACTION_MOVE:
float moveY = ev.getY();
float deltaY = moveY - mDownY;
if (deltaY > 10 && canPullDown)
{
if (deltaY >= MAX_SPAN)
{
deltaY = MAX_SPAN;
}
mContentView.setTranslationY(deltaY);
isMove = true;
}
if (deltaY < -10 && canPullUp)
{
if (deltaY <= -MAX_SPAN)
{
deltaY = -MAX_SPAN;
}
mContentView.setTranslationY(deltaY);
isMove = true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
/**
* 利用动画回到原位置
*/
if (isMove)
{
scrollToOrginial();
}
isMove = false;
break;
}
return super.dispatchTouchEvent(ev);
}
/**
* 利用属性动画滚回原位置
*/
private void scrollToOrginial()
{
ObjectAnimator anim = ObjectAnimator.ofFloat(mContentView, "translationY", mContentView.getTranslationY(), 0);
anim.setDuration(ANIM_DURING);
if (mInterpolator != null)
{
anim.setInterpolator(mInterpolator);
}
anim.start();
}
/**
* 设置动画差值器
*/
public void setInterpolator(TimeInterpolator interpolator)
{
this.mInterpolator = interpolator;
}
private boolean isCanPullDown()
{
return getScrollY() == 0 || mContentView.getHeight() < getHeight() + getScrollY();
}
private boolean isCanPullUp()
{
return mContentView.getHeight() <= getHeight() + getScrollY();
}
}
用法与普通的ScrollView用法完全一样,类中属性都是用的默认值,如果想动态修改,可以改我自定义属性使用即可。将代码拷贝到项目中即可。