一般一些项目中都少不了一些头部背景图,但是如果背景图静态的现实并不能呈现出与用户操作的交互感,所以要想办法让背景图动起来,qq的一些交互感我很喜欢,比如他的个人详情界面的背景图就是可以下拉扩展,并在扩展到一定程度中可以放大图片。其设计原理就是先隐藏头部和底部的一些视图,然后在下拉过程中慢慢把隐藏的部分显示出来,到完整显示后就可以放大图片,这样设计的好处就是:1、节省一些屏幕空间,不影响正常的操作内容显示。2、增加了趣味性,能更好的提升界面与用户的互动性。

既然知道了原理就让我们自己来动手撸一个这样的控件出来吧。在此之前我也了解了一些别人实现的头部图片方法,一般是使用重写ScrollView实现的,但是其中的滑动冲突并没有解决,这自然满足不了对其他项目的兼容性,所以我实现的方法是重写NestedScrollView,使用原因是这个控件已经处理好了与子控件的滑动冲突。

先上图:

仔细看效果,这个背景图是先扩展然后再放大的。和qq的背景图的效果差不多。现在我们来分析一下怎么实现的

第一步就是怎么一开始把图片的顶部和底部隐藏

    @Overrideprotected 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的获取:

    @Overrideprotected void onFinishInflate() {super.onFinishInflate();
//        不可过度滚动,否则上移后下拉会出现部分空白的情况setOverScrollMode(OVER_SCROLL_NEVER);
//        获得默认第一个viewif (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

隐藏部分实现后接下来就是实现其下拉操作的部分:

    @Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {unfoldImage((Float) animation.getAnimatedValue());}});unfold.start();unfoldHeight=0;}

头部视图的回弹实现就是通过给头部控件添加一个动画实现的,内容比较简单,但是需要注意当图片只是扩展时不需要给视图添加放大回弹效果

这样主要的内容就分析完成,实现起来还是比较简单的,有兴趣可以看下源码

GitHub地址

参考博客地址:http://blog.csdn.net/anyfive/article/details/52575262

仿QQ个人信息详情界面中背景图的下拉扩展放大功能相关推荐

  1. uniapp仿朋友圈背景图,下拉动画

    可以把下面代码先粘贴过去再细细研究一下,就是做动画,代码是可以实现效果的 <template><view class="pages" @touchmove=&qu ...

  2. 高仿QQ运动的周报界面

    这次高仿的是QQ运动的周报界面的网图.这个控件刚开始的时候以为代码量不大,没想到一路下来界面代码在加上动画代码还是蛮多的.好了老规矩先上图: 效果还是和qq的才不多吧. 1. 首先我把各个变量都贴出来 ...

  3. CSS-解决苹果点击高亮、安卓select灰色背景(select下拉框在IOS中背景变黑、出现阴影问题)

    CSS-解决苹果点击高亮.安卓select灰色背景(select下拉框在IOS中背景变黑.出现阴影问题) 参考文章: (1)CSS-解决苹果点击高亮.安卓select灰色背景(select下拉框在IO ...

  4. Pyqt5 在表格中单元格设置下拉框,并根据选项改变背景颜色

    关于怎么在表格中单元格设置下拉框,并根据选项改变背景颜色 def table_combox_init(self):combox_statePlm_jria_list = ['', '无', 'O', ...

  5. html中背景图按比例缩放全屏显示

    html中背景图按比例缩放全屏显示,核心代码如下div: <body style="height: 100%; margin: 0;" onload="create ...

  6. iphone中背景图的设置方法

    iphone中背景图的设置   方法一,使用一个UIImageView实例做子视图,并且放最后面 - (void)setBackgroundImage {       NSLog(@"set ...

  7. 选下拉框的的值对应上传相应的图片_如何在excel中实现,选择下拉菜单某一项,该表格中就出现选项对应的数据?(excel表格制作选择数据)...

    怎样从多个excel表格中提取数据,做数据分析图呢 1. 数据的.录入.表格的设置,效果如示. 2.如图所示,选进行分析的图据范围 3.如图所示,点击菜单栏目上的"插入",选择&q ...

  8. Excel表格中如何快速生成下拉菜单

    Excel表格中如何快速生成下拉菜单 目录 Excel表格中如何快速生成下拉菜单 1.例如下表先手动输入前几组的"等级"类别"优良中差" ​2.同时按住 alt ...

  9. easyui下拉框option写死_JavaScript_jQuery+easyui中的combobox实现下拉框特效,1.第一种写法:Input框中显示: - phpStudy...

    jQuery+easyui中的combobox实现下拉框特效 1.第一种写法:Input框中显示: 2. 第二种用法,在list列表中显示: 类别 3. 第二种的另一种写法: 类别 以上3种方法均可实 ...

最新文章

  1. 架构师之路 — 数据库设计 — 关系型数据库的外键约束与关联
  2. 微信小程序 html css xml,微信小程序 使用towxml解析html流程及踩坑记录
  3. Windows下在xampp中配置DVWA
  4. Protel中的快捷键使用(网上资源)
  5. python基本随机数生成函数有_Python中生成随机数的常用方法
  6. 为有朝一日自己弄个玩具玩而准备
  7. c语言 连接两个字符串不使用库函数
  8. 新版ubuntu中打开终端的方法和安装ssh 的方法
  9. 操作系统中分页、分段、交换空间、页面置换算法等相关概念
  10. Delphi创建对象时,Application、Self、nil三者的区别
  11. 虚拟机克隆后如何修复网络、主机名等问题
  12. 如何将商业策略与项目管理相关联
  13. 格式化输出函数(2): FormatDateTime
  14. 大学学习路线规划建议贴
  15. 个体工商户属于小微企业吗_个体户属于小微企业吗?
  16. Vue3警告:[Vue warn] Extraneous non-emits event listeners (changeParentProps) were passed to component
  17. android优化最强软件,手机提速谁最行?十款安卓优化软件比拼
  18. 孩子握笔姿势错误也易致近视
  19. 2017-5-11 公司客户考察篇
  20. win7显示dns服务器故障,Win7怎么解决DNS服务器故障?

热门文章

  1. QQ内置浏览器菜单栏设定
  2. 女生拒绝男生的潜台词!!
  3. 大数据-数据处理分类篇
  4. 关于矿井地面电力综合自动化系统的研究与产品选型
  5. 深度学习(增量学习)——(ICCV)Striking a Balance between Stability and Plasticity for Class-Incremental Learning
  6. linux 开发板通过网线连电脑上网的方法和配置步骤
  7. R语言计算欧几里得距离(Euclidean Distance)实战:两个向量的欧几里得距离、dataframe两个数据列的欧几里得距离
  8. Linux上nginx配置SSL协议非80、443端口自动跳往https端口
  9. Linux os Nginx 配置https 自定义端口非443端口
  10. SCAN算法 | 磁头引臂调度问题 | 双磁头进阶 | Java实现(详细注释)