纵享丝滑滑动切换的周月日历,水滴效果,可高度定制,仿小米日历
老规矩先贴效果图
github地址,觉得有帮助的可以给个 star 呗
github.com/idic779/mon…
添加依赖
compile ‘com.github.idic779:monthweekmaterialcalendarview:1.5’
具体如何使用看这里
这个库可以做什么?
可以控制是否允许左右滑动,上下滑动,切换年月
流畅的上下周月模式切换
自定义日历样式
基于material-calendarview 这个库实现,可以根据需求定制效果
之前开发任务中有涉及到年月日日历的切换效果,由于是需要联动,想到的方向大概有3种,要么通过处理
view
的touch
事件,要么是通过自定义behavior
去实现,要么是通过ViewDragHelper
这个神器去实现,网上比较多的是通过自定义bahavior
去实现,本文使用的是第三种方法,实现的是一个可高度定制自由切换的周月日历视图,提供一种思路去实现页面联动效果。准备
由于重点实现的是年月切换的效果,本来想着说可以自己写一个日历组件然后再加上
ViewDragHelper
,应该可以实现周月联动的效果吧?后面想了想,重点在切换那就干脆直接找个开源库稳定性好点的日历组件,所以用github.com/prolificint…快4000start的库吧,
ViewDragHelper
,作为一个神器可以做很多的事情,官方的DrawerLayout
,BottomSheetBehavior
用他来实现,为什么用它?对于拖动某个View
,如果是自己去重写touch
事件的,计算滑动距离再去移动View
会需要处理比较多繁琐的代码去实现。如果我们用ViewDragHelper
的话能很轻易的实现这样的效果。
简单的介绍下ViewDragHelper
ViewDragHelper helper= ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {@Overridepublic boolean tryCaptureView(View child, int pointerId) {return true;}@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx){return left;}
@Overridepublic int clampViewPositionVertical(View child, int top, int dy){<span class="hljs-built_in">return</span> top;}@Overridepublic int getViewHorizontalDragRange(View child) {<span class="hljs-built_in">return</span> super.getViewHorizontalDragRange(child);}@Overridepublic int getViewVerticalDragRange(View child) {<span class="hljs-built_in">return</span> super.getViewVerticalDragRange(child);}@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {super.onViewPositionChanged(changedView, left, top, dx, dy);}@Overridepublic void onViewReleased(View releasedChild, <span class="hljs-built_in">float</span> xvel, <span class="hljs-built_in">float</span> yvel) {super.onViewReleased(releasedChild, xvel, yvel);} });
tryCaptureView()
:如果返回true,则说明可以捕获该view,我们可以在这里设置捕获的条件clampViewPositionHorizontal ()
clampViewPositionVertical()</code>:
分别对<code>child</code>水平和竖直方向移动的边界进行控制,例如限制周月移动的距离可以在这里做处理</li>
<li><code>onViewPositionChanged()</code> : 当<code>child</code>的位置发生移动时候会回调这个方法</li>
<li><code>onViewReleased()</code>:手指释放时候的回调</li>
<li><code>getViewHorizontalDragRange()getViewVerticalDragRange():返回child
横向或者纵向移动的范围,大于0才能捕获。
更多的可以参考鸿洋的Android ViewDragHelper完全解析 自定义ViewGroup神器
如何实现
既然选择
ViewDragHelper
要实现周月联动呢,我们来理一理要实现的效果,在月视图的时候,能够把下面的recyclerView
上移拖到到周视图的高度,上移过程如果超过一定距离就默认滚动到周视图。 在周视图的的时候又能把recyclerView
下移拖动到月视图的高度位置,下移过程如果超过一定距离就默认滚动到月视图。整体分析
整个页面是由顶部的周名字的
View
、周模式的MaterialCalendarView
、月模式的MaterialCalendarView
和最下面的recyclerView
组成 需要注意的是MaterialCalendarView
这个库原来是有周名字还有顶部显示日期的, 需要注意的是这里稍微做了下修改把这些给隐藏掉了,具体可以看MaterialCalendarView.setTopbarVisible()
。并且做了下修改增加了获得单行的高度方法MaterialCalendarView.getItemHeight()
,即为周模式时显示的高度。具体实现
- 拖动前处理 整个页面只有
recyclerView
,月模式下如果向上拖动时候如果recyclerView
不是滚动到了顶部的话那么就不允许拖动,相关代码
@Overridepublic boolean tryCaptureView(View child, int pointerId) {return !mDragHelper.continueSettling(true)&&child == mRecyclerView && !animatStart&& isAtTop(mRecyclerView) && !ViewCompat.canScrollVertically(mRecyclerView, -1);}
- 限制
recyclerView
移动的高度在周模式和月模式之间
@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {//决定竖直方向上能移动的距离为 finalWeekModeHeight到finalMonthModeHeightint topBound = finalWeekModeHeight;int bottomBound = finalMonthModeHeight;int newTop = Math.min(Math.max(top, topBound), bottomBound);return newTop;}
- 在
onMeasure
获得初始的一些数据值,包括周模式的高度,月模式的高度,最大移动的距离,单行的高度
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);calendarItemHight = mCalendarViewMonth.getItemHeight();calendarWeekHight = calendarItemHight;if (defaultStopHeight == 0) {defaultStopHeight = getCurrentItemPosition(CalendarDay.today()) * calendarItemHight;}calendarMonthHight = mCalendarViewMonth.getMeasuredHeight();weekViewHight = mTopWeekView.getMeasuredHeight();finalMonthModeHeight = weekViewHight + calendarMonthHight;finalWeekModeHeight = calendarItemHight + weekViewHight;maxOffset = calendarMonthHight - calendarItemHight;}
然后在
onlayout()
把布局里的View
绘制到对应的位置上面最大移动的距离defaultStopHeight在选中日期时候就会通过
getCurrentItemPosition()
计算出它点击所在的行数再调用setStopItemPosition()
就可以得到要停止下来的高度,接下来说下最关键的地方 既然是周月联动我们发现在拖动
recyclerView
视图的时候我们会不停回调onViewPositionChanged()
这个方法,我们在这个方法里面就可以根据recyclerView
移动的距离来移动对应的月视图,
//滑动处理private void HandlerOffset(View changedView, int left, int top, int dx, int dy) {//获取日历相对手指移动的相对距离 dy向上移动小于0transY = transY + dy;if (transY > 0) {transY = 0;}if (transY < -calendarMonthHight - calendarItemHight) {transY = -calendarMonthHight - calendarItemHight;}
<span class="hljs-built_in">float</span> abstransY = Math.abs(transY);<span class="hljs-keyword">if</span> (dy < 0) {//如果上滑动,并且滑向动的绝对值距离在超过calendarHight-defaultStopHeight// 并且小于可以滑动的距离calendarHight-calendarItemHight之间的话<span class="hljs-keyword">if</span> (abstransY >= (calendarMonthHight - defaultStopHeight) && abstransY < calendarMonthHight - calendarItemHight) {<span class="hljs-keyword">if</span> (!animatStart) {mCalendarViewMonth.setTranslationY(getOffset((int) mCalendarViewMonth.getTranslationY() + dy, calendarItemHight - defaultStopHeight));}}}<span class="hljs-keyword">if</span> (dy > 0) {<span class="hljs-keyword">if</span> (abstransY < maxOffset&& currentMode.equals(Mode.WEEK)) {mCalendarViewWeek.setVisibility(INVISIBLE);}<span class="hljs-keyword">if</span> (abstransY < maxOffset) {mCalendarViewMonth.setTranslationY(getOffset((int) mCalendarViewMonth.getTranslationY() + dy, 0));}}}
月视图的移动我们是通过
setTranslationY
来移动的,为了防止滑动时候过快通过getOffset()
限制一下它滑动的最大距离。- 在松开手指的时候我们在
onViewReleased()
做相关状态的改变,如果滑动的距离超过一定的值就把当前视图置为月模式还是周模式@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {int moveY = finalMonthModeHeight - mRecyclerView.getTop();//周模式距离滑动为一行的高度,超过就滑动到周位置int weekdistance = calendarItemHight;//最大滑动距离int maxDistance = calendarMonthHight;if (currentMode == Mode.MONTH) {//如果滑动距离超过当前选中项和最大滑动距离之间的距离if (moveY > weekdistance && moveY < maxDistance) {//变为周模式setMode(Mode.WEEK);} else if (moveY <= weekdistance) {//变为月模式setMode(Mode.MONTH);}} else {//周模式下距离顶部选中日期的距离小于最大滑动距离-10的话就让它变为月模式if (moveY > maxOffset - 10) {//变为周模式setMode(Mode.WEEK);} else if (moveY <= maxOffset - 10) {//变为月模式setMode(Mode.MONTH);}}}
需要注意的是在
onInterceptTouchEvent()
如果是月模式并且可以拖动的时候, 底部的recyclerView
是不允许滑动的if (currentMode == Mode.MONTH&& canDrag) { setRecyclerViewCanScroll(false); }
还可以怎么用
接下来说下你可以怎么去定制?如果你想替换项目中的月和周视图的话,不想用Material-calendarview ,很简单,只需要你自己的周月视图必须有一个方法获得单行日历的高度(例如我的库中的MaterialCalendarView.getItemHeight() ),然后把这个月视图和周视图,分别在
MonthWeekMaterialCalendarView
里面按照顺序放到对应位置即可。然后再setListener()
里面设置相关的回调处理,例如日期选中或者月份切换的回调等。好的大工告成。
转自:https://juejin.im/post/5a631efd6fb9a01ca8720f80
纵享丝滑滑动切换的周月日历,水滴效果,可高度定制,仿小米日历相关推荐
- 纵享丝滑滑动切换的周月日历,可流畅滑动高度定制,仿小米日历,基于 material-calendarview
monthweekmaterialcalendarview 项目地址:idic779/monthweekmaterialcalendarview 简介:纵享丝滑滑动切换的周月日历,可流畅滑动高度定制 ...
- 纵享丝滑滑动切换的周月日历,水滴效果,丰富自定义日历样式,仿小米日历(ViewDragHelper实现)...
本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发 老规矩先贴效果图 github地址,觉得有帮助的可以给个 star 呗 github.com/idic779/mo ...
- 纵享丝滑滑动切换的周月日历,水滴效果,丰富自定义日历样式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QF0ojEiz-1650020556182)(https://user-gold-cdn.xitu.io/2018/2/ ...
- android 涂鸦 卡顿,涂鸦框架的优化——解决绘制时的卡顿问题,纵享丝滑
前言 V5.5: 增加优化绘制的选项,可优化绘制速度和性能,纵享丝滑. boolean optimizeDrawing = true; // 是否优化绘制,建议开启,可优化绘制速度和性能. Doodl ...
- typora+picgo+gitee搭建免费图床纵享丝滑
typora+picgo+gitee搭建免费图床纵享丝滑 0.写在前面 由于之前自己在github搭了自己的博客,伴随之而来的一系列问题.如github不显示图片,github图床加载太慢等一系列问题 ...
- 让你的小米5纵享丝滑,可能是最快的小米5rom
小米5刷原生7.1.1 ROM.配合xposed框架模块,非常的流畅!用纵享丝滑形容真不为过. 此标题是根据我的多次刷机实践得来的结果.话不多说先上几张GIF. 下面我上资源和教程: 首先手机要解锁刷 ...
- android 仿小米日历 周视图 月视图切换
android 仿小米日历,周视图左右滑动,月视图左右滑动,周视图月视图无缝切换: http://download.csdn.net/detail/chen352602412/9556162 插播广告 ...
- 阿里云数据库专家白宸:Redis带你尽享丝滑!(图灵访谈)
访谈嘉宾: 本名郑明杭,现阿里云NoSQL数据库技术专家.先后从事Tair分布式系统.Memcached云服务及阿里云Redis数据库云服务开发,关注分布式系统及NoSQL存储技术前沿. 作为嘉宾,曾 ...
- 【达摩院OpenVI】几行代码,尽享丝滑视频观感
团队模型.论文.博文.直播合集,点击此处浏览 随着网络电视.手机等新媒体领域的快速发展,用户对于观看视频质量的要求也越来越高.当前市面上所广为传播的视频帧率大多仍然处于20-30fps,已经无法满足用 ...
- 阿里云数据库专家白宸:Redis带你尽享丝滑!
本文仅用于学习和交流目的,不得用于商业目的.非商业转载请注明作译者.出处,并保留本文的原始链接:http://www.ituring.com.cn/art... 访谈嘉宾: 本名郑明杭,现阿里云NoS ...
最新文章
- mysql中leave和_MySQL数据库之Mysql存储过程使用LEAVE实现MSSQL存储过程中return语法
- Linux_系统破坏性修复实验
- 深入理解strncpy这个函数
- C/C++-style输入输出函数
- 使用log4jdbc记录SQL信息
- 限制ALV报表的导出权限
- 《虚拟化与云计算》读书感(九)服务器虚拟化的其他核心技术
- 微软发布首版基于 Chromium 79 的 Edge 浏览器
- 如何查看有没有django及版本
- 知乎每日精选python阅读脚本
- java写安卓脚本,一文全懂
- 猿猿趴架构实战--02 软件工程及架构师
- 南卡、ikf蓝牙耳机怎么样?南卡、ikf两款国产高性价比蓝牙耳机对比评测
- ASEK711KLC-25AB-T霍尔效应线性电流传感器SOIC8
- 操作系统2015(四川大学软件学院)
- 仿微信图片查看器入场退场动画
- CSS3变形透视动画总结
- CV中直方图比较方法
- 愚人节,60条短信祝你笑口常开……
- PHP基础知识 - PHP 使用 MySQLI
热门文章
- 使用 COLOR THIEF 获取图片主色,实现图片渐变遮罩,颜色填充等
- chrome突然无法复制粘贴了
- 博客怎么写出好的文章吸引读者,只有7个基本的写作技巧
- Dialog dismiss 失效的问题,
- 任天堂游戏 html5,明年的预备阵容!任天堂承诺却还没出的作品
- 王强 河南大学计算机学院,王强-河南大学生命科学学院
- rust怎么建柱子_原神慈盐之末任务怎么做?原神钟离传说任务的方碑柱子点亮顺序...
- CIP4和JDF,您知道多少?(转)
- ios审核要注意的地方(转)
- python_10_绘制图表