仿QQ个人信息详情界面中背景图的下拉扩展放大功能
2017-05-03 15:57
387 查看
一般一些项目中都少不了一些头部背景图,但是如果背景图静态的现实并不能呈现出与用户操作的交互感,所以要想办法让背景图动起来,qq的一些交互感我很喜欢,比如他的个人详情界面的背景图就是可以下拉扩展,并在扩展到一定程度中可以放大图片。其设计原理就是先隐藏头部和底部的一些视图,然后在下拉过程中慢慢把隐藏的部分显示出来,到完整显示后就可以放大图片,这样设计的好处就是:1、节省一些屏幕空间,不影响正常的操作内容显示。2、增加了趣味性,能更好的提升界面与用户的互动性。
既然知道了原理就让我们自己来动手撸一个这样的控件出来吧。在此之前我也了解了一些别人实现的头部图片方法,一般是使用重写ScrollView实现的,但是其中的滑动冲突并没有解决,这自然满足不了对其他项目的兼容性,所以我实现的方法是重写NestedScrollView,使用原因是这个控件已经处理好了与子控件的滑动冲突。
先上图:
仔细看效果,这个背景图是先扩展然后再放大的。和qq的背景图的效果差不多。现在我们来分析一下怎么实现的
第一步就是怎么一开始把图片的顶部和底部隐藏
但是在此之前还要注意一下头部View的获取:
隐藏部分实现后接下来就是实现其下拉操作的部分:
扩展头部视图的实现就是根据下拉的距离来改变顶部和底部的边距,达到隐藏部分慢慢扩展显示的效果
放大的效果即调整头部视图的宽度和高度来实现的,在放大的同时要注意保持头部空间的居中特性。因为在拉伸图片放大时高度会完全显示,但是宽度会超过屏幕,要是不居中,放大的焦点就会处于左上角,居中后放大的焦点将处于控件中心。
这样主要的内容就分析完成,实现起来还是比较简单的,有兴趣可以看下源码
GitHub地址
参考博客地址:http://blog.csdn.net/anyfive/article/details/52575262
既然知道了原理就让我们自己来动手撸一个这样的控件出来吧。在此之前我也了解了一些别人实现的头部图片方法,一般是使用重写ScrollView实现的,但是其中的滑动冲突并没有解决,这自然满足不了对其他项目的兼容性,所以我实现的方法是重写NestedScrollView,使用原因是这个控件已经处理好了与子控件的滑动冲突。
先上图:
仔细看效果,这个背景图是先扩展然后再放大的。和qq的背景图的效果差不多。现在我们来分析一下怎么实现的
第一步就是怎么一开始把图片的顶部和底部隐藏
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //获取头部视图的原始宽高 if (viewWidth <= 0 || viewHeight <=0) { viewWidth = headView.getMeasuredWidth(); viewHeight = headView.getMeasuredHeight(); } //绘制视图时隐藏头部View的顶部和底部 if (hideHeight==0){ hideHeight=viewHeight/hideRatio; ViewGroup.LayoutParams layoutParams = headView.getLayoutParams(); ((MarginLayoutParams) layoutParams).setMargins(0, -hideHeight, 0,-hideHeight); headView.setLayoutParams(layoutParams); } }这里我采取的方式是通过在绘制时调整其顶部与底部的边距实现的。就这几行代码,就简单的实现了头部图片部分的隐藏
但是在此之前还要注意一下头部View的获取:
@Override protected void onFinishInflate() { super.onFinishInflate(); // 不可过度滚动,否则上移后下拉会出现部分空白的情况 setOverScrollMode(OVER_SCROLL_NEVER); // 获得默认第一个view if (getChildAt(0) != null && getChildAt(0) instanceof ViewGroup && headView == null) { ViewGroup mViewGroup = (ViewGroup) getChildAt(0); if (mViewGroup.getChildCount() > 0) { headView = mViewGroup.getChildAt(0); } } }实现的方法很简单,就是获取其内容中的第一个子视图,因为滑动视图的特性,其最近的子视图是ViewGroup,所以则获取这个ViewGroup的第一个子View
隐藏部分实现后接下来就是实现其下拉操作的部分:
@Override public boolean onTouchEvent(MotionEvent ev) { if (viewWidth <= 0 || viewHeight <=0) { viewWidth = headView.getMeasuredWidth(); viewHeight = headView.getMeasuredHeight(); } if (headView == null || viewWidth <= 0 || viewHeight <= 0) { return super.onTouchEvent(ev); } switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: if (!isUnfolding) { if (getScrollY() == 0) { pullY = ev.getY();//滑动到顶部时,记录位置 } else { break; } } int distance = (int) ((ev.getY() - pullY)*zoomRatio); if (distance < 0) break;//若往下滑动 isUnfolding = true; if (hideHeight>distance){ unfoldImage(distance); unfoldHeight=distance; return true; } setZoom(distance-hideHeight); return true; case MotionEvent.ACTION_UP: isUnfolding = false; new Handler().postDelayed(new Runnable() { @Override public void run() { if (!isUnfolding){ replyView(); } } }, 100); break; } return super.onTouchEvent(ev); }如果其子视图没有初始化宽高则初始化宽高,获取头部视图失败则过滤其滑动事件,只需要重写滑动事件即可,当滑动到顶部的时候记录下滑动的第一个位置,否则继续执行其滑动事件,当到达顶部并往上滑的时候传递滑动事件,正常使用滑动视图的功能,当到达顶部并下拉的时候开始进行扩展放大。首先是进行扩展,当图片完全展示出来后进行放大处理。当手指放开便进行视图返回操作,这里我加了个延时,目的是操作时更自然点。这个主要是介绍一下处理的逻辑,接下来分析一下扩展、放大、回弹的实现内容
/** * 扩展头部视图 * @param distance 顶部和底部扩展的距离 */ private void unfoldImage(float distance) { ViewGroup.LayoutParams layoutParams = headView.getLayoutParams(); //下拉时保持居中,设置顶部和底部的边距让隐藏的部分视图显示出来,达到扩展目的 ((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width - viewWidth) / 2>0?0:-(layoutParams.width - viewWidth) / 2, (int)(distance-hideHeight), 0,(int)(distance-hideHeight)); headView.setLayoutParams(layoutParams); }
扩展头部视图的实现就是根据下拉的距离来改变顶部和底部的边距,达到隐藏部分慢慢扩展显示的效果
/** * 放大头部View * @param distance 放大的距离 */ private void setZoom(float distance) { float scaleTimes = (float) ((viewWidth+distance)/(viewWidth*1.0)); // 如超过最大放大倍数,直接返回 if (scaleTimes > maxZoomRatio) return; ViewGroup.LayoutParams layoutParams = headView.getLayoutParams(); layoutParams.width = (int) (viewWidth + distance); layoutParams.height = (int)(viewHeight*((viewWidth+distance)/viewWidth)); // 设置控件水平居中 ((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width - viewWidth) / 2, 0, 0, 0); headView.setLayoutParams(layoutParams); isZoom=true; }
放大的效果即调整头部视图的宽度和高度来实现的,在放大的同时要注意保持头部空间的居中特性。因为在拉伸图片放大时高度会完全显示,但是宽度会超过屏幕,要是不居中,放大的焦点就会处于左上角,居中后放大的焦点将处于控件中心。
/** * 头部视图还原 */ private void replyView() { /** * 如果头部视图被放大,添加动画还原放大的头部视图 */ if (isZoom){ final float distance = headView.getMeasuredWidth() - viewWidth; // 设置动画 ValueAnimator anim = ObjectAnimator.ofFloat(distance, 0.0F).setDuration((long) (distance * replyTimeRatio)); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { setZoom((Float) animation.getAnimatedValue()); } }); anim.start(); } /** * 将扩展出来的头部视图还原 */ ValueAnimator unfold = ObjectAnimator.ofFloat(unfoldHeight, 0.0F).setDuration((long) (unfoldHeight)); unfold.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { unfoldImage((Float) animation.getAnimatedValue()); } }); unfold.start(); unfoldHeight=0; }头部视图的回弹实现就是通过给头部控件添加一个动画实现的,内容比较简单,但是需要注意当图片只是扩展时不需要给视图添加放大回弹效果
这样主要的内容就分析完成,实现起来还是比较简单的,有兴趣可以看下源码
GitHub地址
参考博客地址:http://blog.csdn.net/anyfive/article/details/52575262
相关文章推荐
- 下拉实现头部图片放大效果,实现类似QQ,新浪个人中心界面
- 下拉实现头部图片放大效果,实现类似QQ,新浪个人中心界面
- JAVA仿QQ聊天系统4.0(扩展韩顺平的程序的功能及界面)附源码
- 朋友圈 个人信息 界面 下拉 头部图片视图跟随缩放变化
- 仿面包旅行个人中心下拉顶部背景放大高斯模糊效果
- [置顶] 仿qq实现的记住密码和下拉框功能,简单易懂,还有背景炫酷的登录背景动画功能还有扫码
- 用Flash控制vfp程序,疯狂扩展您的程序功能和界面
- 完全免费功能齐全的个人信息管理系统d1PIM隆重发布
- winform模拟qq聊天界面的小功能textbox1输入自动跳到textbox2
- winform模拟qq聊天界面的小功能textbox1输入自动跳到textbox2
- 简单的QQ分类下拉功能模仿
- 在delphi程序中实现QQ用户的Web登陆并获取个人信息
- C#制作QQ截图的自动框选功能的个人思路(三)<自动框选>
- 在delphi程序中实现QQ用户的Web登陆并获取个人信息
- 项目外包,类似QQ这样界面的客户端,要求界面漂亮,功能是帮助客户完成在线业务的功能。
- C#制作QQ截图的自动框选功能的个人思路(一)<思路介绍>
- 谷歌新推隐私控制功能 方便用户查看个人信息78ps
- 完全免费功能齐全的个人信息管理系统d1PIM2009 Preview4发布
- 用combobox扩展控件(dsCtrlComboBox)做出类似QQ登录界面的效果
- 《ERP从内部集成起步》读书笔记——第8章 ERP的信息集成及扩展系统 8.1ERP内部集成的扩展功能