Android通过overScrollBy实现下拉视差特效
程序员文章站
2023-12-01 17:13:16
overscrollby实现下拉视差特效,效果图如下
先来分析overscrollby方法的使用,它是view的方法,参数有点多:
/**
* 当滑...
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); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。