Android触屏校验

需求背景,在开机动画结束后弹出触屏校验 :
效果图 :
Android触屏校验_第1张图片
实现方法 :使用WindowManager在launcher上面添加View
具体代码:

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager

/**
 * @ClassName ScreenTestSimple.java
 * @author youdianxiaohuai
 * @Description 触屏校验
 * @createTime 2022年03月01日
 */
@SuppressLint("StaticFieldLeak")
object ScreenTestSimple {
    //监听触屏校验完成
    var onScreenTestOverListener: (() -> Unit)? = null
    private lateinit var context: Context
    private var touchPassed = false
    private var content: View? = null

    @Suppress("DEPRECATION")
    private val params: WindowManager.LayoutParams by lazy {
        val params = WindowManager.LayoutParams()
        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
        params.format = PixelFormat.TRANSLUCENT
        params.width = WindowManager.LayoutParams.MATCH_PARENT
        params.height = WindowManager.LayoutParams.MATCH_PARENT
        params.x = 0
        params.y = 0
        params.gravity = Gravity.CENTER
        params
    }
    private val windowManager: WindowManager by lazy {
        context.applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    }

    /**
     * 使用时调用start方法
     */
    fun start(context: Context) {
        this.context = context
        content = TouchView(context)
        //防止第二次调用时touchPassed = true
        touchPassed = false
        try {
            //防止view没有被remove掉
            windowManager.addView(content, params)
        } catch (e: RuntimeException) {
            windowManager.removeView(content)
        }

    }

    /**
    *触屏校验完成时调用
    *
    */
    private fun onFinish() {
        windowManager.updateViewLayout(content, params)
        onScreenTestOverListener?.invoke()
        windowManager.removeView(content)
        content = null
    }
    
    /**
     * 触屏校验的VIEW
    */
   
    class TouchView(context: Context) : View(context) {


        private val COL_WIDTH_HEIGHT = 31

        private val screenDisplay: Point by lazy {
            val point = Point()
            windowManager.defaultDisplay.getRealSize(point)
            point
        }

        private val screenWidth by lazy { screenDisplay.x }
        private val screenHeight by lazy { screenDisplay.y }

        private val matrixBitmap: Bitmap by lazy {
            Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.RGB_565)
        }
        private val matrixCanvas: Canvas by lazy {
            val canvas = Canvas(matrixBitmap)
            canvas.drawColor(-1)
            canvas
        }

        private val widthBasis: Int by lazy { screenWidth / COL_WIDTH_HEIGHT }
        private val heightBasis: Int by lazy { screenHeight / COL_WIDTH_HEIGHT }
        private val widthBasisCross: Int by lazy { 2 * (widthBasis - 2) }
        private val heightBasisCross: Int by lazy { widthBasisCross }

        private val colWidth: Float by lazy { screenWidth.toFloat() / widthBasis }
        private val colHeight: Float by lazy { screenHeight.toFloat() / heightBasis }

        private val widthCross: Float by lazy { colWidth / 2.0f }
        private val heightCross: Float by lazy { (screenHeight - colHeight) / (4 + (widthBasisCross - 1)) }

        private val draw: Array<IntArray> by lazy { Array(heightBasis) { IntArray(widthBasis) } }
        private val isDrawArea: Array<IntArray> by lazy { Array(heightBasis) { IntArray(widthBasis) } }
        private val drawCross = IntArray(2 * heightBasisCross)

        private var touchedX = 0.0f
        private var touchedY = 0.0f
        private var preTouchedX = 0.0f
        private var preTouchedY = 0.0f
        private var isTouchDown = false

        private val linePaint: Paint by lazy {
            val linePaint = Paint()
            linePaint.isAntiAlias = true
            linePaint.isDither = true
            linePaint.style = Paint.Style.STROKE
            linePaint.strokeJoin = Paint.Join.ROUND
            linePaint.strokeCap = Paint.Cap.SQUARE
            linePaint.strokeWidth = 5.0f
            val localDashPathEffect = DashPathEffect(floatArrayOf(5.0f, 5.0f), 1.0f)
            linePaint.pathEffect = localDashPathEffect
            linePaint.color = -16777216
            linePaint
        }
        private val clickPaint: Paint by lazy {
            val clickPaint = Paint()
            clickPaint.isAntiAlias = false
            clickPaint.style = Paint.Style.FILL
            clickPaint.color = -16711936
            clickPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)
            clickPaint
        }
        private val emptyPaint: Paint by lazy {
            val emptyPaint = Paint()
            emptyPaint.isAntiAlias = false
            emptyPaint.color = -1
            emptyPaint
        }
        
        /**
         * 处理滑动点击事件
         */
        @SuppressLint("ClickableViewAccessibility")
        override fun onTouchEvent(event: MotionEvent): Boolean {
            if (event.getToolType(0) == 2 || touchPassed) {
                return if (touchPassed) {
                    super.onTouchEvent(event)
                } else {
                    true
                }
            }
            when (event.action) {
                MotionEvent.ACTION_DOWN -> drawDown(event)
                MotionEvent.ACTION_UP -> drawUp(event)
                MotionEvent.ACTION_MOVE -> drawMove(event)
                else -> {
                }
            }
            return true
        }

        override fun onDraw(canvas: Canvas) {
            canvas.drawBitmap(matrixBitmap, 0.0f, 0.0f, null)
        }

        init {
            val paint1 = Paint()
            val paint2 = Paint()
            paint1.color = -16777216
            paint2.color = -16777216
            paint2.style = Paint.Style.STROKE
            //先全部画格子
            for (i in 0..heightBasis) {
                val y = (colHeight * i)
                matrixCanvas.drawLine(0.0f, y, screenWidth.toFloat(), y, paint1)
            }
            for (i in 0..widthBasis) {
                val x = (colWidth * i)
                matrixCanvas.drawLine(x, 0.0f, x, screenHeight.toFloat(), paint1)
            }
            //把中间涂白  480时的涂白高度范围如果不上下缩小1会少点线,但是600的不会,应该是精度问题,其他也会,全部都这样好了
            matrixCanvas.drawRect(
                1 + colWidth, 1 + colHeight,
                colWidth * (widthBasis - 1) - 1, colHeight * (heightBasis - 1) - 1, emptyPaint
            )

            //记录进数组
            for (i in 0 until heightBasis) {
                for (j in 0 until widthBasis) {
                    draw[i][j] = 0
                    if (i == 0 || i == heightBasis - 1 || j == 0 || j == widthBasis - 1) {
                        isDrawArea[i][j] = 1
                    }
                }
            }

            //再画斜向和记录进数组
            for (i in 0 until heightBasisCross) {
                val x1 = (widthCross * (i + 2))
                val y1 = heightCross * (i + 2)
                matrixCanvas.drawRect(x1, y1, x1 + colWidth / 2, y1 + colHeight, paint2)
                drawCross[i] = 0

                val x3 = (widthCross * (i + 2))
                val y3 = (screenHeight - (colHeight + heightCross * (i + 2)))
                matrixCanvas.drawRect(x3, y3, x3 + colWidth / 2, y3 + colHeight, paint2)
                drawCross[i + heightBasisCross] = 0
            }
        }

        private fun isPass(): Boolean {
            for (i in 0 until heightBasis) {
                for (j in 0 until widthBasis) {
                    if (isDrawArea[i][j] == 1) {
                        if (draw[i][j] == 0) {
                            return false
                        }
                    }
                }
            }
            return true
        }

        private fun isPassCross(): Boolean {
            for (i in 0 until 2 * heightBasisCross) {
                if (drawCross[i] == 0) {
                    return false
                }
            }
            return true
        }

        private fun drawDown(event: MotionEvent) {
            touchedX = event.x
            touchedY = event.y
            isTouchDown = drawRect(touchedX, touchedY, clickPaint)
        }

        private fun drawRect(x: Float, y: Float, paint: Paint): Boolean {
            val xIndex = (x / colWidth).toInt()
            val yIndex = (y / colHeight).toInt()
            if (xIndex >= 0 && yIndex >= 0 && xIndex < widthBasis && yIndex < heightBasis) {
                if (draw[yIndex][xIndex] == 0) {
                    draw[yIndex][xIndex] = 1
                    if (isDrawArea[yIndex][xIndex] != 0) {
                        val rectX = colWidth * xIndex
                        val rectY = colHeight * yIndex
                        matrixCanvas.drawRect(
                            rectX,
                            colHeight * yIndex,
                            rectX + colWidth,
                            rectY + colHeight,
                            paint
                        )
                        invalidate()
                    }
                }
                if (xIndex > 0 && xIndex < widthBasis - 1) {
                    checkCrossRectRegion(x, y, paint)
                }
                if (isPass() && isPassCross()) {
                    touchPassed = true
                    onFinish()
                    return false
                }
            }
            return true
        }

        private fun checkCrossRectRegion(x: Float, y: Float, paint: Paint) {
            val crossIndex = ((x - colWidth) / widthCross).toInt()
            val crossX = (widthCross * (crossIndex + 2))
            val crossY = (heightCross * (crossIndex + 2))

            if (y > crossY && y < crossY + colHeight) {
                if (drawCross[crossIndex] == 0) {
                    matrixCanvas.drawRect(
                        crossX,
                        crossY,
                        crossX + widthCross,
                        crossY + colHeight,
                        paint
                    )
                    invalidate()
                    drawCross[crossIndex] = 1
                }
            }
            val crossY2 = screenHeight - colHeight - crossY
            if (y > crossY2 && y < crossY2 + colHeight) {
                val index = 2 * widthBasisCross - 1 - crossIndex
                if (drawCross[index] == 0) {
                    matrixCanvas.drawRect(
                        crossX,
                        crossY2,
                        (crossX + colWidth / 2.0f),
                        (crossY2 + colHeight),
                        paint
                    )
                    invalidate()
                    drawCross[index] = 1
                }
            }
        }

        private fun drawMove(event: MotionEvent) {
            if (isTouchDown) {
                preTouchedX = touchedX
                preTouchedY = touchedY
                touchedX = event.x
                touchedY = event.y
                matrixCanvas.drawLine(preTouchedX, preTouchedY, touchedX, touchedY, linePaint)
                invalidate()
                isTouchDown = drawRect(touchedX, touchedY, clickPaint)
            }
        }

        private fun drawUp(paramMotionEvent: MotionEvent) {
            if (isTouchDown) {
                preTouchedX = touchedX
                preTouchedY = touchedY
                touchedX = paramMotionEvent.x
                touchedY = paramMotionEvent.y
                if (preTouchedX == touchedX && preTouchedY == touchedY) {
                    matrixCanvas.drawPoint(touchedX, touchedY, linePaint)
                    invalidate()
                }
                isTouchDown = false
            }
        }

    }
}

你可能感兴趣的:(android,自定义View,WindowManager)