当前位置: 移动技术网 > IT编程>移动开发>Android > Android通过overScrollBy实现下拉视差特效

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

定州学校,中国天才在韩国之临界之恋,服饰辅料

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); 
  } 
} 

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网