android scrollby 动画,Android通过overScrollBy实现下拉视差特效

overScrollBy实现下拉视差特效,效果图如下

de57e73539b9c8b8f8a039288ad8ade7.gif

先来分析overScrollBy方法的使用,它是View的方法,参数有点多:

/**

* 当滑动的超出上,下,左,右最大范围时回调

*

* @param deltaX x方向的瞬时偏移量,左边到头,向右拉为负,右边到头,向左拉为正

* @param deltaY y方向的瞬时偏移量,顶部到头,向下拉为负,底部到头,向上拉为正

* @param scrollX 水平方向的永久偏移量

* @param scrollY 竖直方向的永久偏移量

* @param scrollRangeX 水平方向滑动的范围

* @param scrollRangeY 竖直方向滑动的范围

* @param maxOverScrollX 水平方向最大滑动范围

* @param maxOverScrollY 竖直方向最大滑动范围

* @param isTouchEvent 是否是手指触摸滑动, true为手指, false为惯性

* @return

*/

@Override

protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,

int scrollRangeX, int scrollRangeY, int maxOverScrollX,

int maxOverScrollY, boolean isTouchEvent) {

return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,

scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY,

isTouchEvent);

}

大致步骤如下:

1.这整体是一个ListView,所以需要自定义一个ListView.

2.处理头部布局文件,将其以HeaderView的方式添加到自定义的ListView中

3.需要获取HeaderView的ImageView的初始高度和ImageView中图片的高度.因为这2个高度将决定下来的时候图片拉出的范围,以及松手后图片回弹的动画效果.对应控件宽高的获取,有兴趣的可以看这篇文章浅谈自定义View的宽高获取

4.在overScrollBy方法内通过修改ImageView的LayoutParams的height值来显示更多的图片内容.

5.在onTouchEvent方法内处理ACTION_UP事件,使ImageView有回弹的动画效果,这里介绍2种方式,分别是属性动画和自定义动画.

好了,先来看HeaderView的布局文件:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

android:id="@+id/imageView"

android:layout_width="match_parent"

android:layout_height="160dp"

android:scaleType="centerCrop"

android:src="@drawable/header" />

没什么特别的,就是一个ImageView,通过src设置了一张图片,这里唯一要将的就是scaleType属性,我这边设置了centerCrop,以图片的最小的边开始截取,因为这里选择的图片是高度大于宽度的,所以裁剪的时候会保留完整的宽度,中心裁剪,如下图所示:

086aa9ec5871af10a3325c34acf05e90.png

自定义ListView代码,整体代码还是比较简短的.

/**

* Created by mChenys on 2015/12/23.

*/

public class MyListView extends ListView {

private ImageView mHeaderIv; //HeaderView 的ImageView

private int mOriginalHeight; //最初ImageView的高度

private int mDrawableHeight;//ImageView中图片的高度

public MyListView(Context context) {

this(context, null);

}

public MyListView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

/**

* 设置头部和获取高度信息

*/

private void init() {

//初始化头部文件

View headerView = View.inflate(getContext(), R.layout.view_header, null);

mHeaderIv = (ImageView) headerView.findViewById(R.id.imageView);

//将其添加到ListView的头部

addHeaderView(headerView);

//通过设置监听来获取控件的高度

mHeaderIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)

@Override

public void onGlobalLayout() {

//只需监听一次,否则之后的onLayout方法回调的时候还是会回调这里

mHeaderIv.getViewTreeObserver().removeOnGlobalLayoutListener(this);

mOriginalHeight = mHeaderIv.getMeasuredHeight();//获取ImageView的初始高度

mDrawableHeight = mHeaderIv.getDrawable().getIntrinsicHeight();//获取ImageView中图片的高度

}

});

//去掉下拉到头部后的蓝色线

setOverScrollMode(OVER_SCROLL_NEVER);

}

/**

* 当滑动的超出上,下,左,右最大范围时回调

*

* @param deltaX x方向的瞬时偏移量,左边到头,向右拉为负,右边到头,向左拉为正

* @param deltaY y方向的瞬时偏移量,顶部到头,向下拉为负,底部到头,向上拉为正

* @param scrollX 水平方向的永久偏移量

* @param scrollY 竖直方向的永久偏移量

* @param scrollRangeX 水平方向滑动的范围

* @param scrollRangeY 竖直方向滑动的范围

* @param maxOverScrollX 水平方向最大滑动范围

* @param maxOverScrollY 竖直方向最大滑动范围

* @param isTouchEvent 是否是手指触摸滑动, true为手指, false为惯性

* @return

*/

@Override

protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,

int scrollRangeX, int scrollRangeY, int maxOverScrollX,

int maxOverScrollY, boolean isTouchEvent) {

// 手指拉动并且是下拉

if (isTouchEvent && deltaY < 0) {

// 把拉动的瞬时变化量的绝对值交给Header, 就可以实现放大效果

if (mHeaderIv.getHeight() <= mDrawableHeight) {

// 高度不超出图片最大高度时,才让其生效

int newHeight = (int) (mHeaderIv.getHeight() + Math.abs(deltaY / 3.0f));//这里除以3是为了达到视差的效果

mHeaderIv.getLayoutParams().height = newHeight;

//此方法必须调用,调用后会重新调用onMeasure和onLayout方法进行测量和定位

mHeaderIv.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:

// 执行回弹动画, 方式一: 属性动画\值动画

//获取ImageView在松手时的高度

int currHeight = mHeaderIv.getHeight();

// 从当前高度mHeaderIv.getHeight(), 执行动画到原始高度mOriginalHeight

ValueAnimator animator = ValueAnimator.ofInt(currHeight, mOriginalHeight);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

int value = (int) animation.getAnimatedValue();

mHeaderIv.getLayoutParams().height = value;

//此方法必须调用,调用后会重新调用onMeasure和onLayout方法进行测量和定位

mHeaderIv.requestLayout();

}

});

animator.setDuration(500);

animator.setInterpolator(new OvershootInterpolator());

animator.start();

//方式二,通过自定义动画

/*ResetAnimation animation = new ResetAnimation(mHeaderIv, mHeaderIv.getHeight(), mOriginalHeight);

startAnimation(animation);*/

break;

}

return super.onTouchEvent(ev);

}

}

看看自定义动画:

/**

* 自定义动画

* Created by mChenys on 2015/12/24.

*/

public class ResetAnimation extends Animation {

private final ImageView headerIv; //要执行动画的目标ImageView

private final int startHeight;//执行动画的开始时的高度

private final int endHeight;//执行动画结束时的高度

private IntEvaluator mEvaluator; //整型估值器

/**

* 构造方法初始化

*

* @param headerIv 应用动画的目标控件

* @param startHeight 开始的高度

* @param endHeight 结束的高度

*/

public ResetAnimation(ImageView headerIv, int startHeight, int endHeight) {

this.headerIv = headerIv;

this.startHeight = startHeight;

this.endHeight = endHeight;

//定义一个int类型的类型估值器,用于获取实时变化的高度值

mEvaluator = new IntEvaluator();

//设置动画持续时间

setDuration(500);

//设置插值器

setInterpolator(new OvershootInterpolator());

}

/**

* 在指定的时间内一直执行该方法,直到动画结束

* interpolatedTime:0-1 标识动画执行的进度或者百分比

*

* @param interpolatedTime

* @param t

*/

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

int currHeight = mEvaluator.evaluate(interpolatedTime, startHeight, endHeight);

//通过LayoutParams不断的改变其高度

headerIv.getLayoutParams().height = currHeight;

//此方法必须调用,调用后会重新调用onMeasure和onLayout方法进行测量和定位

headerIv.requestLayout();

}

}

MainActivity测试类:

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

MyListView listView = new MyListView(this);

listView.setDividerHeight(1);

listView.setSelector(new ColorDrawable());

listView.setCacheColorHint(Color.TRANSPARENT);

listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, Cheeses.NAMES));

setContentView(listView);

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值