ListView的头部视差效果的实现

本文介绍了一种具有头部视差效果的ListView实现方法。通过自定义ListView并重写滑动及触摸事件,使得列表顶部图片能在滑动时产生缩放效果,并在手指离开时平滑回弹至原始状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先看效果

视差效果

实现这个效果主要是自定义了ListView,添加了一个处理滑动到顶端的方法(mListView.setOverScrollMode(ListView.OVER_SCROLL_NEVER);),另外又重写OnTouchEvent方法, 当手指松开的时候实现一个图片高度的还原和一个弹性动画的效果,用到了nineoldandroid库。

具体的思路如下
- 自定义ListView,ParallaxListView,为其先填充数据
- 添加头部布局
- ImageView中src与background的区别
- addHeaderView完成之后才可以setAdapter
- 当拉到顶端的时候让HeadView的图片放大
- overScrollBy方法
- 各个参数的意义
- 当手指松开的时候图片回到原来的高度,并伴随弹性动画
- nineoldandroid
- 去除ListView下拉时的蓝色阴影。
- mListView.setOverScrollMode(ListView.OVER_SCROLL_NEVER);

  • 自定义ListView的代码
/**
 * Created by sunxin on 2016/10/6.
 * 具有头部视差效果的ListView
 */
public class ParallaxListView extends ListView {
    private static final String TAG = "ParallaxListView";
    private int mImageViewHeight;//ImageView的原始高度

    public ParallaxListView(Context context) {
        super(context);
    }

    public ParallaxListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ParallaxListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    //设置图片的最大高度
    private int maxHeight;

    private ImageView mImageView;

    public void setImageView(final ImageView imageView) {
        this.mImageView = imageView;
        //设置图片的最大高度   Intrinsic:本质的,固有的

        //设置一个全局的布局监听,在onLayout方法执行完之后执行。保证getHeight不等于0
        imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //一定要移除
                imageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                //需要兼容小图片
                int drawableHeight = imageView.getDrawable().getIntrinsicHeight();//图片的高度
                //ImageView的高度,不过这个height可能为0
                mImageViewHeight = imageView.getHeight();
                //如果图片的高度小于ImageView的高度,那么最大高度设置为ImageView高度的2倍。否则就设置为图片高度
                maxHeight = drawableHeight < mImageViewHeight ? mImageViewHeight * 2 : drawableHeight;
            }
        });



    }


    /**
     * 控制滑动到边缘的处理方法。在ListView滑动到头的时候执行,可以获取继续滑动的距离和方向
     *
     * @param deltaX         x轴继续滑动的距离
     * @param deltaY         y轴继续滑动的距离  负值:顶部到头,  正值:底部到头
     * @param scrollX
     * @param scrollY
     * @param scrollRangeX
     * @param scrollRangeY
     * @param maxOverScrollX x方向最大的可以滑动的距离
     * @param maxOverScrollY y方向最大的可以滑动的距离 修改这个值就可以让ListView具有弹性
     * @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) {


        Log.d(TAG, "overScrollBy: deltaY    " + deltaY + "   isTouchEvent    " + isTouchEvent);

        if (deltaY < 0 && isTouchEvent) {
            //说明是顶部到头并且是手指继续拖动
            //让ImageView的height不断的增大
            if (mImageView != null) {
                int newHeight = mImageView.getHeight() - deltaY/3;
                //判断是否超过最大的高度
                if (newHeight > maxHeight) {
                    newHeight = maxHeight;
                }

                mImageView.getLayoutParams().height = newHeight;
                mImageView.requestLayout();//使布局生效
            }
        }


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


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //设置手松开图片高度回到原来的高度
        if (ev.getAction() == MotionEvent.ACTION_UP){
            //使用属性动画,nineoldandroid.jar
            //设置从当前高度到原始高度
            ValueAnimator animator = ValueAnimator.ofFloat(mImageView.getHeight(),mImageViewHeight);
            //添加动画更新的监听
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animator) {
                    //获取的动画的值
                    float animatorValue = (Float) animator.getAnimatedValue();
                    mImageView.getLayoutParams().height = (int) animatorValue;
                    mImageView.requestLayout();//使布局生效
                }
            });
            animator.setInterpolator(new OvershootInterpolator());//弹性差值器
            animator.setDuration(350);
            animator.start();
        }

        return super.onTouchEvent(ev);
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_kayce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值