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

Android实现有视差效果的ListView

程序员文章站 2024-03-04 19:03:18
视差效果是什么? 所谓的视差效果在web设计和移动应用中都非常常见,我们在一些主要的平台都可以发现它的身影,从windows phone到ios乃至android。按照维...

视差效果是什么?

所谓的视差效果在web设计和移动应用中都非常常见,我们在一些主要的平台都可以发现它的身影,从windows phone到ios乃至android。按照*的说法,视差滚动是计算机图形学中的一种特殊的滚动技术,在此相机移动背景图像比前景图像慢,从而引起了视觉深度的假象。

那么到底什么是视差效果呢?一起来看效果图就知道了:

Android实现有视差效果的ListView

我们可以看到 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接口和抽象类实例分析

下一篇: