概述
在前幾期自定義 View的文章里哎垦,有一篇是畫了一個雷達(dá)掃描界面武通。這次再重畫一遍县好,用 Kotlin畫。因?yàn)檫壿嬙砼c上次畫的一樣,只是換了科特林鳖粟。所以原理這里就不講了,就直接貼出代碼拙绊。在代碼注釋里有部分Kotlin區(qū)別于java的語法解釋向图,自己看就好。
Screenrecorder-2021-08-04-18-15-57-5262021842252183.gif
代碼:
class ScanViewKt : View {
// 同心圓畫筆
private lateinit var paint: Paint // 注釋 1标沪, lateinit關(guān)鍵詞 :可延遲賦值榄攀。 var關(guān)鍵詞 :可變變量聲明(val 則類似于 java的 final)
// 畫掃描圓畫筆
private lateinit var scanPaint: Paint // 注釋 2,變量名在前金句,類型在后檩赢,中間引號
// 設(shè)備點(diǎn)畫筆
private lateinit var pointPaint: Paint // 注釋 3,后面分號可以省略违寞,但必須換行贞瞒,否則下一條語句報(bào)錯
// 同心圓之間的間距
private var spaceIntCircles: Int = 0
// 掃描圓的陰影
private lateinit var scanShader: Shader
// 掃描圓陰影矩陣
private var scanMatrix: Matrix = Matrix() // 注釋 4偶房,對象創(chuàng)建不用 java的 new關(guān)鍵詞了
// 旋轉(zhuǎn)角度
private var rotation: Int = 0
// 掃描結(jié)果
private var pointList: CopyOnWriteArrayList<PointPositionKt> = CopyOnWriteArrayList()
// 停止掃描
private var stopScan = false
constructor(context: Context) : this(context, null) // 注釋 5,構(gòu)造器關(guān)鍵詞 constructor
constructor(context: Context, attrs: AttributeSet?) : this(
context,
attrs,
0
) // 注釋 6军浆,構(gòu)造器調(diào)用的 this棕洋、super放在形參表和方法體之間,加以引號
constructor(context: Context, attrs: AttributeSet?, style: Int) : super(context, attrs, 0) {
init()
}
private fun init() { // 注釋 7乒融, 方法用關(guān)鍵字 fun修飾
paint = Paint()
paint.style = Paint.Style.STROKE
paint.color = Color.parseColor("#FFF10404")
paint.isDither = true
paint.isAntiAlias = true
paint.strokeWidth = 2f
scanPaint = Paint()
scanPaint.isDither = true
scanPaint.isAntiAlias = true
pointPaint = Paint()
pointPaint.style = Paint.Style.FILL
pointPaint.isDither = true
pointPaint.isAntiAlias = true
pointPaint.color = Color.parseColor("#FF3700B3")
}
override fun onMeasure(
widthMeasureSpec: Int,
heightMeasureSpec: Int
) { //注釋 8掰盘, 重寫的方法聲明使用關(guān)鍵字 override替換注解
var width = getMeasureSize(widthMeasureSpec)
var height = getMeasureSize(heightMeasureSpec)
var size = Math.min(width, height)
setMeasuredDimension(size, size)
}
@SuppressLint("DrawAllocation")
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
spaceIntCircles = width / 12 - width / 120
scanShader = SweepGradient(
(width / 2).toFloat(), (height / 2).toFloat(),
intArrayOf(Color.TRANSPARENT, Color.GRAY), floatArrayOf(0.1f, 0.9f)
)
scanPaint.shader = scanShader
scanShader.setLocalMatrix(scanMatrix)
}
private fun getMeasureSize(measureSpec: Int): Int {
var mode = MeasureSpec.getMode(measureSpec)
var size = MeasureSpec.getSize(measureSpec)
if (mode == AT_MOST) return dipToPx(18f).toInt() // 注釋 9,類型強(qiáng)轉(zhuǎn)使用 to..()方法
return size
}
private fun dipToPx(dip: Float): Float { // 注釋 10簇抵,方法返回值類型方法形參列表后庆杜,以引號隔開
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, dip, resources.displayMetrics)
}
override fun onDraw(canvas: Canvas) {
// 畫 6個圈
for (i in 0..6) { // 注釋 11,for循環(huán)的其中一種形式: (i in 0..6)碟摆,0..6 表示區(qū)間晃财。這里包含邊界值〉渫桑可用 (i in 0 until 6)去除有邊界
canvas.drawCircle(
(height / 2).toFloat(), (height / 2).toFloat(),
(i * spaceIntCircles).toFloat(), paint
)
}
// 畫帶陰影的掃描圓
canvas.drawCircle(
(height / 2).toFloat(), (height / 2).toFloat(),
(5 * spaceIntCircles).toFloat(), scanPaint
)
drawPoint(canvas)
setRotation()
}
/***
* 畫所有的點(diǎn) (設(shè)備)
* ***/
private fun drawPoint(canvas: Canvas) {
for (item in pointList) { // 注釋 12断盛, item關(guān)鍵字的 for循環(huán)迭代遍歷集合
pointPaint.color = item.pointColor
if (pointList.indexOf(item) == pointList.size - 1) {
canvas.drawCircle(
item.getPoint().x, item.getPoint().y,
(spaceIntCircles / 2).toFloat(), pointPaint
)
continue
}
canvas.drawCircle(
item.getPoint().x, item.getPoint().y,
(spaceIntCircles / 4).toFloat(), pointPaint
)
}
}
/***
* 改變旋轉(zhuǎn)角度
* ***/
private fun setRotation() {
if (rotation >= 360) rotation = 0
rotation += 2
scanMatrix.setRotate(rotation.toFloat(), (width / 2).toFloat(), (height / 2).toFloat())
scanShader.setLocalMatrix(scanMatrix)
if (!stopScan) invalidate()
}
/***
*停止掃描
* ***/
fun setScanStop() {
if (this.stopScan) return
this.stopScan = true
}
/***
* 開始掃描
* ***/
fun setStartScan() {
if (!this.stopScan) return
this.stopScan = false
invalidate()
}
/***
* 添加設(shè)備
* ***/
fun addPoint(point: PointPositionKt) {
if (stopScan) return
if (this.pointList.contains(point)) return
point.setRadio(spaceIntCircles * 6)
.setCenterPoint(PointF((width / 2).toFloat(), (height / 2).toFloat()))
.setPoint(rotation)
pointList.add(point)
}
/***
* 移除某個設(shè)備
* ***/
fun removePoint(point: PointPositionKt) {
if (pointList.contains(point)) pointList.remove(point)
invalidate()
}
/***
* 清除界面設(shè)備
* ***/
fun clearPoint() {
if (pointList.size == 0) return
pointList.clear()
invalidate()
}
}
整理一下上面的語法注釋:
// 注釋 1, lateinit關(guān)鍵詞 :可延遲賦值愉舔。 var關(guān)鍵詞 :可變變量聲明(val 則類似于 java的 final)
// 注釋 2钢猛,變量名在前,類型在后轩缤,中間引號
// 注釋 3命迈,后面分號可以省略,但必須換行火的,否則下一條語句報(bào)錯
// 注釋 4壶愤,對象創(chuàng)建不用 java的 new關(guān)鍵詞了
// 注釋 5,構(gòu)造器關(guān)鍵詞 constructor
// 注釋 6馏鹤,構(gòu)造器調(diào)用的 this征椒、super放在形參表和方法體之間,加以引號
// 注釋 7湃累, 方法用關(guān)鍵字 fun修飾
// 注釋 8勃救, 重寫的方法聲明使用關(guān)鍵字 override替換注解
// 注釋 9,類型強(qiáng)轉(zhuǎn)使用 to..()方法
// 注釋 10治力,方法返回值類型放在形參列表后蒙秒,以引號隔開
// 注釋 11,for循環(huán)的其中一種形式: (i in 0..6)宵统,0..6 表示區(qū)間税肪。這里包含邊界值。可用 (i in 0 until 6)去除右邊界
// 注釋 12益兄, item關(guān)鍵字的 for循環(huán)迭代遍歷集合