




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】自定义View系列之kotlin绘制手势设置温度控件的示例分析
这篇文章将为大家详细讲解有关自定义View系列之kotlin绘制手势设置温度控件的示例分析,在下觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。引言最近公司接了一个车联网的项目,主要是新能源汽车的一些控制功能,其中涉及到一个是温度的调节功能,产品的意思是做一个手势滑动调节温度,大概意思我是明白的。就是要手势调节呗,没办法,谁让我是搬砖的呢,人为刀俎,我为鱼肉,只有搞了;最后搞出来的效果大概如下,不过还没确定,思路在这里我先说下自己的实现思路,这个控件的难点主要是手势控制,其他的都很简单,没有什么好说的,控制的一些具体的数值我是写死的,没有做自定义拓展,主要是闲麻烦,如果有需要可以自己的实现;具体的实现步奏首先绘制圆盘,刻度,阴影(需要关闭硬件加速),文字然后根据划过的角度绘制进度条最后根绝touch事件重新绘制,并设置数据回调代码实现1,绘制前的准备首先kotlin提供了init方法,我们需要在这个方法里面初始化我们需要的画笔和一些数据注:这里涉及到阴影的绘制,所以必须关闭硬件加速
init
{
//关闭硬件加速
setLayerType(View.LAYER_TYPE_SOFTWARE,
null)
mInCirclePaint.color
=
Color.WHITE
mInCirclePaint.strokeWidth
=
1f
mInCirclePaint.style
=
Paint.Style.FILL
mInCirclePaint.setShadowLayer(25f,
0f,
0f,
Color.GRAY)
mGrayLinePaint.color
=
Color.parseColor("#00EEEE")
mGrayLinePaint.strokeWidth
=
dp2px(1f).toFloat()
mGrayLinePaint.style
=
Paint.Style.STROKE
mGrayLinePaint.setShadowLayer(15f,
0f,
0f,
Color.GRAY)
mTempTextPaint.textSize
=
sp2px(32f).toFloat()
mTempTextPaint.style
=
Paint.Style.FILL
mTempTextPaint.color
=
Color.parseColor("#7CCD7C")
mTempTextPaint.textAlign
=
Paint.Align.CENTER
mTempTextPaint.isFakeBoldText
=
true
mTempTextPaint.setShadowLayer(5f,
0f,
0f,
Color.GRAY)
mTextPaint.textSize
=
sp2px(18f).toFloat()
mTextPaint.style
=
Paint.Style.FILL
mTextPaint.color
=
Color.parseColor("#aaaaaa")
mTextPaint.textAlign
=
Paint.Align.CENTER
//
mTextPaint.setShadowLayer(5f,
0f,
0f,
Color.GRAY)
mLineProgressPaint.style
=
Paint.Style.STROKE
mLineProgressPaint.strokeWidth
=
dp2px(10f).toFloat()
mLineProgressPaint.color
=
Color.parseColor("#7CCD7C")
//
mLineProgressPaint.setShadowLayer(5f,
0f,
0f,
Color.GRAY)
mProgressCirclePaint.style
=
Paint.Style.FILL
//
mProgressCirclePaint.setShadowLayer(15f,
0f,
0f,
Color.GRAY)
mProgressPaint.style
=
Paint.Style.FILL
mProgressPaint.color
=
Color.parseColor("#436EEE")
mProgressPaint.strokeCap
=
Paint.Cap.ROUND
//
mProgressPaint.setShadowLayer(5f,
0f,
0f,
Color.GRAY)
mPaintTriangle.style
=
Paint.Style.FILL
mPaintTriangle.color
=
Color.parseColor("#436EEE")
}然后我们需要重写onMeasure()方法,因为这个控件必须是正方形的,所以我们必须保证宽和高一致;
override
fun
onMeasure(widthMeasureSpec:
Int,
heightMeasureSpec:
Int)
{
val
width
=
View.MeasureSpec.getSize(widthMeasureSpec)
val
height
=
View.MeasureSpec.getSize(heightMeasureSpec)
val
imageSize
=
if
(width
<
height)
width
else
height
setMeasuredDimension(imageSize,
imageSize)
}再之后我们需要知道一些具体的宽高值,从而设置半径的大小,一般是在onSizeChanged()方法里面拿到
override
fun
onSizeChanged(w:
Int,
h:
Int,
oldw:
Int,
oldh:
Int)
{
super.onSizeChanged(w,
h,
oldw,
oldh)
mHeight
=
Math.min(h,
w)
mWidth
=
height
dialRadius
=
(width
/
2
-
dp2px(10f))
arcRadius
=
dialRadius
/
2
mBgRectf
=
RectF(-dialRadius
*
1f
/
2
-
dp2px(5f),
-dialRadius
*
1f
/
2
-
dp2px(5f),
dialRadius
*
1f
/
2
+
dp2px(5f),
dialRadius
*
1f
/
2
+
dp2px(5f))
}2,绘制接下来就开始绘制视图了,绘制之前需要把视图的原心移动到中心位置
canvas.translate(mWidth
*
1f
/
2,
mHeight
*
1f
/
2);接着就开始绘制,首先我们绘制最外边源的线,这里绘制180根线,其中30根长线
private
var
beginAngle
=
0f
private
val
drawLine
=
{
canvas:
Canvas
->
beginAngle
=
0f
canvas.save()
for
(i
in
0..180)
{
canvas.save()
canvas.rotate(beginAngle)
mGrayLinePaint.setARGB(180,
(0.7
*
i
*
2).toInt(),
((255
-
0.7
*
i
*
2).toInt()),
((255
-
0.7
*
i
*
2).toInt()))
if
(beginAngle
%
12
==
0f)
{
canvas.drawLine(dialRadius
*
7f
/
9
-
dp2px(5f),
0f,
dialRadius
*
8f
/
9,
0f,
mGrayLinePaint)
}
else
{
canvas.drawLine(dialRadius
*
7f
/
9,
0f,
dialRadius
*
8f
/
9,
0f,
mGrayLinePaint)
}
beginAngle
+=
2f
canvas.restore()
}
canvas.restore()
}效果如下接着开始绘制中心的文字,如果如下
private
val
drawText
=
{
canvas:
Canvas
->
val
baseLineY
=
Math.abs(mTempTextPaint.ascent()
+
mTempTextPaint.descent())
/
2
mTempTextPaint.setARGB(180,
(0.7
*
currentAngle).toInt(),
(255
-
0.7
*
currentAngle).toInt(),
(255
-
0.7
*
currentAngle).toInt())
if
(temText
==
30
||
temText
==
29)
{
mTempTextPaint.setARGB(255,
255,
0,
0)
}
else
if
(temText
==
15)
{
mTempTextPaint.setARGB(255,
0,
255,
255)
}
canvas.drawText("${temText}°",
0f,
baseLineY
+
dp2px(20f),
mTempTextPaint)
canvas.drawText("最大温度设置",
0f,
baseLineY
-
dp2px(20f),
mTextPaint)
}接下来就开始绘制进度条和阴影部分
private
val
drawPointCircle
=
{
canvas:
Canvas
->
canvas.save()
canvas.rotate(rotateAngle
+
2)
mProgressPaint.setARGB(255,
(0.7
*
currentAngle).toInt(),
(260
-
0.7
*
currentAngle).toInt(),
(260
-
0.7
*
currentAngle).toInt())
mPaintTriangle.setARGB(255,
(0.7
*
currentAngle).toInt(),
(260
-
0.7
*
currentAngle).toInt(),
(260
-
0.7
*
currentAngle).toInt())
if
(temText
==
30
||
temText
==
29)
{
mProgressPaint.setARGB(255,
255,
0,
0)
mPaintTriangle.setARGB(255,
255,
0,
0)
}
else
if
(temText
==
15)
{
mProgressPaint.setARGB(255,
0,
255,
255)
mPaintTriangle.setARGB(255,
0,
255,
255)
}
val
path
=
Path()
path.moveTo(dialRadius
*
1f
/
2
+
dp2px(5f),
(-dp2px(10f)).toFloat())
path.lineTo(dialRadius
*
1f
/
2
+
dp2px(5f),
dp2px(10f).toFloat())
path.lineTo(dialRadius
*
1f
/
2
-
dp2px(10f),
0f)
path.close()
canvas.drawPath(path,
mPaintTriangle)
val
point
=
dialRadius
*
1f
/
2
+
dp2px(5f)
canvas.drawCircle(point,
0f,
dp2px(10f).toFloat(),
mProgressPaint)
canvas.restore()
}
private
val
drawProgress
=
{
canvas:
Canvas
->
if
(rotateAngle
>
0)
{
mProgressCirclePaint.color
=
Color.parseColor("#00ffff")
canvas.drawCircle(dialRadius
*
1f
/
2
+
dp2px(5f),
0f,
dp2px(5f).toFloat(),
mProgressCirclePaint)
}
val
colors
=
intArrayOf(Color.parseColor("#00ffff"),
Color.parseColor("#ff0000"))
val
mShader
=
SweepGradient(0f,
0f,
colors,
null)
mLineProgressPaint.shader
=
mShader
canvas.drawArc(mBgRectf,
0f,
rotateAngle,
false,
mLineProgressPaint)
}2,手势绘制视图结束,现在开始手势的处理,主要就是处理touch事件,我们以圆心为坐标圆点,建立坐标系,求出(targetX,targetY)坐标与x轴的夹角,显现代码如下private
val
calcAngle
=
{
targetX:
Float,
targetY:
Float
->
val
x
=
targetX
-
width
/
2
val
y
=
targetY
-
height
/
2
val
radian:
Double
if
(x
!=
0f)
{
val
tan
=
Math.abs(y
/
x)
if
(x
>
0)
{
if
(y
>=
0)
{
radian
=
Math.atan(tan.toDouble())
}
else
{
radian
=
2
*
Math.PI
-
Math.atan(tan.toDouble())
}
}
else
{
if
(y
>=
0)
{
radian
=
Math.PI
-
Math.atan(tan.toDouble())
}
else
{
radian
=
Math.PI
+
Math.atan(tan.toDouble())
}
}
}
else
{
if
(y
>
0)
{
radian
=
Math.PI
/
2
}
else
{
radian
=
-Math.PI
/
2
}
}
(radian
*
180
/
Math.PI).toFloat()
}然后在touch事件中进行处理,主要代码如下override
fun
onTouchEvent(event:
MotionEvent):
Boolean
{
when
(event.action)
{
MotionEvent.ACTION_DOWN
->
{
isDown
=
true
downX
=
event.x
downY
=
event.y
currentAngle
=
calcAngle(downX,
downY)
}
MotionEvent.ACTION_MOVE
->
{
isMove
=
true
val
targetX:
Float
=
event.x
val
targetY:
Float
=
event.y
val
angle
=
calcAngle(targetX,
targetY)
//
滑过的角度增量
var
angleIncreased
=
angle
-
currentAngle
if
(angleIncreased
<
-180)
{
angleInc
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 结构化思维商务英语考试试题及答案
- 注册土木工程师考试内容清单试题及答案
- 社会管理创新试题及答案
- 游戏化营销在品牌传播中的影响力分析:2025年深度报告
- 标准推理测试题及答案
- 威海考教师编试题及答案
- 无机化学实验题目及答案
- 护理基础考核试题及答案
- 萍乡卫生职业学院《经贸日语》2023-2024学年第一学期期末试卷
- 江苏省盐城市大丰2025届初三年级下学期十月份月考化学试题含解析
- HIV实验室SOP文件-新版
- 孤独症儿童评估填写范例(一表两图)
- 贺兰山东麓干红葡萄酒多酚组分与其抗氧化、抗癌活性的关联性研究
- 第15课+十月革命的胜利与苏联的社会主义实践【高效备课精研 + 知识精讲提升】 高一历史 课件(中外历史纲要下)
- (4.3.1)-3.3我国储粮生态区的分布
- 辽宁盘锦浩业化工“1.15”泄漏爆炸着火事故警示教育
- 2023年衡阳市水务投资集团有限公司招聘笔试题库及答案解析
- 110~750kV架空输电线路设计规范方案
- 北师大版五年级数学下册公开课《包装的学问》课件
- 北师大版英语八年级下册 Unit 4 Lesson 11 Online Time 课件(30张PPT)
- 浅析商业综合体的消防疏散
评论
0/150
提交评论