欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-01 17:13:16
overscrollby实现下拉视差特效,效果图如下 先来分析overscrollby方法的使用,它是view的方法,参数有点多: /** * 当滑...

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

Android通过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,以图片的最小的边开始截取,因为这里选择的图片是高度大于宽度的,所以裁剪的时候会保留完整的宽度,中心裁剪,如下图所示:

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

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

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