Android 自定义view:实现ListView下拉的视差特效

一、概述:

现在流型的APP如微信朋友圈,QQ空间,微博个人展示都有视差特效的影子。
如图:下拉图片会产生图片拉升的效果,放手后图片有弹回到原处:
这里写图片描述

那我们如何实现呢?
1)重写ListView控件:
2)重写里面的overScrollBy方法
3)在松手后执行值动画

二、具体实现:

1.创建ParallaListView 自定义ListView

public class ParallaListView extends ListView {

    private static final String TAG = "tag";

    public ParallaListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public ParallaListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ParallaListView(Context context) {
        this(context, null);
    }
}

2)添加到布局里:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.android.imooc.paralla.ParallaListView
        android:id="@+id/lv_paralla"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </com.android.imooc.paralla.ParallaListView>

</LinearLayout>

3)生成主页,填充数据:

public class ParallaActivity extends Activity {
    private ParallaListView mListView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_paralla);
        initViews();
    }

    private void initViews() {
        mListView = (ParallaListView) findViewById(R.id.lv_paralla);
        mListView.setAdapter(new ArrayAdapter<String>(ParallaActivity.this, android.R.layout.simple_list_item_1, Cheeses.NAMES));
    }
}

4)创建头布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/iv_header"
        android:scaleType="centerCrop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/parallax_img" />

</LinearLayout>

图片设成scaleType=”centerCrop”模式
其它模式说明:
这里写图片描述

5)在主页里找到头布局并添加到listview里

View mHeader = LayoutInflater.from(this).inflate(R.layout.view_paralla_header, null);
mListView = (ParallaListView) findViewById(R.id.lv_paralla);
mListView.addHeaderView(mHeader);

三、功能实现:

1.现在基本能看到效果了,但我们必须要拖动图片,这就要实现这个方法overScrollBy
因为拖动是Y轴方向,所以只要打印Y轴方向的各个参数就好了

@Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
            int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        Logger.i(TAG, "deltaY="+deltaY + " scrollX="+scrollX+ " scrollRangeY="+scrollRangeY + " maxOverScrollY=" +maxOverScrollY + " isTouchEvent=" +isTouchEvent);

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

}

得到数据下拉:deltaY=-3 scrollX=0 scrollRangeY=0 maxOverScrollY=0 isTouchEvent=true
得到数据上拉:deltaY=4 scrollX=0 scrollRangeY=0 maxOverScrollY=0 isTouchEvent=true

2.如果是下拉,我们把值赋给header,但我们如何获得高度呢?
1)在主页里初始化图片,然后设置到parallaListView里

ImageView iv = (ImageView) findViewById(R.id.iv_head);
mListView.setParallaImage(iv);

2)在parallaListView创建方法setParallaImage

public void setParallaImage(ImageView iv) {
        mImageView = iv;
        //在这个方法里获得高度
        int height = iv.getHeight();
        int measureHeight = iv.getMeasuredHeight();
        int instrinsicHeight = iv.getDrawable().getIntrinsicHeight();
        Logger.i(TAG, "height="+height + " measureHeight="+measureHeight+ " instrinsicHeight="+instrinsicHeight );
    }

得到结果:height=0 measureHeight=0 instrinsicHeight=732
为什么会如此:因为此时的图片还没有初始化
那我们如何得到高度呢?
记得有个方法叫做iv.getViewTreeObserver(),那我们就在这个方法的监听事件里得到高度

iv.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //当布局填充完成后,此方法会被调用
                mListView.setParallaImage(iv);
                //移除监听
                iv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
        });

此时得到的高度height=240 measureHeight=240 instrinsicHeight=732

3)把值赋给图片就能实现拉伸的效果了

if (isTouchEvent && deltaY < 0) {
            mHeight += Math.abs(deltaY);
            if (mHeight <= mBitmapHeight) {
                mImageView.getLayoutParams().height = mHeight;
                mImageView.requestLayout();
            }

        }

3.松手后图片回弹,这个功能在onTouchEvent里实现:

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_UP:
            final int startHeight = mImageView.getHeight();
            final int endHeight = mBitmapHeight;
            //值动画
            //valueAnim(startHeight, endHeight);

            //竖直移动动画
            ResetAnimation anim = new ResetAnimation(mImageView, startHeight, endHeight);
            anim.setInterpolator(new OvershootInterpolator());
            startAnimation(anim);
            break;

        default:
            break;
        }
        return super.onTouchEvent(ev);
    }

4、动画实现:

/**
 * @描述         使用平移动画实现下拉图片后弹射回去
 * @项目名称      App_imooc
 * @包名         com.android.imooc.paralla
 * @类名         ResetAnimation
 * @author      chenlin
 * @date        2016年5月29日 下午12:27:00
 * @version     1.0
 */

public class ResetAnimation extends Animation {
    private ImageView mImageView;
    private int mStartHeight;
    private int mEndHeight;

    public ResetAnimation(ImageView imageView, int startHeight, int endHeight) {
        this.mImageView = imageView;
        this.mStartHeight = startHeight;
        this.mEndHeight = endHeight;

        setDuration(500);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        int newHeight = (int) (ValueUtil.evalute(interpolatedTime, mStartHeight, mEndHeight) + 0.5f);
        mImageView.getLayoutParams().height = newHeight;
        mImageView.requestLayout();
        super.applyTransformation(interpolatedTime, t);
    }
}

四、源码下载:

链接:http://pan.baidu.com/s/1sk8vzA1 密码:r33a

———————————————————————
(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)
有需求者请进站查看,非诚勿扰

https://item.taobao.com/item.htm?spm=686.1000925.0.0.4a155084hc8wek&id=555888526201

01.高级架构师四十二个阶段高
02.Java高级系统培训架构课程148课时
03.Java高级互联网架构师课程
04.Java互联网架构Netty、Nio、Mina等-视频教程
05.Java高级架构设计2016整理-视频教程
06.架构师基础、高级片
07.Java架构师必修linux运维系列课程
08.Java高级系统培训架构课程116课时
(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)
——————————————————————–

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lovoo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值