当前位置: 移动技术网 > 移动技术>移动开发>Android > Android实现有视差效果的ListView

Android实现有视差效果的ListView

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

视差效果是什么?

所谓的视差效果在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开发者们能有所帮助,如果有疑问大家可以留言交流。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网