相关源码文件,将会在文末附上。
效果如图所示。本文将讲述如何自定义一个这样的控件,代码在文末。
思考
(一)实现方式
(二)传递给业务层的数据格式
(三)实现细节
上面三个点,是需要我们去思考的。
(一),这里选择的实现方法,推荐是自定义view,因为这种布局,一般普通的控件,是不支持的。
(二)对于业务层来说,应该做的是,传递颜色数据进入我们的控件,然后控件选择了颜色后,把颜色数据原封不动的传回给业务层,这里选择了String格式作为色值传递,如“#ffffff”。
(三)实现中,使用canvas如何正确绘制圆弧,如何计算真实的角度,象限区间的数据转换,以及坐标数据的转换,点击事件的坐标计算,都是值得思考的问题。
好了,思考完以后,就开始干活。
实现过程
#####(一)定义类
做类似的控件,都是需要有一个大纲思维,就是我这个控件库,给外部暴露了什么方法,我内部又需要如何处理外部传入的数据。所以,要先定义好抽象方法:
(1)控件抽象类:
interface LibColorCirclePickerApi {fun setColor(color: Array<Array<String>>)fun setLibColorCirclePickerListener(listener: LibColorCirclePickerListener)fun removeLibColorCirclePickerListener()
}
(2)外部监听类:
interface LibColorCirclePickerListener {fun selInfo(info: LibColorSelInfo)}
定义好这些方法,就可以通过继承,具体实现了。
#####(二)自定义view实现绘制色值
这里涉及到canvas绘制的知识,请提前了解。
而如图所示,绘制分为两个层级。一个就是中心圆,另外一个就是色块。
在绘制之前,需要确定以下的变量,方便后续的绘制:
(一)绘制的中心坐标点,x,y点。这里取x/2,y/2。
(二)绘制的半径,这里取最短边的一般作为绘制的半径。
(三)绘制中心圆的半径,通过一定的比率和(二)相乘,得出中心圆的半径。
(四)除中心圆外,剩余的半径长度,这里后续会做平均划分,计算除每层色块的半径长度。
(五)初始化相关中间变量值(如色块坐标集合)
初始相关变量后后,就开始绘制:
绘制中心圆
对于中心圆,这里直接调用canvas的画圆圈方法就行,不再啰嗦
绘制色块
对于色块,首先要明确,你的色块有多少层,这里就决定了每层色块的半径长度。这里的多少层,是通过外部传入的二维数组决定的。对于传入的二维数组,一维决定层级,二维就是一维下的色块数组。
通过上述的了解,就可以通过 “剩余半径” 除以 “色块层数” 即可得出 “每层色块半径长度”。
再通过 360 除以 “每层色块数量”,即可得出每个色块所占的角度。
最后通过设置画笔的strokeWidth,就可以进行绘制。
最后,把绘制过程中产生的“半径范围值”,“角度范围值”,“色值”通过中间变量保存,供以后续的触摸事件调用。
ps:
这里有个实现细节,就是关于Paint的strokeWidth。实际是基于绘制坐标两端扩展的。例如,绘制一条直线,那就会在Y坐标两端拓展,如 (x,y)(0,10),strokeWidth是10,那么直角边宽度就会基于(0,5)-(0,15)中间。
所以,设置strokeWidth后绘制,需要预留绘制实现中的位置。
触摸事件
对于触摸事件,需要在onTouchEvent中进行处理,父类方法重新如下:
override fun onTouchEvent(event: MotionEvent?): Boolean {when (event?.action) {MotionEvent.ACTION_DOWN -> {}MotionEvent.ACTION_MOVE -> {}MotionEvent.ACTION_UP -> {val currentX = event.xval currentY = event.ydealWithUpEvent(currentX, currentY)}MotionEvent.ACTION_CANCEL -> {}}return true}
这里通过return true,把所有事件都拦截到本view进行处理了。
设想一下,有了中心坐标,和点击时候的x,y坐标。是不是可以得出一个“象限区间”的逻辑?然后再通过数学公式tan方法,即可得出对应的角度。
角度有了,象限有了,就可以换算出最后的真正点击角度,还有点击坐标点的半径。核心代码如下:
/*** 处理手势抬起事件* */private fun dealWithUpEvent(currentX: Float, currentY: Float) {//判断象限val trainX = (currentX - mCenterX)val trainY = (mCenterY - currentY)//求半径长度val x = abs(abs(currentX) - abs(mCenterX)).toDouble()val y = abs(abs(mCenterY) - abs(currentY)).toDouble()//半径val trainRadius = sqrt((x.pow(2.0) + y.pow(2.0)))//角度val angle = atan(abs(x) / abs(y)) * 180 / PI//计算后,再根据象限,转换最终的角度var trainAngle = 0fif (trainX <= 0 && trainY >= 0) {trainAngle = (90 - angle + 270).toFloat()} else if (trainX >= 0 && trainY >= 0) {trainAngle = angle.toFloat()} else if (trainX <= 0 && trainY <= 0) {trainAngle = (angle + 180).toFloat()} else if (trainX >= 0 && trainY <= 0) {trainAngle = (90 - angle + 90).toFloat()} else {return}
// Log.d("dealWithUpEvent", "angle $angle + 转换角度 $trainAngle 半径: $trainRadius")//通过象限,角度,半径,三个条件,确定具体的位置val filterList: MutableList<LibColorInnerPosInfo> = ArrayList()this.mColorPosInfo.filter {it.startAngle <= trainAngle && it.endAngle >= trainAngle}.filter {it.startRadius >= trainRadius && it.endRadius <= trainRadius}.filter {!it.color.isNullOrBlank()}.toCollection(filterList)if (filterList.size != 1) {return}mListener?.selInfo(LibColorSelInfo().apply {this.colorStr = filterList.first().color})}
至此,全部流程已经说完了,还有不懂的地方,请下载源码了解:
源码
提取码: naf2
that’s all————————————————————–
查看全文
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dgrt.cn/a/1987411.html
如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!
相关文章:
关于安卓颜色选择器的使用(一)
本文内容为从0-1开发一个颜色选择器,先上效果图
相关源码文件,将会在文末附上。
效果如图所示。本文将讲述如何自定义一个这样的控件,代码在文末。
思考
(一)实现方式 (二)传递给业务层的数……
fMRI之dpabi处理经验(一)
fMRI dpabi处理经验(一)
dpabi用以处理fMRI、MRI数据非常好的matlab工具箱,下载地址:dpabi。下面来介绍下我在学习使用的过程中遇到的问题及操作吧。
fMRI处理常见问题
打开matlab后再命令窗口输入dpabi打开界面,fM……
MRIcron下的4DNifti格式转变为3DNifti格式
MRIcron下的4DNifti格式转变为3DNifti格式
本文为转载,只是为了防止连接丢失,做备用,原文链接:http://blog.sina.com.cn/s/blog_691f18960101jyuv.html
原作者:非邪恶的博客,这个博主有很多fMRI等神经影像……
替代数据surrogate data
替代数据surrogate data To my understanding, the purpose of surrogate data testing is to stir the original data, then to check if the coherence(or other connectivity measures) really exist, am I right? AND; Yes generate synthetic signals and test them agai……
python读取mat文件报错问题
python读取mat文件报错问题
在用python读取mat文件时报了以下错误:OSError: Unable to create file 发现是自己mat文件格式的问题,原来直接在matlab中右键另存cell文件,但这种文件python打不开,需要用save函数保存才行 eg.save(……
校园网拨号上网一直掉线但实际网络通路是连接着的
校园网拨号上网一直掉线但实际网络通路已连接问题问题描述解决问题描述
台式机有线网络要通过拨号上网,但是几分钟显示掉一次线,浏览器不能用,网页打不开,以为网络断了,但是偶然间发现微信是一直连着的,在……
【同一电脑原win用户信息迁移到新Win用户下python interpreter显示 no interpreter问题】
这里写自定义目录标题问题解决问题
原来的win用户下系统突然报错,所有的win的设置点击都会闪退,朋友说是微软的uwp全挂了,经过各种办法尝试仍未解决,最后偶然间发现创建新用户后,电脑能正常使用。于是把原win用户下所……
【 PermissionError: [Errno 13] Permission denied: 问题】
PermissionError: [Errno 13] Permission denied: 问题
个人情况比较特殊,常规的Errno 13解决方法都无效。
问题及解决:
刚开始还能正常安装扩展包,突然间不知道为什么创建新的虚拟环境和安装新的扩展包都失败了,报错ÿ……
智慧灌区管理平台-大中型灌区信息化监测系统
智慧灌区管理平台平台概述柳林智慧灌区管理平台以物理灌区为单元、时空数据为底座、数学模型为核心、水利知识为驱动,对物理灌区全要素和建设运行全过程进行数字映射、智能模拟、前瞻预演,与物理灌区同步仿真运行、虚实交互、迭代优化,实现对……
DRBG_InstantiateSeeded调试-1
public 参数解析: standardEKPolicy: 837197674484b3f81a90cc8d46a5d724fd52d76e06520b64f2a1da1b331469aa(32bytes)
rawCmdBuf 命令数据: 800200000063000001314000000100000009400000090000010000000400000000003a0001000b000300720020837197674484b3f81a90cc8d46a5d724fd5……
cocos2d-js中的回调函数中世界坐标系和节点坐标系的相互转换
世界坐标系和节点坐标系都是OPENGL 坐标系 1、世界坐标系原点就是屏幕的左下角; 2、节点坐标系的原点就是一个节点的左下角; 3、两个坐标系可以通过已经写好的cocosAPI进行想换转换; 4、所有的节点需要转为一个节点上或者是统一的世界坐标系……
通过JavaScript实现漂浮
<html>
<head><meta http-equiv"Content-Type" content"text/html"; charset"gb2312" /><title>漂浮广告</title><style type"text/css">div{position:absolute;}</style>
</head>
&……
序列动画和图片内存问题
一、帧动画问题 /*** 帧动画总结:* 1、如果精灵进行新建时,加载了纹理,那么setRestoreOriginalFrame可以设置为false或者true* 2、如果精灵新建时,没有加载纹理的话,那么setRestoreOriginalFrame需要设置为false&#……
冒泡排序的两种写法
//第一种写法: #include <iostream> using namespace std; void bubbleSort(int arr[], int n) { for (int i 0; i < n-1; i) { int temp 0; for (int j i1; j <n; j) { if (arr[i] ……
c++中this详解
http://blog.csdn.net/ugg/article/details/606396…
编程是可以从事一生的职业吗
暂且不论这个话题,留待以后再添加见解。
目前而言,编程符合自己的性格和兴趣,且可以解决自我的生活,一举两得,总算是做了自己喜欢的事情。2016-7-24
在此立文以自勉!
2016-8-30: 1、编程就是一个不断和自我的惰性做……
STL中常用容器详解
常用的容器
一、顺序容器 1、vector 向量 :随机访问(按照下标)任何一个元素,在尾部增删元素,相当于是一个动态的数组。 vector容器,在头部增加、删除元素,其时间消耗和元素数目成正比ÿ……
c++中的继承的讲解
cpp中的继承的总结: 1、继承方式对于之列继承自父类的成的访问权限的影响 对于父类本身没有影响,对于子类扩展成员也没有影响。 2、子类中从父类继承的成员,其访问权限不能高于继承声明时使用的访问权限。 私有继承: 子类中所有继……
c++虚函数的讲解
废话少说,直接上测试代码 #include<iostream> #include<stdlib.h>usingnamespace std;//有虚函数的类 class A{public:A();~A();virtual void f(){cout<<"this is A f()"<<endl;}virtual void g(){cout<<"this is A g……
ListView TableView ScrollView三者之Tableview
注意点:
1、其中的listView和Tableview都是继承自Scrollview
2、本文主要讲解的是tableview
3、代码部分引用的是在公司中做的产品
4、以上代码可以修改的地方:将cell改为继承自TableviewCell,这样可以直接创建cell。
5、代码中使用了函数的绑定和函……
编程日记2023/4/16 15:01:17