内容简介:产品要做一个支持最开始的想法时用MPAndroidChart来做,可用这个库有些细节满足不了产品的需求 如选中的label标签要用选中颜色及回滚功能,然后就很没底,找了很多类似功能的自定义控件的类比,做之前也咨询了一位大佬(在此感谢扔物线大神),觉得薄荷尺子的逻辑和这个需求很类似,就决定用自定义view来实现。自己以前写过的自定义view都比较简单,自己刚开始做的时候压力挺大的,挺担心自己做不出来影响项目进度的,不过一时也没有好的办法,只能逼着自己去做,主要参考之前仿写薄荷尺子的大神的博客,做了四天下来,总
产品要做一个支持 横向滚动 中心区域选中 惯性滚动 停止时回滚到中心位置 点击选中 的图表需求 效果图如下:
最开始的想法时用MPAndroidChart来做,可用这个库有些细节满足不了产品的需求 如选中的label标签要用选中颜色及回滚功能,然后就很没底,找了很多类似功能的自定义控件的类比,做之前也咨询了一位大佬(在此感谢扔物线大神),觉得薄荷尺子的逻辑和这个需求很类似,就决定用自定义view来实现。自己以前写过的自定义view都比较简单,自己刚开始做的时候压力挺大的,挺担心自己做不出来影响项目进度的,不过一时也没有好的办法,只能逼着自己去做,主要参考之前仿写薄荷尺子的大神的博客,做了四天下来,总算有点眉目,把demo拿给产品过目也比较满意,这个效果的实现也渐渐领略到开源的魅力,看到自己做出来的效果贼开心贼有成就感,周末打算分享出来,希望能对大家有所帮助,项目中有什么问题请不吝赐教,感激不尽。 目前有些代码可能还不够完善,后续还需要处理嵌套滚动的问题,但主体思路已经比较清晰了
话不多说,效果如下:
源码地址: github.com/SilenceBurs…参考博客:
之前仿写薄荷尺子的大神 很多代码甚至注释都被我毫不留情的copy过来了 :grin: blog.csdn.net/totond/arti…
scoller相关及多点触控相关 请看其系列博客 blog.csdn.net/u012422440/…
根据实现的步骤拆分为如下功能点
- 自定义属性的设置及使用
- draw 绘制图表
- 触摸控制并处理多指触控问题(手指拖动图表可移动)
- 惯性滚动(根据手指释放时的速度计算图表需要滚动的距离)
- 回滚 (up时或者惯性滚动结束 需要回滚到选中位置)
- 点击选中 (根据点击的坐标,计算需要选中的下标并选中)
1.自定义属性的设置及使用
在attr文件中声明该控件的一些自定义属性,在构造方法中解析,设置控件的属性即可
2. draw 绘制图表
绘制图表其实主要时数学问题,具体坐标的计算就不再赘述了
请教扔物线的时候,我问他会不会有性能问题,他就说了一点, 屏幕外不要绘制 我们就只需绘制屏幕上用户看到的内容即可,之前之后的就不用绘制了
但由于如果只绘制屏幕显示区域的话,左右两侧的点需要计算path连接而且在滚动时文字的显示会有突然显示或隐藏的问题,所以把绘制区域加长,左右两侧均多绘制一个label的距离 绘制区域为绿色加红色
我们根据x轴方向当前已滚动的距离getScrollX()计算第一个显示的label下标,再加上控件宽度和一个label距离(右侧多绘制的一个label的距离)计算出最后一个label的下标,只需要绘制两个下标中间即可,其他的就是数学问题了。
多个点的连接使用的贝塞尔曲线,代码参考自: www.jianshu.com/p/98088ff77…
3. 触摸控制并处理多指触控问题(手指拖动图表可移动)
触摸控制是根据第一个event点移动的距离,调用view的scrollBy方法滚动view,主要代码如下
//处理滑动 计算现在的event坐标和上一个触摸事件的坐标来计算偏移量 决定scrollBy的多少 @Override public boolean onTouchEvent(MotionEvent event) { ... switch (event.getAction()) { case MotionEvent.ACTION_DOWN: ... //记录首个触控点的id mActivePointerId = event.findPointerIndex(event.getActionIndex()); ... mLastX = event.getX(); ... break; case MotionEvent.ACTION_MOVE: if (mActivePointerId == INVALID_ID || event.findPointerIndex(mActivePointerId) == INVALID_ID) { break; } //计算首个触控点移动后的坐标 float moveX = mLastX - event.getX(mActivePointerId); if (Math.abs(moveX) > IGNORE_MOVE_OFFSET) { ... mLastX = event.getX(mActivePointerId); scrollBy((int) moveX, 0); } break; case MotionEvent.ACTION_UP: mActivePointerId = INVALID_ID; mLastX = 0; ... break; case MotionEvent.ACTION_CANCEL: mActivePointerId = INVALID_ID; mLastX = 0; ... break; } return true; } 复制代码
scrollBy方法内部会调用scrollTo方法,重写了scrollTo方法在里面进行一些选中下标的判断和最小最大滚动位置的拦截
@Override public void scrollTo(int x, int y) { //默认左边缘为x最小值-半个控件的宽度 if (x < mMinPosition) { x = mMinPosition; } //默认右边缘为x最大值+半个控件的宽度 if (x > mMaxPosition) { x = mMaxPosition; } if (x != getScrollX()) { super.scrollTo(x, y); } mSelectIndex = scrollX2Index(x); } 复制代码
注意在move事件中需要根据第一个触控点id计算移动距离,直接调用event.getX()方法,会有多点触控问题(复现步骤:一个手指滑动后,按下第二个手指,第一个手指抬起,view会自动滚动) 因为后面会有点击事件的判断,所以在move时判断如果移动距离小于IGNORE_MOVE_OFFSET = 2.5时,忽略,这样当手机滑动比较慢时,会有部分滑动事件被忽略掉的情况,不过2.5这个值自己滑动时觉得体验还可以,再大的话慢速滑动会有卡顿,太小的话点击事件的判定会过于精确。
4. 惯性滚动(根据手指释放时的速度计算图表需要滚动的距离)
惯性滚动的实现需要用到VelocityTracker计算up事件时的速度,OverScroller处理fling事件 主要思路时,当up事件发生时,判断手指速度,若速度小于最小值, scrollBackToExactPosition()
直接将当前选中下标滚动到中心区域;若速度小于最大值按原速度计算否则按最大速度计算,根据此速度 当前x方向偏移量 可scrollTo的最小、最大值调用fling方法,并调用 invalidate();
方法, invalidate();
内部几次回调会调用view的draw方法,在view的draw方法中调用 computeScroll()
方法,若惯性滚动未结束,调用scrollTo方法将view滚动到该速度应滚动到的位置,再调用 postInvalidate();
,几次回调又会重新调用view的draw方法,循环调用scrollTo将view再进行滚动 如此实现惯性滚动 直至滚动结束
5. 回滚 (up时或者惯性滚动结束 需要回滚到选中位置)
这个主要也是数学题,需要回滚的距离过大时,使用OverScroller慢速回滚;若过小则立刻回弹
//触摸事件或惯性滚动结束后 应滚动到中心位置 private void scrollBackToExactPosition() { float rightPosition = mSelectIndex * mParent.getXLabelInterval() - (float) getWidth() / 2; if (Math.abs(getScrollX() - rightPosition) > IGNORE_OFFSET) { int dx = Math.round(rightPosition - getScrollX()); if (Math.abs(dx) > MIN_SCROLLER_DP) { //渐变回弹 mOverScroller.startScroll(getScrollX(), getScrollY(), dx, 0, 500); invalidate(); } else { //立刻回弹 scrollBy(dx, 0); 复制代码
6. 点击选中 (根据点击的坐标,计算需要选中的下标并选中)
点击事件的判定:最开始的想法是,判断事件如果是down紧接up即为点击,后来发现这种判定比较苛刻,因为有些点击事件会引起略微的move事件,所以在move事件中判断如果move距离较短,则忽略,这种方法的判定目前没有发现问题,如果大家有好的想法,欢迎讨论。 判定为点击事件后,要根据点击点的坐标位置和当前已滚动的距离,计算出点击点所在的下标,改变需要选中的下标,滚动到指定下标
这个控件的一点一个功能的实现,过程之中问题不断,问题解决又是惊喜,希望自己多些信心,多点努力,年后的第一篇博客,收拾行装,又上征程,加油,我们都是追梦人
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- JQuery选中select组件被选中的值方法
- JQuery选中select组件被选中的值方法
- python – Django检查是否选中了复选框
- 在ng-repeat内Checkbox默认选中
- Xshell 配置 鼠标选中即复制,右键即粘贴的功能
- 手撕一个让人 “欲罢不能” 的水波纹选中控件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Out of their Minds
Dennis Shasha、Cathy Lazere / Springer / 1998-07-02 / USD 16.00
This best-selling book is now available in an inexpensive softcover format. Imagine living during the Renaissance and being able to interview that eras greatest scientists about their inspirations, di......一起来看看 《Out of their Minds》 这本书的介绍吧!
MD5 加密
MD5 加密工具
html转js在线工具
html转js在线工具