Android通过overScrollBy实现下拉视差特效

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

先来分析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的布局文件:

<?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/imageView"
    android:layout_width="match_parent"
    android:layout_height="160dp"
    <span style="color:#ff0000;">android:scaleType="centerCrop"</span>
    android:src="@drawable/header" />
</LinearLayout>

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

自定义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)

相关推荐

  • Android UI设计系列之自定义ListView仿QQ空间阻尼下拉刷新和渐变菜单栏效果(8)

    好久没有写有关UI的博客了,刚刚翻了一下之前的博客,最近一篇有关UI的博客:Android UI设计系列之自定义Dialog实现各种风格的对话框效果(7) ,实现各种风格效果的对话框,在那篇博客写完后由于公司封闭开发封网以及其它原因致使博客中断至今,中断这么久很是惭愧,后续我会尽量把该写的都补充出来.近来项目有个需求,要做个和QQ空间类似的菜单栏透明度渐变和下拉刷新带有阻尼回弹的效果.于是花点时间动手试了试,基本上达到了QQ空间的效果,截图如下: 通过观察QQ空间的运行效果,发现当往上滚动时菜单

  • Android自定义view实现阻尼效果的加载动画

    效果: 需要知识: 1. 二次贝塞尔曲线 2. 动画知识 3. 基础自定义view知识 先来解释下什么叫阻尼运动 阻尼振动是指,由于振动系统受到摩擦和介质阻力或其他能耗而使振幅随时间逐渐衰减的振动,又称减幅振动.衰减振动.[1] 不论是弹簧振子还是单摆由于外界的摩擦和介质阻力总是存在,在振动过程中要不断克服外界阻力做功,消耗能量,振幅就会逐渐减小,经过一段时间,振动就会完全停下来.这种振幅随时间减小的振动称为阻尼振动.因为振幅与振动的能量有关,阻尼振动也就是能量不断减少的振动.阻尼振动是非简谐运

  • Android通过overScrollBy实现下拉视差特效

    overScrollBy实现下拉视差特效,效果图如下 先来分析overScrollBy方法的使用,它是View的方法,参数有点多: /** * 当滑动的超出上,下,左,右最大范围时回调 * * @param deltaX x方向的瞬时偏移量,左边到头,向右拉为负,右边到头,向左拉为正 * @param deltaY y方向的瞬时偏移量,顶部到头,向下拉为负,底部到头,向上拉为正 * @param scrollX 水平方向的永久偏移量 * @param scrollY 竖直方向的永久偏移量 * @

  • Android实现简单的下拉阻尼效应示例代码

    OS的下拉上拉都会出现一个很玄的动态效果.在Android中,虽然可以实现类似的效果,但有点不同的是,如果调用overScrollBy来实现类似的阻尼效应的话,最顶部会出现一片亮的区域,让人感觉不是很爽.所以决定不采用该方法来实现而是改用自定义的方式来实现. 下面是自定义控件的代码部分: public class MyView extends ScrollView { //记录下最开始点击的位置 int initY; //移动的位置 int deltaY; int touchY; //记录第一个

  • jQuery+easyui中的combobox实现下拉框特效

    1.第一种写法:Input框中显示: 复制代码 代码如下: <input id="cc" class="easyui-combobox" name="name" data-options="valueField:'value',textField:'text',data:[{'value':'1','text':'java'},{'value':'2','text':'C#'}]"/> 2. 第二种用法,在list

  • jQuery树形下拉菜单特效代码分享

    本文实例讲述了jQuery实现幻树形下拉菜单特效,实现自动伸缩,分享给大家供大家参考. 运行jQuery树形下拉菜单特效效果图: 为大家分享的jQuery树形下拉菜单代码如下 <head> <title>常用的jquery下拉菜单</title> <script type="text/javascript" src="js/jquery.js"></script> <script type="

  • Android微信端的下拉刷新功能

    在Android和iOS上对于下拉刷新的处理方法: 在微信公众号内,在面对下拉刷新这个问题上,Android和iOS都自己的表现方式: iOS: Android: 所以我们要给内容加载监听器 function bindEvent() { document.addEventListener('touchstart', touchSatrtFunc, false); document.addEventListener('touchmove', touchMoveFunc, false); docum

  • Android 仿硅谷新闻下拉刷新/上拉加载更多

    1.添加加载更多布局 1_初始化和隐藏代码 在RefreshListView构造方法中调用 private void initFooterView(Context context) { View footerView = View.inflate(context, R.layout.refresh_listview_footer, null); //隐藏代码 footerView.measure(0, 0); int footerViewHeight = footerView.getMeasur

  • JavaScript简单下拉菜单特效

    本文实例为大家分享了js下拉菜单特效,供大家参考,具体内容如下 实例1:联动的省市下拉菜单 onchange 事件会在域的内容改变时发生. <script type="text/javascript"> var arr = new Array(); //数据数组 //定义数据,结构为:id.名字.父id arr[arr.length] = [1, '北京市', null]; arr[arr.length] = [2, '四川省', null]; arr[arr.length

  • Android开发之禁止下拉通知栏的方法

    本文实例讲述了Android开发之禁止下拉通知栏的方法.分享给大家供大家参考,具体如下: 1.在AndroidManifest.xml中添加权限 <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/> <uses-permission android:name="android.permission.STATUS_BAR"/> 2.在相应的activity中

  • Android编程实现二级下拉菜单及快速搜索的方法

    本文实例讲述了Android编程实现二级下拉菜单及快速搜索的方法.分享给大家供大家参考,具体如下: 一.我们要做什么? 上面有个搜索框,下面是一个二级下拉菜单. 输入查询内容,下面列表将显示查询结果. 二.界面设计 (1)这是主框架(部分属性已经省去,请看源码),从上至下分别是文本框,列表,二级列表. <?xml version="1.0" encoding="utf-8"?> <LinearLayout> <LinearLayout

  • Android使用ListView实现下拉刷新及上拉显示更多的方法

    本文实例讲述了Android使用ListView实现下拉刷新及上拉显示更多的方法.分享给大家供大家参考,具体如下: 今天得需求是做listview+上下拉动在header和footer显示progressdialog,但不影响用户操作 直接上代码,我已经加上注释了,自己看. package com.stay.main; import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.HashMap;

随机推荐