在移动设备上,手势解锁已经成为一种盛行的安全办法。在本文中,咱们将具体介绍怎么运用自定义视图实现手势解锁功用。
1. 创立 GestureLockView 类
首要,咱们需要创立一个名为 GestureLockView 的类,继承自 View。这个类将担任制作手势解锁视图,并处理用户的接触事情。
class GestureLockView @JvmOverloads constructor(
context: Context, attrs:
AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
// 行数
private val numRows = 3
// 列数
private val numColumns = 3
private val mStrokeWidth = 10.dpToPx
//画笔
private val mPaint = Paint().apply {
isAntiAlias = true
strokeWidth = mStrokeWidth
style = Paint.Style.FILL
}
//手势途径
private val mPath = Path()
//可视化的九宫格点
private val allPoints: MutableList<PointF> = mutableListOf()
//可视化的九宫格点
private val choosePoints: MutableList<PointF> = mutableListOf()
//圆点的半径
private var pointRadius = 0f
//手指最终移动的方位
private var lastX = 0f
private var lastY = 0f
// ...
}
在这段代码中,咱们定义了一些私有属性和变量。行数和列数分别为 3,表示手势解锁界面是一个 3×3 的九宫格。mStrokeWidth 表示九宫格线的宽度。mPaint 是用于制作九宫格的画笔。mPath 是手势途径,用于制作用户划过的途径。allPoints 是可视化的九宫格点的调集,choosePoints 是用户选择的点的调集。pointRadius 是圆点的半径。lastX 和 lastY 是手指最终一次接触的方位。
2. 初始化手势解锁视图
接下来,在 onSizeChanged 办法中初始化手势解锁视图。
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
val offset = w / (numRows + 1).toFloat()
pointRadius = offset / 4f
for (y in 0 until numRows) {
for (x in 0 until numColumns) {
allPoints.add(PointF(offset + offset * x, offset + offset * y))
}
}
}
在这段代码中,咱们首要核算出九宫格每个点之间的间隔 offset,然后依据 offset 核算出圆点的半径 pointRadius。接着运用两个嵌套的循环,将所有的九宫格点添加到 allPoints 调集中。
3. 制作手势解锁视图
在 onDraw 办法中,咱们运用 Canvas 和 Paint 目标来制作手势解锁视图。
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
allPoints.forEach {
if (choosePoints.contains(it)) {
mPaint.color = Color.BLUE
} else {
mPaint.color = Color.WHITE
}
mPaint.style = Paint.Style.FILL
mPaint.alpha = 255
//制作中心的实心圆
canvas.drawCircle(it.x, it.y, pointRadius / 2f, mPaint)
mPaint.alpha = 153
canvas.drawCircle(it.x, it.y, pointRadius, mPaint)
}
mPaint.alpha = 255
mPath.reset()
choosePoints.takeIf { it.isNotEmpty() }?.run {
forEach {
mPath.takeIf { it.isEmpty }?.run {
moveTo(it.x, it.y)
} ?: run {
mPath.lineTo(it.x, it.y)
}
}
mPath.lineTo(lastX, lastY)
//制作途径
mPaint.color = Color.BLUE
mPaint.style = Paint.Style.STROKE
canvas.drawPath(mPath, mPaint)
}
}
这段代码中,咱们先依据用户选择的点决定圆点的颜色,并制作实心和空心圆。然后,咱们运用 mPath 跟踪用户选择的途径,并依据途径制作手势解锁的途径。最终,咱们运用 canvas 的 drawPath 办法将途径制作到屏幕上。
4. 处理接触事情
在 onTouchEvent 办法中,咱们处理用户的接触事情,并依据用户的操作更新视图。
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
lastX = event.x
lastY = event.y
allPoints.forEach {
//接触的点和九宫格密码圆相交
if (abs(it.x - lastX) < pointRadius && abs(it.y - lastY) < pointRadius) {
choosePoints.add(it)
}
}
}
MotionEvent.ACTION_MOVE -> {
lastX = event.x
lastY = event.y
allPoints.forEach {
//接触的点和九宫格密码圆相交
if (distanceFromPath(mPath, it.x, it.y) < pointRadius + mStrokeWidth / 2f && choosePoints.contains(it).not()
|| (mPath.isEmpty && abs(it.x - lastX) < pointRadius && abs(it.y - lastY) < pointRadius)
) {
choosePoints.add(it)
lastX = it.x
lastY = it.y
}
}
}
MotionEvent.ACTION_UP -> {
choosePoints.clear()
mPath.reset()
}
}
invalidate()
return true
}
在这段代码中,咱们依据用户的接触事情类型,更新 choosePoints 和 mPath 目标。在 MotionEvent.ACTION_DOWN 中,咱们依据用户接触的方位判断是否与九宫格的圆点相交,并将相交的圆点添加到 choosePoints 调集中。在 MotionEvent.ACTION_MOVE 中,咱们依据用户的接触方位判断是否与九宫格的圆点相交,并更新 choosePoints 调集和最终接触的方位 lastX 和 lastY。在 MotionEvent.ACTION_UP 中,咱们清空 choosePoints 和 mPath 目标,表示用户完成了一次手势解锁操作。最终,咱们调用 invalidate 办法,告诉系统从头制作视图。
5. 辅助办法
在代码的末尾,咱们还定义了一个辅助办法 distanceFromPath,用于核算一个点到途径的最短间隔。
private fun distanceFromPath(path: Path, x: Float, y: Float): Float {
val pathMeasure = PathMeasure(path, false)
val pos = FloatArray(2)
val tan = FloatArray(2)
var distance = Float.MAX_VALUE
var i = 0f
while (i <= pathMeasure.length) {
if (pathMeasure.getPosTan(i, pos, tan)) {
val dx = pos[0] - x
val dy = pos[1] - y
val d = sqrt((dx * dx + dy * dy).toDouble()).toFloat()
if (d < distance) {
distance = d
}
}
i += 1f
}
return distance
}
这个办法运用 PathMeasure 来测量途径的长度,并逐步遍历途径上的点,核算每个点到给定点的间隔。最终返回最短的间隔。
总结
在本文中,咱们具体解说了怎么创立一个自定义的手势解锁视图。咱们经过制作九宫格点和用户选择的途径,实现了手势解锁的功用。希望这篇文章能够帮助你了解并实现自定义视图的过程。如果你对该主题有更多的兴趣,能够进一步探究 Android 的绘图 API 和接触事情处理机制。