Android简易实战教程--第五十四话《视差特效》
查看更多进阶知识,可以关注我的公众号,微信搜索:Android小菜
这个简易实战教程系列专栏发现已经大半年没更新了啊,赶紧添点东西。
本文实现一个视差特效效果,动态效果如下:
代码十分简单,自定义View代码添加在下面:
public class ParallaxListView extends ListView { private static final String TAG = "ParallaxListView"; private ImageView ParallaxHeaderImageView;//头部视视差效果的图片 private int mOldHeight;//此时ImageView的高度 private int mRealHeight;//图片的真正高度 public ParallaxListView(Context context) { this(context,null); } public ParallaxListView(Context context, AttributeSet attrs) { super(context, attrs); } public void setHeadImageView(ImageView ivHeadImageView) { this.ParallaxHeaderImageView = ivHeadImageView; mOldHeight = ParallaxHeaderImageView.getMeasuredHeight();// int height = ParallaxHeaderImageView.getHeight();// Log.e(TAG,mOldHeight+"----"+height);//两个值一样 mRealHeight = ParallaxHeaderImageView.getDrawable().getIntrinsicHeight(); } @Override protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { System.out.println("deltaY: "+ deltaY + " scrollY: " + scrollY + " scrollRangeY: " + scrollRangeY + " maxOverScrollY: " + maxOverScrollY + " isTouchEvent: " + isTouchEvent); // deltaY : 竖直方向的瞬时偏移量, 顶部下拉- , 底部上拉+, 速度越快绝对值越大. // scrollY : 竖直方向ListView滚动的距离, 顶部- , 底部+ // scrollRangeY : 竖直方向滚动距离 // maxOverScrollY : 最大的超出滚动范围 // isTouchEvent : 是否是手指触摸到顶部/底部. true触摸, false惯性 if(deltaY <0 && isTouchEvent){ int newHeight = ParallaxHeaderImageView.getHeight() + Math.abs(deltaY)/2;//减少拖动的距离 setCurrentImageViewHeight(newHeight); } return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); } private void setCurrentImageViewHeight(int newHeight) { ParallaxHeaderImageView.getLayoutParams().height = newHeight; ParallaxHeaderImageView.requestLayout(); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_UP: int startHeight = ParallaxHeaderImageView.getHeight(); ValueAnimator animator = ValueAnimator.ofInt(startHeight, mOldHeight); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // 500 毫秒内多次调用 // 0.0 -> 1.0 System.out.println("animation: " + animation.getAnimatedFraction()); // 模拟出来的中间值 Object animatedValue = animation.getAnimatedValue(); System.out.println("animation: " + animatedValue); // 让新的高度生效 setCurrentImageViewHeight((Integer)animatedValue); } }); animator.setInterpolator(new OvershootInterpolator(4)); animator.setDuration(500); animator.start(); break; default: break; } return super.onTouchEvent(ev); }}
代码解析: 通过setHeadImageView方法传入一头布局,然后拿到当前ImageView的高度和图片的真实高度(注意:真实高度和控件的高度是不一样的)。然后重写overScrollBy方法,这个方法会对ListView滑动到边缘时候做一些判断,具体的参数含义如下:
// deltaY : 竖直方向的瞬时偏移量, 顶部下拉- , 底部上拉+, 速度越快绝对值越大.
// scrollY : 竖直方向ListView滚动的距离, 顶部- , 底部+
// scrollRangeY : 竖直方向滚动距离
// maxOverScrollY : 最大的超出滚动范围
// isTouchEvent : 是否是手指触摸到顶部/底部. true触摸, false惯性
因为是在头部下拉,所以判断deltaY<0 且是触摸状态(非惯性滑动状态),才去处理事件。得到最新的ImageView的高度【因为手指下滑有一个滑动了多少的绝对值,类加后就是当前ImagView的当前高度】,并把最新的高度设置给ImageView。这样就实现了ImagView的放大效果了。
那么松开手要做的逻辑,肯定是放在onTouchEvent的UP事件里面了,主要做的工作就是,记录松开手时候ImagView的高度,使用属性动画把ImagView控件不断地缩小,这里还使用了插值器,让ImagView恢复原来高度值后有一个弹性效果。这样整个简易的自定义View就完成了。
然后看看客户端如何使用这个控件:
MainActivity的布局文件:
<?xml version="1.0" encoding="utf-8"?>
然后在onCreat方法中:
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ParallaxListView) findViewById(R.id.lv); mHeadView = View.inflate(this, R.layout.layout_head,null); mIvHead = (ImageView) mHeadView.findViewById(R.id.iv); mListView.addHeaderView(mHeadView); mIvHead.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mListView.setHeadImageView(mIvHead); mIvHead.getViewTreeObserver().removeGlobalOnLayoutListener(this); } }); mListView.setAdapter(new ArrayAdapter(this,android.R.layout.simple_list_item_1,Strings.NAMES));}
拿到ListView的实例,给其设置数据进去。在试图绘制完毕的时候,把拿到的一张图片设置到刚才的自定义View中去了。然后运行后,就是开头的效果了。 最后可能会存在一点点的bug:
if(deltaY <0 && isTouchEvent){ int newHeight = ParallaxHeaderImageView.getHeight() + Math.abs(deltaY)/2;//减少拖动的距离 if(newHeight <= mRealHeight){ //只有在滑动的距离小于图片的真正高度的时候才去重新设置,超过了图片的高度就不去设置了。 setCurrentImageViewHeight(newHeight); } }
超过图片的实际高度不应该再往下下拉设置高度给ImagView了吧。 如果觉得有点作用记得加个关注哈,要想看更高级的文章,欢迎关注微信公众号“Android小菜”
代码下载链接地址:源码下载
更多相关文章
- Android修改图片颜色-转成灰度图
- Android ImageView设置长度高度为wrap_content时高度根据图片比
- Android实现获取本机中所有图片
- Android中实现网络图片的获取
- AsyncTask异步下载图片
- Android图片加载框架Picasso最全使用教程 一
- android checkbox 未选中状态 已选中状态 替换成自己的图片