ListView拓展-下拉刷新,顶部图片放大效果

##效果图:
这里写图片描述

实现思路:

因为是ListView的基本功能上进行拓展,所以首先需要继承ListView。
然后给ListView添加HeadView,HeadView的布局中是一个ImageView
在ImageView中放入一张比ImageView大的图片,
重写ListView的overScrollBy()方法,下拉过程中,通过获取下拉的手滑动的距离,逐渐增加ImageView的高度值,
重写onTouchEvent()方法,当抬起手的时候,通过ValueAnimator使得ImageView返回到的初始的高度。
##代码实现:
首先,暴漏出一个方法来传入HeadView中的ImageView控件, 并在此方法中获取到ImageView的高度和ImageView中图片的真实高度。

 public void setImageView(ImageView iv){
        this.mImage = iv;
        // 获取ImageView里面图片的真实高度
        mIntrinsicHeight = iv.getDrawable().getIntrinsicHeight();
        // 获取ImageView的最初高度
        mIvHeight = iv.getLayoutParams().height;
    }

重写overScrollBy()方法,关于overScrollBy()方法的具体解释,请看我的另一篇文章TODO
在此方法中,如果图片到达了上边界,并且手还在往下拉动,则增加ImageView的高度,不断调用requestLayout()方法进行重新绘制ImageView.
可以判断,如果拉动的距离大于图片告诉百分比(可以设置提供对外的方法。让使用者自己去设置)

protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        Log.d("test", "deltaY : " + deltaY + ", scrollY : " + scrollY + ", scrollRangeY : " + scrollRangeY +  ", maxOverScrollY : " + maxOverScrollY + ", isTouchEvent : " + isTouchEvent);
        // 如果到达了边界,并且手还在往下拉
        if(isTouchEvent){
            // 到达了上边界
            if(deltaY < 0){
                int oldHeight = mImage.getLayoutParams().height;   // 获取到ImageView的高度
                int newHeight = oldHeight + Math.abs(deltaY);       // 每次手指移动,都在上次高度的基础上,加上手指移动的距离
                if(newHeight > mIntrinsicHeight * 0.995f){           // 判断如果拖动出的图片的高度大于了其真实高度百分之99.5,则不能再拖动
                    newHeight = (int) (mIntrinsicHeight * 0.995f);
                }
                mImage.getLayoutParams().height = newHeight;

                mImage.requestLayout();
            }
        }
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
    }

到此时,就能实现下拉的功能了,还差松开手后自动回弹
我们知道,监听松开手在onTouchEvent()中实现。我们看看在onTouchEvent()中需要做什么操作

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:    // 当抬起手时,图片返回到原来的高度
                va = ValueAnimator.ofInt(mImage.getLayoutParams().height, mIvHeight);
                va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        int ivHeight = (int) animation.getAnimatedValue();  // 获取到控件高度
                        mImage.getLayoutParams().height = ivHeight;
                     
                        mImage.requestLayout();
                    }
                });
                va.setInterpolator(new OvershootInterpolator(2));
                va.start();
                break;
            case MotionEvent.ACTION_DOWN:  // 当按下时,如果动画在执行,则取消
                if (va != null) {
                    if (va.isRunning()) {
                        va.cancel();
                    }
                }

                mImage.requestLayout();
                break;
        }
        return super.onTouchEvent(ev);
    }

在MotionEvent.ACTION_UP抬起手的时候,需要用ValueAnimator.ofInt(mImage.getLayoutParams().height, mIvHeight)
方法实现数值模拟变化过程,这个过程中,起始值为ImaggView控件此时的高度(此时已经被下拉),结束值为ImageView最初的高度(未下拉之前的高度)。
然后开启动画,把这些模拟数据不断设置给ImageView的height,然后调用requestLayout方法不断重新绘制。同时,为了用户体验,我使用的差值器setInterpolator(new OvershootInterpolator(2));关于差值器
Interpolator请看我的另一片文章TODO

我们注意到,在MotionEvent.ACTION_DOWN我们的也做了操作,这个操作是,但动画回弹到一半时,我们用手马上再次下拉,我们就停止当前动画,以便去响应再次下拉的操作。

##结束语:
这个控件最核心的方法是overScrollBy(),这个方法具体请看

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值