Android实现有视差效果的ListView
视差效果是什么?
所谓的视差效果在web设计和移动应用中都非常常见,我们在一些主要的平台都可以发现它的身影,从windows phone到ios乃至android。按照*的说法,视差滚动是计算机图形学中的一种特殊的滚动技术,在此相机移动背景图像比前景图像慢,从而引起了视觉深度的假象。
那么到底什么是视差效果呢?一起来看效果图就知道了:
我们可以看到 listview
的 headerview
会跟随 listview
的滑动而变大,headerview
里的图片会有缩放效果。这些可以使用属性动画来实现。接下来我们就来动手吧!
首先自定义几个属性,在之后可以用到:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="zoomlistview"> <!-- headerview的高度 --> <attr name="header_height" format="dimension|reference"></attr> <!-- headerview的最大高度 --> <attr name="header_max_height" format="dimension|reference"></attr> <!-- headerview里面的图片最大的伸缩量 --> <attr name="header_max_scale" format="float"></attr> </declare-styleable> </resources>
之后创建 zoomlistview
类,继承自 listview
:
public class zoomlistview extends listview { // 最大的伸缩量 private final float defaultheadermaxscale = 1.2f; // 头部最大的高度 private float headermaxheight; // 头部初始高度 private float headerheight; // 头部默认初始高度 private float defaultheaderheight; // 头部默认最大的高度 private float defaultheadermaxheight; private imageview headerview; private viewgroup.layoutparams layoutparams; private linearlayout linearlayout; // 最大的缩放值 private float headermaxscale; public zoomlistview(context context) { this(context, null); } public zoomlistview(context context, attributeset attrs) { this(context, attrs, 0); } public zoomlistview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); defaultheaderheight = typedvalue.applydimension(typedvalue.complex_unit_dip, 160, context.getresources().getdisplaymetrics()); defaultheadermaxheight = typedvalue.applydimension(typedvalue.complex_unit_dip, 240, context.getresources().getdisplaymetrics()); typedarray a = context.obtainstyledattributes(attrs, r.styleable.zoomlistview); headerheight = a.getdimension(r.styleable.zoomlistview_header_height, defaultheaderheight); headermaxheight = a.getdimension(r.styleable.zoomlistview_header_max_height, defaultheadermaxheight); headermaxscale = a.getfloat(r.styleable.zoomlistview_header_max_scale, defaultheadermaxscale); a.recycle(); initview(); } ... }
到这里都是按部就班式的,设置好自定义属性的初始值,之后调用 initview()
,那就来看看 initview()
方法:
private void initview() { headerview = new imageview(getcontext()); headerview.setscaletype(imageview.scaletype.center_crop); linearlayout = new linearlayout(getcontext()); linearlayout.addview(headerview); layoutparams = headerview.getlayoutparams(); if (layoutparams == null) { layoutparams = new viewgroup.layoutparams(viewgroup.layoutparams.match_parent, (int) headerheight); } else { layoutparams.width = viewgroup.layoutparams.match_parent; layoutparams.height = (int) headerheight; } headerview.setlayoutparams(layoutparams); addheaderview(linearlayout); } public void setdrawableid(int id) { headerview.setimageresource(id); }
可以看出在 initview()
里我们创建了 headerview
,并添加到了listview
的头部。而 setdrawableid(int id)
就是给 headerview
设置相关图片的。
下面就是视差效果的主要实现代码了:
@override protected boolean overscrollby(int deltax, int deltay, int scrollx, int scrolly, int scrollrangex, int scrollrangey, int maxoverscrollx, int maxoverscrolly, boolean istouchevent) { if (deltay < 0 && istouchevent) { if (headerview.getheight() < headermaxheight) { int newheight = headerview.getheight() + math.abs(deltay / 3); headerview.getlayoutparams().height = newheight; headerview.requestlayout(); float temp = 1 + (headermaxscale - 1f) * (headerview.getheight() - headerheight) / (headermaxheight - headerheight); headerview.animate().scalex(temp) .scaley(temp).setduration(0).start(); } } return super.overscrollby(deltax, deltay, scrollx, scrolly, scrollrangex, scrollrangey, maxoverscrollx, maxoverscrolly, istouchevent); }
我们重写了 overscrollby()
方法,当 deltay 小于0时(即 listview
已经到顶端,但是用户手势还是向下拉),去动态地设置 headerview
的高度以及 headerview
的 scale
值。这样就可以产生 headerview
变高以及图片放大的效果了。
接下来要考虑的问题就是当用户松开手指时,要恢复回原来的样子。所以我们应该在 ontouchevent(motionevent ev)
里去实现相关操作:
@override public boolean ontouchevent(motionevent ev) { switch (ev.getaction()) { case motionevent.action_up: startanim(); break; } return super.ontouchevent(ev); } // 开始执行动画 private void startanim() { valueanimator animator = valueanimator.offloat(headerview.getheight(), headerheight); animator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { float fraction = (float) animation.getanimatedvalue(); headerview.getlayoutparams().height = (int) fraction; headerview.requestlayout(); } }); animator.setduration(500); animator.setinterpolator(new linearinterpolator()); valueanimator animator2 = valueanimator.offloat(headerview.getscalex(), 1f); animator2.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { float fraction = (float) animation.getanimatedvalue(); headerview.setscalex(fraction); headerview.setscaley(fraction); } }); animator2.setduration(500); animator2.setinterpolator(new linearinterpolator()); animator.start(); animator2.start(); }
上面的代码简单点来说,就是在 action_up 时,去开始两个属性动画,一个属性动画是将 headerview
的高度恢复成原来的值,另一个属性动画就是把 headerview
的 scale 重新恢复为1f。相信大家都可以看懂的。
总结
以上就是这篇文章的全部内容了,希望这篇文章的内容对各位android开发者们能有所帮助,如果有疑问大家可以留言交流。
上一篇: Java接口和抽象类实例分析
推荐阅读
-
Android ListView弹性效果的实现方法
-
Android ListView弹性效果的实现方法
-
Android App中ListView仿QQ实现滑动删除效果的要点解析
-
Android App中ListView仿QQ实现滑动删除效果的要点解析
-
Android中如何取消listview的点击效果
-
Android中如何取消listview的点击效果
-
Android Animation实战之一个APP的ListView的动画效果
-
Android Animation实战之一个APP的ListView的动画效果
-
Android开发使用自定义view实现ListView下拉的视差特效功能
-
Android开发使用自定义view实现ListView下拉的视差特效功能