今日科技快讯

近日,文化部部署北京、上海、广东、浙江等地文化市场综合执法机构,对50家主要网络表演经营单位进行集中执法检查,虎牙直播、YY直播、龙珠直播、火猫直播、秒拍等30家内容违规的网络表演平台被依法查处。同时关停了“悟空TV”等11家手机表演平台。

作者简介

不知不觉又到周五,有了本公众号的陪伴,是不是感觉时间过得很快呢?提前祝大家周末愉快。

本篇是 frank909 的第六篇投稿了!今天他给大家细致地分析了自己的一个自定义View,思路很不错,希望大家喜欢。

frank909 的博客地址:

http://blog.csdn.net/briblue

前言

在 Dribble 上偶然看到了一组交互如下:

当时在心里问自己能不能做,答案肯定是能做的,不过我比较懒,觉得中间那个伸缩变化要编写很多代码,所以懒得理。后来,为了不让自己那么浮躁,也为了锻炼自己的耐心程度,还是坚持实现它了。这个过程,觉得自己还是有所收获,把握了一些想当然的细节,输理了对于自定义 View 的流程。

我将这个自定义 View,起了一个名字叫做 LoadButton。

这篇文章涉及到的知识点有如下:

1. 自定义 View 时的基本流程,包含 attrs.xml 中属性的编写,构造方法中属性的获取,onMeasure() 中尺寸的测量。onDraw() 中界面的实现。

2. 可以让 Android 初学者再次感受一次回调机制的美妙。

3. 属性动画的基本使用。

先确定尺寸

先观察 LoadView 的形态。

上面的显示的是两种形状,一个是圆角矩形,另外一个就是圆。两个形态尺寸区别是,高相同,宽度不一致。

我们再进一步分析形态 1。

形态 1 可以看成是左右两个半圆和中间一个矩形。再回顾下示例图片中的动画表现。

圆角矩形最终变成了一个圆。我们可以用线框图来渐进表现它。

当进行动画时,中间的矩形部分不停地缩小,当它缩小为 0 时,形态 1 就转变成了形态2。

上面的能够说明什么呢?说明 LoadButton 由 3 个部分组成,左右的半圆和中间的矩形,即使是 形态2 也可以看做是左右半圆和中间宽度为 0 的矩形组成。

细化尺寸

我们进一步讨论尺寸相关的情况。

我们知道对于普通开发者而言,自定义一个 View 测量尺寸的时候我们通常要关注的测量模式是 MeasureSpec.EXACTLY 和 MeasureSpec.AT_MOST 两种。要了解更多详细的信息可以阅读我写的这篇博:

长谈:关于 View Measure 测量机制,让我一次把话说完

http://blog.csdn.net/briblue/article/details/72190143

接下来,我们详细讨论一下这两种情况。

  • MeasureSpec.EXACTLY

当一个 View 的 layout_width 或者 layout_height 的取值为 match_parent 或 30dp 这样具体的数值时,这就表明它的测量模式是 MeasureSpec.EXACTLY。它已经获得了精确的数值了,按照常理我们是不应该再去干涉它,parent 给出的建议尺寸是什么,我们就把尺寸设置成什么,但是结合开发的实际情况来看,我们有一个底线,为了保证 LoadView 的完整性,也就是再差的情况下,parent 给出来的建议尺寸也不能小于 形态2。否则如下图情况就不是我们想要的了

  • MeasureSpec.AT_MOST

当一个 View 的 layout_width 或者 layout_height 的取值为 wrap_content 时,它的测量模式就是 MeasureSpec.AT_MOST,这个时候我们需要自己根据内容计算尺寸。而 LoadButton 的内容是什么呢?它的内容有 text 还有 加载成功或者加载失败的图片。因为图片大小在 形态2 中的圆形内可以确认。所以问题的关键就在于 LoadButton 文字内容宽高的尺寸测量。

text 内容自然是居中显示,然后它距离中间的 rect 上下左右间距也要考虑。这个时候的 rect 尺寸就是相对应的文字尺寸加上相对应方向上的 padding 值,这些 padding 值通过在 attrs.xml 中自定义属性然后在布局文件中赋予。

最后整体 LoadButton 尺寸自然是中间 rect 加上左右两个半圆的半径,但是这还不是最终的尺寸,最终的尺寸还是要和 parent 给的建议尺寸比较,不能大于它。

上面分析了尺寸测量相关,所以顺着思路进行的话,编码也只是水到渠成的事情了。

绘制

测量是在 onMeasure() 方法中进行,而绘制就是在 onDraw() 方法中进行的,这是 Android 开发者都知道的事情。所以这一节的重点在于 onDraw() 这个方法。

为了不给读者造成困扰,我先张贴自定的属性,及在构造方法中获取属性值的代码。其它的细节应该看名字就大概知道了。attrs.xml:

然后在 LoadButton 的构造方法中获取这些值。

形态1的绘制,借助于Path的力量

android 绘制图形离不开 Canvas,Canvas 可以直接绘制 直线、矩形、圆、椭圆,但是 LoadButton 的 形态1 怎么绘制呢?它是一个不规则的闭合图形,直接用 Canvas 的话肯定不行,所以得借助另外一个类 Path,Path 中文译做路径,可以专门处理这种情况,而且可以处理比这复杂的情况,具体情况请读者们自己查阅相应资料与教程。

我们再来观察 形态1 到 形态2 的转变过程。

这是个中间矩形从初始值变为 0 的过程,我们用 rectWidth 表示这个矩形的宽度值,因为在 onDraw() 方法中,LoadButton 尺寸确定,所以我们很容易得到它的中心点,所以我们可以中心点坐标为参考坐标,然后以 rectWidth 为变量创建一个 path,这个 path 实现了 LoadButton 的轮廓。

以 rectWidth 为变量建立 path 的好处时,当从 形态1 到 形态2 转变的过程,肯定是 rectWidth 数值变化的过程,而对于其它数值是不变的,所以重绘的时候 LoadButton 能够很轻松地处理这种情况。

我们到这一步的时候已经能够准确地绘制了 LoadButton 的轮廓。现在需要精确地绘制它的内容,只有这样才是完整的 LoadButton。

我们先需要给 LoadButton 定义一些状态。

LoadButton的状态

它们的状态转换如下:

LoadButton 的状态转换由用户点击按钮触发。所以 LoadButton 需要在内部设置一个 OnClickListenner。

1. 当在 Initial 状态下点击时,它会转换到 Folding 状态下。

2. Foding 状态结束后,由 形态 1 转变成形态 2。自然就进入了 Loading 状态。

3. Loading 状态有 3 个走向,加载成功后,用户通过相应 API 设置状态为 Successed。加载失败后,用户可以设置状态为 Error。如果在 Loading 状态下点击按钮,会进入 Paused 状态。

4. 在 Paused 状态下点击按钮,LoadButton 重新进入 Loading 状态。

5. 在 Successed 或者 Error 状态下点击按钮,将通过回调对象,通知调用者点击事件的发生。

我们在 LoadButton 的构造方法中设置这样的内部的 OnClickListenner。

状态的绘制

Initial 状态下其实就是中间一个 text 文本居中显示,相关代码如下:

Folding 状态其实就是不显示文字的 Inital 状态,不同的还有它的 rectwidth 每次重绘时会变小,最终会由 Initial 的 形态1 过渡到 Loading 状态下的 形态2。在 Initial 状态下点击按钮会调用一个动画,这个动画用于展示 形态1 到 形态2 的过程。

这里是一个典型的属性动画应用场景,通过不断改变属性 rectWidth 的值来进行重绘,而对于绘制这一方面,文章前面部分有说过 LoadButton 通过以中心坐标为参考,以 mRectWidth 为变量建立了一个 Path 来绘制轮廓。

另外,大家可以注意到,shrinkAnim 有一个监听器,我设置为了 LoadButton 本身。

在收缩动画结束的时候,我调用了 load() 方法用来将状态设置为 Loading,并进行加载动画。

我们先看看 Loading 状态下的绘制,它是 形态2 ,也就是在一个圆形内有一个正在加载无限循环的动画。思路也很简单,用进度条的背景色画一个圆圈,然后用进度条的前景色绘制相应角度的弧,并且这个弧的半径和进度条的半径一样。

上面有两个关键的变量 progressReverse 和 circleSweep。progressReverse 用来表示动画是否需要翻转,circleSweep 表示每次绘制的时候从起始角度扫描的角度。

正常情况下,起始角度是 270 度不变,如果动画翻转时,它是 270 + circleSweep 的值,具体为什么这样做,大家可以观看之前的图像来思考一下。

加载的动画自然也是属性动画控制的,这个动画让 circleSweep 从 0 到 360 之间不停地变化。并且在每次循环的时候,将 progressReverse 变量置反。

Paused 状态是当 LoadButton 在 Loading 状态下,用户点击了按钮,这个时候按钮会显示一个暂停图标。

至于显示方面,非常简单就是给一个 drawable 设置好 bound 范围然后显示。稍后我会给出代码。

Successed 状态和 Error 状态实现过程基本上是一致的。但是它们被点击的时候,需要通知点击者。所以我们需要定义一个回调接口。

LoadListenner.onClick() 方法中的参数,isSuccessed 为真告诉点击者加载成功了的信息。否则提示加载失败。needLoading() 方法用来告诉点击者当在 Paused 状态下点击按钮时,调用者应该重新加载了。

它们的显示代码如下:

另外,需要注意的是 Successed 和 Error 状态,需要开发者根据实际情况决定调用。

将 LoadButton 重置为 Initial 状态用 reset() 方法。

到此,整个 LoadButton 实现逻辑已经完成。接下来我们可以编写代码测试。

测试

我们添加一个 LoadButton 到布局文件,然后用 3 个 Button 来测试它成功、失败、重置的情况。

测试结果:

总结

本文的主题并不难,但是如果要实现它也需要细心。关键是编码的时候,要先设计分析,之后就是一气呵成、水到渠成的事情了。

通过演练这个项目,我觉得自己还是有些收获。

  • 复习了自定义 View 的基本流程。特别是对 onMeasure() 这一块有更深的理解。

  • 复习了属性动画的使用。

  • 复习了 Canvas 和 Path 的基本用法。

  • 演练了状态模式下的编程。

  • 享受回调机制带来的美妙感受。

如果有人认为好用,我想把它上传到 jcenter 仓库,目的也是为了演练怎么上传 Android 模块到开源库。喜欢这篇文章就给我一个赞吧,需要你们的鼓励。哈哈。

项目地址:

https://github.com/frank909zhao/LoadButton

更多

每天学习累了,看些搞笑的段子放松一下吧。关注最具娱乐精神的公众号,每天都有好心情。

如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号:

实现一个清新美观的加载按钮相关推荐

  1. 页面重新加载_Chrome为PWA应用加入了返回和重新加载按钮

    此前,微软已在 Chromium Edge 浏览器中,为渐进式 Web 应用(WPA)添加了后退按钮和跳转列表支持.现在,谷歌 Chromium 团队亦为 Chrome 浏览器上的 PWA 应用,加入 ...

  2. Unity3d制作动画顺便加载按钮控制

    先上图: 我主要做了几件事:1.导入kl的unity package并拼接动画,2.添加两个UI中的按钮,Canvas是加载按钮时自动生成的,3.同时用代码实现了另外4个按钮的生成,效果图如下: 不管 ...

  3. [css] 请用css写一个扫码的加载动画图

    [css] 请用css写一个扫码的加载动画图 @Keyframes donut-spin { 0% { transform: rotate(0deg); } 100% { transform: rot ...

  4. 一个到顶部自动加载更多的ListView

    为什么80%的码农都做不了架构师?>>>    一个可以到顶自动加载更多的ListView,实现该控件的目的是用于im聊天页面场景,一些第三方实现的下拉加载更多也可以实现类似功能,但 ...

  5. 一个简单的购物车加减按钮

    一个简单的购物车加减按钮,自定义控件实现,非常简单,有兴趣的可以自己尝试一下 import android.content.Context; import android.util.Attribute ...

  6. libGDX跨平台游戏开发框架入门:开发一个小游戏之加载资源

    目录 前言 加载资源 libGDX资源目录说明 配置各个平台启动器 desktop模块启动器设置 Android模块启动器设置 加速度计和指南针 html模块启动器设置 编写加载资产代码 1. 加载图 ...

  7. arcgis前端(2)----->基础篇--发布一个自定义地图及加载自定义地图/底图

    arcgis前端(2)----->基础篇–发布一个自定义地图及加载自定义地图/底图 文章目录 arcgis前端(2)----->基础篇--发布一个自定义地图及加载自定义地图/底图 前言 & ...

  8. 从一个ELF程序的加载窥探操作系统内核-(5)

    从一个ELF程序的加载窥探操作系统内核-(5) 操作系统加载一个ELF程序看似一个EASY的动作,其实下面隐藏了很多很多OS内核的关键实现,让我们一起来解密其中的流程 作者是一个micro kerne ...

  9. easyui datagrid 自定义加载按钮实例

    今天写一个项目,在用到datagrid的时候突然发现加载操作列中的自定义按钮出来问题,经过一番研究,原来这么简单.话不多说,上图 //获取选中行审核 function Checker(indexDiv ...

最新文章

  1. Sqlite3数据库之第三方库FMDB学习心得
  2. ***正传——著名网络安全人士郭鑫成长经历
  3. push to origin/master was rejected错误解决方案(IDEA)
  4. cJSON库源码分析
  5. linux 安装反病毒软件
  6. 小程序引入的echarts过大如何解决_解决微信小程序引用echarts视图模糊的问题
  7. calendar类计算时间距离_日期时间--JAVA成长之路
  8. 取文件 shell_webshell文件上传分析溯源
  9. oracle jvm禁用,java-如何减少Sun / Oracle JVM内部开销?
  10. sqlserver 2008r2 执行代码 快捷键
  11. 进程间通信系列 之 信号实例
  12. java使用Redis(六个类型)
  13. CentOS7.5.1804 Minimal 静默安装oracle 12c R1企业版
  14. 计算机外设解决方案,瑞昱在2007 IDF上展出多款计算机外设产品解决方案
  15. 华为笔试——C++平安果dp算法
  16. DevOps平台的“精益创业”之路
  17. Dell服务器开启CPU虚拟化
  18. linux和win10文件共享smb,Windows 10 Samba文件共享的设置方法,解决不能访问和密码错误的问题...
  19. 直播技术——视频编解码(理论基础)
  20. leetcode 547. 朋友圈 C语言

热门文章

  1. eclipse配置tomcat时Preferences中没有server解决方案
  2. 天猫抢红包活动活动规则【2012年6…
  3. python中argparse_python argparse用法总结
  4. 5G 时代,从视频互动特效技术看未来趋势
  5. JavaWeb项目结构使用Vue项目
  6. 2021年的元宇宙,1999年的互联网
  7. Tengine安装使用及配置
  8. 【教程】保姆级红米AX6000刷UBoot和OpenWrt固件
  9. 因果推断丨双重差分法
  10. 济南三个比较邪的地儿(转)