废话不多说,先上效果效果酷炫,动画丰富,效果爆炸boom~设计思路看腻了市面上各种丑陋难看的时钟控件,是时候整点新活!将现实生活中的摆钟圆形表盘设计、电子手表的数显表盘设计抽象出来,提取出“圆形”、“数显”、“时光流逝感”等词汇,融合这些词汇特征,把特征赋予最终的UI设计......就这样,一个炫酷的UI控件诞生了!拨动时钟圆盘可以调整时钟,伴随时间的流逝,拨动的圆盘还能自动回位,交互逻辑自然顺畅。设置不同的主题色即可体现更多的内涵,“静谧”、“夜晚”、“月夜”、“纯净”等等,控件设计本身的可扩展性非常好。实现方案设计思路清晰明确之后,就要考虑如何实现了。来人,上口号。?没有人?比我?更懂☝️实现类设计从UI图中可以观察到,时钟控件由四个大表盘组成,分别是上下午表盘、小时表盘、分钟表盘、秒钟表盘。在实现思路上首先考虑抽象出圆盘控件父类DiskView,其余表盘均继承自DiskView即可。有了各种各样的表盘,最后再用ViewGroup将其进行组装。而DiskView作为基类,需要承担动画、拖动、点击等交互的逻辑,同时还要具备表盘的公共属性,例如表盘半径radius、表盘旋转角度degree等。

public class DiskView extends View {    private static final String TAG = "DiskView";    Context mContext;    /**     * 圆盘半径     */    int mRadius = 0;    /**     * 手指第一次按下时的坐标     */    float startX, startY;    /**     * 当前手指按下点的坐标     */    float curX, curY;    /**     * 第一次手指按下的点与初始位置形成的夹角     */    int startDegree;    /**     * 手指按下的点与初始位置形成的夹角     */    int curDegree;    /**     * 圆盘当前位置相对初始位置的角度,初始位置角度为0度     */    int degree = 0;    /**     * 手指抬起后是否需要回归原来的状态     */    boolean isNeedReturn = true;    ValueAnimator animator;}

UI绘制有了坐标、角度、半径、颜色等属性定义,接下来考虑绘制。绘制采用canvas的图形绘制api,计算好各个图形的位置,赋予对应的颜色。调用rotate方法围绕圆心绘制具有一定角度的文字。需要注意的是,绘制文字时要确保文字中线经过圆盘圆心。

@Overrideprotected void onDraw(Canvas canvas) {    super.onDraw(canvas);    //画圆盘    mPaint.setColor(diskColor);    canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);    //画数字    mPaint.setColor(numColor);    Rect bounds = new Rect();    for (int i = 0; i < 60; i++) {        if (i == minute) {            mPaint.setColor(selectNumColor);        } else {            mPaint.setColor(numColor);        }        if (i % 10 != 0) {            if (i % 5 == 0) {                canvas.drawCircle(mRadius, 2 * mRadius - textHeight * 3 / 2, DisplayUtils.sp2px(mContext, 20) / 4, mPaint);            } else {                canvas.drawCircle(mRadius, 2 * mRadius - textHeight * 3 / 2, DisplayUtils.sp2px(mContext, 20) / 6, mPaint);            }        } else {            mPaint.getTextBounds(i + "", 0, (i + "").length(), bounds);            textHeight = bounds.height();            canvas.drawText(i + "", mRadius - bounds.width() / 2, mRadius * 2 - bounds.height(), mPaint);        }        canvas.rotate(-6, mRadius, mRadius);    }}

交互逻辑控件交互逻辑大部分都在onTouchEvent的回调中进行处理,分别对用户的点击、移动、抬起动作做针对性处理,核心关键在于计算好各个情况的圆盘角度,之后再通过animator计算好对应的数值,实时刷新界面即可。需要注意的是用户的起始落点不能超过圆盘的界限,在单独使用某一个圆盘控件时要考虑边界限制。

@Overridepublic boolean onTouchEvent(MotionEvent event) {    curX = event.getX();    curY = event.getY();    switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            startX = event.getX();            startY = event.getY();            startDegree = computeCurrentAngle(curX, curY);            //起始落点不能超过圆盘界限            if (Math.sqrt(                    (startX - mRadius) * (startX - mRadius) + (startY - mRadius) * (startY - mRadius)            ) > mRadius) {                startDegree = 0;            }            break;        case MotionEvent.ACTION_MOVE:            //起始落点不能超过圆盘界限            if (Math.sqrt(                    (startX - mRadius) * (startX - mRadius) + (startY - mRadius) * (startY - mRadius)            ) > mRadius) {                return false;            }            curDegree = computeCurrentAngle(curX, curY);            postInvalidate();            break;        case MotionEvent.ACTION_UP:            if (Math.sqrt(                    (startX - mRadius) * (startX - mRadius) + (startY - mRadius) * (startY - mRadius)            ) > mRadius) {                return false;            }            int tmpDegree = degree;//手指按下前的圆盘角度            degree = degree + curDegree - startDegree;            if (Math.abs(degree) > 360) {                degree %= 360;            }            startDegree = 0;            curDegree = 0;            startX = 0;            startY = 0;            //是否需要回位            if (isNeedReturn) {                animator = ValueAnimator.ofInt(degree, tmpDegree);                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                    @Override                    public void onAnimationUpdate(ValueAnimator animation) {                        degree = (int) animation.getAnimatedValue();                        postInvalidate();                    }                });                animator.setDuration(200);                animator.setInterpolator(new DecelerateInterpolator());                animator.start();            }            break;    }    return true;}

后记自定义控件开发作为Android开发中的重要一环,如何利用好各个api实现功能是一方面,如何自顶向下进行设计才是重点。在开发之前最关键的事情并不是构思如何实现、如何设计,而是去发掘用户的需求,从需求倒推功能,再从功能角度考虑如何进行设计,最终呈现给用户。

技术交流,欢迎加我微信:ezglumes ,拉你入技术交流群。

推荐阅读:

音视频面试基础题

OpenGL ES 学习资源分享

开通专辑 | 细数那些年写过的技术文章专辑

NDK 学习进阶免费视频来了

推荐几个堪称教科书级别的 Android 音视频入门项目

觉得不错,点个在看呗~

android 根据bounds坐标进行点击操作_炫酷的Android时钟UI控件,隔壁产品都馋哭了...相关推荐

  1. android 控件随手指移动_液体流动控件,隔壁产品都馋哭了

    作者:彭也 链接: https://www.jianshu.com/p/4f0844c72e8a 模拟液体流动的展开特效,适合一些需要侧边展开进行辅助说明的页面,如用户在填写某个表单,需要操作很多步骤 ...

  2. Android UI控件和布局

    说明: 本文是郭霖<第一行代码-第3版>的读书笔记 4.1 如何编写程序界面 编写XML,这是传统的方法 ConstraintLayout,Google推出的新方法,可以在可视化编辑器中拖 ...

  3. Android开发详解:第4章《UI 控件》

    Android开发详解:第4章<UI 控件> 控件是Android程序设计的基本组成单位,通过使用控件可以高效地开发Android应用程序.所以熟练掌握控件的使用是合理.有效地进行Andr ...

  4. android 画布裁剪,一种基于Android系统对UI控件进行轮廓剪裁及美化的方法与流程...

    本发明涉及Android应用的技术领域,特别涉及一种基于Android系统对UI控件进行轮廓剪裁及美化的方法. 背景技术: 目前,随着智能电视的普及,Android应用层出不穷,而那些表现形式单一.传 ...

  5. android listview 滑动条显示_第七十六回:Android中UI控件之RecyclerView基础

    各位看官们,大家好,上一回中咱们说的是Android中UI控件之ListView优化的例子,这一回咱们说的例子是UI控件之RecyclerView.闲话休提,言归正转.让我们一起Talk Androi ...

  6. Android提供了哪些主要UI控件,Android必备:Android UI控件的了解与学习

    因为工做须要,最近一段时间,须要进行Android App开发的学习,以前简单的进行过Android的了解,对于基本的Android环境的搭建等已经有过整理,一个Android App是由一个或多个A ...

  7. android高德地图上加自定义菜单,自定义UI控件-UI界面定制-开发指南-Android 导航SDK | 高德地图API...

    关于自定义 UI 布局,您还可以参考官方Demo--完全自定义UI导航. 单元素自定义 可以通过AMapNaviViewOptions中如下接口进行单UI元素显示隐藏,只列出部分接口,更多功能请参考A ...

  8. 课堂笔记:Android UI控件

    常用的UI控件: TextView: <TextViewandroid:layout_width="wrap_content"android:layout_height=&q ...

  9. Android开发 入门篇(二) - 常用UI控件

    文章目录 控件 Button TextView EditText ImageView ProgressBar AlertDialog ProgressDialog 布局 LenearLayout an ...

最新文章

  1. DEV开发之控件NavBarControl
  2. WPF and Silverlight 学习笔记(十):WPF控件模型
  3. java 项目使用 ajaxfileupload
  4. 8.VMware View 4.6安装与部署-connection server(View Transfer Server)
  5. WebFlux基础之响应式编程
  6. 机器学习如何应用到实际生活和创业中
  7. Python中bytes和str区别详细介绍
  8. 【译】ES2018 新特性: 正则表达式的 s (dotAll) 标志
  9. 计算机实现数论 奇偶排列问题
  10. php程序员试卷无答案,2019年最新PHP经典面试题及答案,PHP程序员必看
  11. 使用h5py操作hdf5文件
  12. 如何在linux中也能够使用自动类型推导关键字auto?
  13. 使用Fiddler进行http抓包和调试
  14. win7计算机怎么录屏,win7电脑怎么录屏,什么电脑录屏软件好用?
  15. jmail qq邮箱的服务器,asp jmail qq邮箱发送邮件方法
  16. Nanopore 16S测序数据分析流程之blast/last
  17. EXCEL数据格式,字符型空值““参与计算、数值为0时单元格显示为空(解决了无法使用value()函数将字符型空值““转换为数字型的问题)
  18. 各类dp的总结+例题
  19. 初学SLAM二之BA当中的数学知识点
  20. outlook中网址连接打不开解决办法

热门文章

  1. PyODPS开发中的最佳实践
  2. 产品经理教你玩转阿里云负载均衡SLB系列(一):快速入门--什么是负载均衡
  3. 大咖说中台 | 建设数据中台系列(五)——中台架构详解(下)
  4. 突发!Python再次卫冕,Java和C下降,你怎么看?
  5. 百度Q2智能云增长强劲;据悉史上最大 AI 芯片诞生!中兴与奇瑞成立合资公司一起加快开发5G汽车……...
  6. Storm精华问答 | 为什么要用Storm?不用Spark?
  7. 只了解View的事件分发是不够的,来看下输入系统对事件的处理
  8. Linux里怎么进行路由跟踪,[Linux] traceroute 路由跟踪指令用例
  9. eq linux_音乐家和音乐爱好者的开放硬件 | Linux 中国
  10. yarn全局安装vue/cli vue不是内部命令