前一段时间阳光小强安装了一个豆瓣客户端,第一次打开就被这种界面风格吸引了,今天早上起来在打开豆瓣听音乐的时候,突然产生一个念头,来试着实现一下这种效果,打开客户端分析了一下发现其实这种效果的实现并不是想象中的那么难,下面我先分析一下这种效果的实现思路,然后一步步解释实现的过程,希望大家能提出意见和建议,一起交流学习。

先给大家展示一下我的成果吧:

其实豆瓣客户端的界面上还有其他的文字和菜单,但是这两个的实现效果和其他几个类似,可以作为代表,所以就不绘制那么多组件了。

转载请说明出处:http://blog.csdn.net/dawanganban

一、分析界面的组成结构

有两个和我们手机屏幕尺寸大小相等的View(分别是灰色透明度变化的背景和主界面),假设屏幕的宽和高是w和h, 屏幕的坐标原点在左上角,这两个View相对于屏幕的坐标是

刚开始的坐标:

灰色背景: left 0  right w  top  -h  bottom  0

主界面:left 0  right w  top 0 bottom h

滑动到最底部(d为滑动到最底部的高度)

灰色背景: left 0 right w top -d bottom h-d

主界面: left 0 right w top h-d bottom 2h-d

接下来我们就要分析两个大问题:

1、滑动的具体实现

从上面的图上可以很容易的看出来,此时我们就要考虑如何实现界面上下滑动,观察豆瓣客户端的滑动手势发现支持滑动加速度检测(速度大于某值时直接从一端滑向另一端)、支持屏幕跟随手指滑动、屏幕的Y轴方向的中间是一个恢复位置的临界点。

从上面的分析我们基本上可以知道用到的技术有如下几个:

(1)监听Event_Move事件,通过scorllBy实现实时移动(跟随手指)。

(2)判断Event_Up时的手指位置,来判断是否恢复到原来位置。

(3)滑动的时候判断手指滑动的速度,来确定是否直接滑动到另一端(上端和下端)。

2、界面上元素的缩放和透明度的变化

界面上透明度变化的地方大致有这几处,滑动时上面的灰色背景透明度渐变(从上向下滑动变透明,从下向上滑动变灰),主界面上的文字透明度变化。

缩放的控件有主界面上的圆形图片和底部菜单(底部菜单是类似的实现,这里不做讨论),而且随着滑动位置从水平居中向左边移动并且变小。

透明度变化的实现其实很简单,只需要知道当前位置相对整个屏幕坐标的比例计算出来即可,现在比较难的是如何实现中间圆形图片的缩放和位置的移动。

可以简单的从上图中看出大概的变化规律,我们要参考的时屏幕的TOP和LEFT来确定圆形的位置。

二、实现过程详解

首先我们添加两个View(灰色界面和主界面)

 private void addChild(){addTopView();addCenterView();}
 private void addTopView(){View view = new View(context);view.setBackgroundColor(Color.GRAY);mTopView = view;  addView(mTopView);}private void addCenterView(){View view = new CustomCenterVIew(context);view.setBackgroundColor(Color.WHITE);mCenterView = view;addView(mCenterView);}

重写ViewGroup,然后再onLayout中对两个View进行布局(初始布局)

 @Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mTopView.layout(0, -mViewHeight, mViewWidth, 0);mCenterView.layout(0, 0, mViewWidth, mViewHeight);}

我们重点来看一下对屏幕事件的处理,下面是重写onTouchEvent方法

 private float mOldY;private VelocityTracker vTracker;@Overridepublic boolean onTouchEvent(MotionEvent event) {int disY;int vTrackY;float eventY = event.getY();obtainVelocityTracker(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mOldY = eventY;break;case MotionEvent.ACTION_MOVE:  disY = (int)(eventY - mOldY);if(disY > 0 && Util.getCenterViewPointY(mCenterView) >= mViewHeight){return true;}if(disY < 0 && Util.getCenterViewPointY(mCenterView) <= mViewPointY){return true;}mOldY = eventY;scrollBy(0, -disY);break;case MotionEvent.ACTION_UP:vTracker.computeCurrentVelocity(1000);vTrackY = (int) vTracker.getYVelocity();Log.e(TAG, "vTrack = " + vTrackY);if(Math.abs(vTrackY) > 6000){if(vTrackY > 0){moveToBottom();}else{moveToTop();}}else{int disPointY = Util.getCenterViewPointY(mCenterView) - mViewPointY;if(disPointY > mViewHeight / 2){moveToBottom();}else{moveToTop();}}break;}return true;}

在ACTION_MOVE事件中我们做了两个条件判断是为了防止滑动到最上边后或滑动到最下端还可以继续滑动(限定了一个滑动的范围),然后使用scrollBy滑动响应(手机滑动)的距离。

在ACTION_UP中主要做了两件事,一个是判断用户的手指滑动速度是否超出了一个临界值,如果超出则表明用户是想滑动到底的。另一个是判断是否手指滑动到了屏幕的中界线以外来处理滑动到底还是恢复到原来的位置。

为了实现平滑的滑动我们在moveToBottom和moveToTop中使用了computerScroll方法来实现平滑滑动效果。关于详细用法请参考我的另一篇博文:http://blog.csdn.net/dawanganban/article/details/23998781
接下来我们来看一下主界面View的实现,这个View其实是一个自定义View,我重写了onDraw方法来实现透明度和大小的变化(使用系统动画实现不了随着手指移动实时变化的效果)具体的实现如下:

 @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int currentNum = Util.getCenterViewPointY(this);Log.e(TAG, "currentNum = " + currentNum);int alpha = 255 - (int)((float)500 * (currentNum - CustomView.BOTTOM_MENU_HEIGHT) / maxNum);if(alpha > 0){titleTextPaint.setAlpha(alpha);float titleWidth = titleTextPaint.measureText(title);canvas.drawText(title, (mViewWidth - titleWidth) / 2, TITLE_TOP_MARGIN, titleTextPaint);}int beginX = (int)((mViewWidth - mCenterIconBitmap.getWidth()) / 2 - (float)CENTER_ICON_LEFT_GAP * (currentNum - CustomView.BOTTOM_MENU_HEIGHT) / maxNum);int beginY = (int)(CENTER_ICON_MARGIN - (float)CENTER_ICON_MARGIN * currentNum / maxNum);canvas.save();float scale = 1.6f - (float)currentNum / maxNum;canvas.scale(scale, scale, beginX + mCenterIconBitmap.getWidth() / 2, beginY + mCenterIconBitmap.getHeight() / 2);rectf.set(beginX, beginY, beginX + mCenterIconBitmap.getWidth(), beginY + mCenterIconBitmap.getHeight());canvas.drawBitmap(mCenterIconBitmap, null, rectf, bitmapPaint);canvas.restore();}

在上面的绘制中主要是计算大小和透明度来实现绘制中间圆形和文字的效果,现在我们运行的时候可以发现并不是我们所想的可以实现我们想要的效果,这个onDraw方法根本不会随着滑动调用,那么怎么办呢?我们可以让滑动的时候来通知自定义View的重绘(这里可以做一些优化)。

 @Overridepublic void computeScroll() {super.computeScroll();if(mScroller.computeScrollOffset()){scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}centerViewUpdate();}

看以看到在computeScroll的最后一行我们调用了一个centerViewUpdate方法来实现让自定义View和上面灰色界面透明度变化的重绘,代码如下:

 private void centerViewUpdate(){mCenterView.postInvalidate();float alpha = 1 - (float)(Util.getCenterViewPointY(mCenterView) - mViewPointY) / mViewHeight;if(alpha < 0){mTopView.setVisibility(View.GONE);}else{mTopView.setVisibility(View.VISIBLE);mTopView.setAlpha(alpha);mTopView.postInvalidate();}}

至此整个工作基本完成, 完整源代码请狂点 右下角跳舞的小人,加群后在群共享中获取,或者点此 下载

是男人就下100层【第六层】——高仿豆瓣客户端相关推荐

  1. Unity经典游戏教程之:是男人就下100层

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  2. 是男人就下100层【第五层】——换肤版2048游戏

    ---------------------------------------------------------------------------------------------------- ...

  3. 是男人就下100层【第五层】——2048游戏从源代码到公布市场

    上一篇<是男人就下100层[第五层]--换肤版2048游戏>中阳光小强对2048游戏用自己的方式进行了实现,并分享了核心源码,这一篇阳光小强打算将该项目的全部源码公开并结合这个实例在这篇文 ...

  4. 是男人就下100层【第四层】——Crazy贪吃蛇(2)

    在上一篇<是男人就下100层[第四层]--Crazy贪吃蛇(1)>中我们让贪吃蛇移动了起来,接下来我们来实现让贪吃蛇能够绕着手机屏幕边线移动而且能够改变方向 一.加入状态并改动代码 首先我 ...

  5. 是男人就下100层【第一层】——高仿微信界面(4)

    上一篇<是男人就下100层[第一层]--高仿微信界面(3)>中我们完成了登录,这一篇看完成登录后的一个短暂加载和引导界面. 加载界面: <RelativeLayout xmlns:a ...

  6. 《是男人就下100层》真的有隐藏剧情!B站up主数月破解,原作者点赞致谢

    边策 杨净 发自 凹非寺 量子位 报道 | 公众号 QbitAI <是男人就下100层>,曾经风靡一代的flash小游戏.炙手可热的休闲游戏之最. 它让多少人没日没夜地想去尝试" ...

  7. 是男人就下100层【第五层】——2048游戏从源码到发布市场

    上一篇<是男人就下100层[第五层]--换肤版2048游戏>中阳光小强对2048游戏用自己的方式进行了实现,并分享了核心源码,这一篇阳光小强打算将该项目的所有源代码公开并结合这个实例在这篇 ...

  8. cocos2d-x 是男人就下100层 附源码

    1.效果图: 玩法: 一个不断下降的小人,点击屏幕的left或者right控制小人的移动方向,尽可能生存久些.为什么要搞这个游戏呢?因为在2012年的8月份,我完成它的android版本,见<自 ...

  9. OpenGL2D小游戏——是男人就下100层

    2019独角兽企业重金招聘Python工程师标准>>> 是男人就下100层想必大家一定都玩过,在这里给大家简单介绍一下游戏规则. 游戏规则: 游戏人物从屏幕上方按一定速率下落,同时台 ...

最新文章

  1. 一文看尽各种 NLP 任务
  2. 六十五、Leetcode数组系列(上篇)
  3. cors解决ajax跨域
  4. 配置单臂路由、三层交换技术以及动态路由
  5. Spring Boot JPA的查询语句
  6. matlab delete、clf、cla、close、closereq删除对象
  7. AndroidStudio_android实现双击_3击_监听实现---Android原生开发工作笔记240
  8. 谷歌发布 XS-Leaks 漏洞知识库
  9. 数据结构上机实践第八周项目7—对称矩阵的压缩存储及基本运算
  10. Linux-vim常见命令
  11. Mac上修改hosts文件无效的解决方案
  12. 口袋小精灵JAVA版下载_口袋小精灵200合一
  13. Django期末考试复习
  14. 如何使用mac电脑远程你的windows电脑
  15. SEO关键词排名优化的核心因素
  16. 用Python绘制诱人的桑基图,一眼看透熬夜和狗粮的秘密...
  17. Vue3使用路由及配置vite.alias简化导入写法
  18. boot linux 分区 扩容,linux分区扩容
  19. 如何做好ERP项目启动会
  20. 常州网站服务器_常州云主机

热门文章

  1. 显示器的Overdrive设置
  2. 3D人物动画如何制作?DAZ Studio 4来帮你!
  3. Android类似于美图秀秀的拼图实现
  4. 中国机器人大赛-工程竞技组(摄像头搬运项目赛后总结)
  5. 在 macOS 平台上启动 MATLAB
  6. git版本管理(1)
  7. 移动软件开发 微信小程序 第四次实验
  8. php 图片转成数据流发送
  9. python制作音乐相册_装逼篇 | 抖音超火的九宫格视频是如何生成的,Python 告诉你答案...
  10. __weak类型函数