Android實(shí)現(xiàn)九宮格手勢密碼
本文實(shí)例為大家分享了Android實(shí)現(xiàn)九宮格手勢密碼的具體代碼,供大家參考,具體內(nèi)容如下
介紹下自己編寫的九宮格手勢密碼。先見圖
思路:首先是9個(gè)格子,接著是格子連線;那么我們的步驟就有了。
1.手勢監(jiān)聽,進(jìn)行連線
2.格子的狀態(tài)未連接(初始狀態(tài))、已連接的(沒有結(jié)果前)、錯(cuò)誤狀態(tài)(有結(jié)果后)。(先這三個(gè),可擴(kuò)展,比如按下狀態(tài))
3.自定義viewgroup作為九宮格的容器,里面包含9個(gè)view(小格子)
一、先從簡單的說起吧,9個(gè)小格子以及狀態(tài)
為了擴(kuò)展性,不自定義view,將三個(gè)狀態(tài)和有關(guān)屬性提取
1.提取屬性,代碼如下:
class NineChildInf { ? ? ? ? /** ? ? ? ? ?* 當(dāng)前所在9宮格的位置 ? ? ? ? ?* 從1開始 ? ? ? ? ?*/ ? ? ? ? var index = 0 ? ? ? ? /** ? ? ? ? ?* 是否被點(diǎn)亮 ? ? ? ? ?*/ ? ? ? ? var isLight = false ? ? ? ? /** ? ? ? ? ?* 中心點(diǎn)所在父類容器內(nèi)的坐標(biāo) ? ? ? ? ?*/ ? ? ? ? var centerX = 0.toFloat() ? ? ? ? var centerY = 0.toFloat() ? ? ? ? ? fun setContent(index: Int, centerX: Float, centerY: Float) { ? ? ? ? ? ? this.index = index ? ? ? ? ? ? this.centerX = centerX ? ? ? ? ? ? this.centerY = centerY ? ? ? ? } ? ? ? ? ? constructor() ? ? ? ? ? fun updateCenterPoint(x: Float, y: Float) { ? ? ? ? ? ? this.centerX = x ? ? ? ? ? ? this.centerY = y ? ? ? ? } ? ? ? ? ? fun reset() { ? ? ? ? ? ? this.index = 0 ? ? ? ? ? ? this.centerX = 0f ? ? ? ? ? ? this.centerY = 0f ? ? ? ? ? ? this.isLight = false ? ? ? ? } ? ? ? ? ? override fun toString(): String { ? ? ? ? ? ? return "NineChildInf(index=$index, isLight=$isLight, centerX=$centerX, centerY=$centerY)" ? ? ? ? } ? ? }
2.三個(gè)狀態(tài),代碼如下
/** ?* Created by XinHeng on 2019/02/27. ?* describe:9宮格子view必須實(shí)現(xiàn)此接口 ?*/ abstract class NineChildParent<T : View>(var view: T) { ? ? protected open var context = view.context.applicationContext ? ? val NINE_CHILD_INF = NineChildInf() ? ? /** ? ? ?* 密碼錯(cuò)誤時(shí)的顯示 ? ? ?*/ ? ? abstract fun setErrorStatue() ? ? ? /** ? ? ?* 被選中時(shí)的顯示 ? ? ?*/ ? ? abstract fun setLightStatue() ? ? ? /** ? ? ?* 默認(rèn)顯示 ? ? ?*/ ? ? abstract fun setDefaultStatue() ? }
二、自定義九宮格容器,NineViewGroup。
既然是九宮格,那自然少不了這些屬性,水平間隔、垂直間隔、最小有效連接數(shù)、當(dāng)前狀態(tài)、密碼是否設(shè)置完成等。還需要將開啟viewgroup的onDraw()方法。具體代碼如下:
class NineViewGroup @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ViewGroup(context, attrs, defStyleAttr) { ? ? /** ? ? ?* 水平間的間隔 ? ? ?*/ ? ? private var paddingH = 60 ? ? /** ? ? ?* 垂直間的間隔 ? ? ?*/ ? ? private var paddingV = 60 ? ? /** ? ? ?* 連線最小有效數(shù)字 ? ? ?*/ ? ? var minEffectiveSize = 4 ? ? /** ? ? ?* 小格子的寬高 ? ? ?*/ ? ? private var childSlide: Int = 30 ? ? private val ERROR_STATUE = 2 ? ? private val LINKING_STATUE = 1 ? ? private val DEFAULT_STATUE = 0 ? ? /** ? ? ?* 當(dāng)前狀態(tài) ? ? ?* 0->最初狀態(tài) DEFAULT_STATUE ? ? ?* 1->正在連線中 LINKING_STATUE ? ? ?* 2->錯(cuò)誤狀態(tài) ERROR_STATUE ? ? ?*/ ? ? private var nowStatue = DEFAULT_STATUE ? ? /** ? ? ?* 一次密碼設(shè)置完成標(biāo)志 ? ? ?*/ ? ? private var complete = false ? ? /** ? ? ?* 線條寬度 ? ? ?*/ ? ? private var lineWidth = 5 ? ? private var lineColor = Color.parseColor("#33b5e5") ? ? private var errorLineColor = Color.RED ? ? private var childViews = ArrayList<NineChildParent<*>>(9) ? ? init { ? ? ? ? //使能調(diào)用onDraw()方法 ? ? ? ? setWillNotDraw(false) ? ? ? ? var array = context.obtainStyledAttributes(attrs, R.styleable.NineViewGroup, defStyleAttr, 0) ? ? ? ? (0..array.indexCount).forEach { ? ? ? ? ? ? var index = array.getIndex(it) ? ? ? ? ? ? when (index) { ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_child_size -> childSlide = array.getDimensionPixelSize(index, childSlide) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_line_color -> lineColor = array.getColor(index, lineColor) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_error_line_color -> errorLineColor = array.getColor(index, errorLineColor) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_effective_size -> minEffectiveSize = array.getInt(index, minEffectiveSize) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_padding_h -> paddingH = array.getDimensionPixelSize(index, paddingH) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_padding_v -> paddingV = array.getDimensionPixelSize(index, paddingV) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_line_width -> lineWidth = array.getDimensionPixelSize(index, lineWidth) ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? array.recycle() ? ? ?? ? ? } ? ? override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { ? ? ? ? var width = childSlide * 3 + paddingLeft + paddingRight + paddingH * 2 ? ? ? ? var height = childSlide * 3 + paddingTop + paddingBottom + paddingV * 2 ? ? ? ? setMeasuredDimension(width, height) ? ? ? ? //又忘了計(jì)算子view的大小了。。。 ? ? ? ? measureChildren(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)) ? ? } ? ? override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { ? ? ? ? var childView: View ? ? ? ? var top: Int = paddingTop ? ? ? ? var left: Int = paddingLeft ? ? ? ? var right: Int ? ? ? ? var bottom: Int ? ? ? ? if (childCount > 0) { ? ? ? ? ? ? (0 until childCount).forEach { ? ? ? ? ? ? ? ? childView = getChildAt(it) ? ? ? ? ? ? ? ? right = left + childView.measuredWidth ? ? ? ? ? ? ? ? bottom = top + childView.measuredHeight ? ? ? ? ? ? ? ? //Log.e("TAG", "onLayout: $left $top $right $bottom") ? ? ? ? ? ? ? ? var nineChildInf = (childViews[it]).NINE_CHILD_INF ? ? ? ? ? ? ? ? nineChildInf.setContent(it + 1, (left + right) / 2f, (top + bottom) / 2f) ? ? ? ? ? ? ? ? //Log.e("TAG", "onLayout: child=$nineChildInf") ? ? ? ? ? ? ? ? childView.layout(left, top, right, bottom) ? ? ? ? ? ? ? ? if ((it + 1) % 3 == 0) { ? ? ? ? ? ? ? ? ? ? left = paddingLeft ? ? ? ? ? ? ? ? ? ? top = bottom + paddingV ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? left = right + paddingH ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? } }
三、手勢監(jiān)聽、連線
1.手勢監(jiān)聽,重寫onTouchEvent()方法,必要需要時(shí)重寫onInterceptTouchEvent()方法進(jìn)行攔截(跟情況而定,這里就不多說了)。簡單的三個(gè)手勢狀態(tài)按下、移動(dòng)、抬起。在各個(gè)狀態(tài)下,記錄坐標(biāo),并且更新子view(小格子)的ui,還有線條。代碼片段如下:
override fun onTouchEvent(event: MotionEvent): Boolean { ? ? ? ? if (childCount == 0 || complete) { ? ? ? ? ? ? return super.onTouchEvent(event) ? ? ? ? } ? ? ? ? when (event.action) { ? ? ? ? ? ? MotionEvent.ACTION_DOWN -> { ? ? ? ? ? ? ? ? //記錄落點(diǎn) ? ? ? ? ? ? ? ? lastX = event.x ? ? ? ? ? ? ? ? lastY = event.y ? ? ? ? ? ? ? ? downUpdateChild(lastX, lastY) ? ? ? ? ? ? } ? ? ? ? ? ? MotionEvent.ACTION_MOVE -> { ? ? ? ? ? ? ? ? lastX = event.x ? ? ? ? ? ? ? ? lastY = event.y ? ? ? ? ? ? ? ? moveUpdateChild(lastX, lastY) ? ? ? ? ? ? } ? ? ? ? ? ? MotionEvent.ACTION_UP -> { ? ? ? ? ? ? ? ? complete = true ? ? ? ? ? ? ? ? //統(tǒng)計(jì) ? ? ? ? ? ? ? ? upUpdateChild() ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return true ? ? }
2.連線,在容器的onDraw()方法,進(jìn)行畫線操作,代碼片段如下:
override fun onDraw(canvas: Canvas) { ? ? ? ? super.onDraw(canvas) ? ? ? ? if (!showLine) { ? ? ? ? ? ? return ? ? ? ? } ? ? ? ? paint.color = when (nowStatue) { ? ? ? ? ? ? ERROR_STATUE -> errorLineColor ? ? ? ? ? ? else -> lineColor ? ? ? ? } ? ? ? ? if (points.size > 1) { ? ? ? ? ? ? (1 until points.size).forEach { ? ? ? ? ? ? ? ? var pointXYStart = points[it - 1].NINE_CHILD_INF ? ? ? ? ? ? ? ? var pointXYEnd = points[it].NINE_CHILD_INF ? ? ? ? ? ? ? ? canvas.drawLine(pointXYStart.centerX, pointXYStart.centerY, pointXYEnd.centerX, pointXYEnd.centerY, paint) ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? if (lastX > 0 && points.size > 0) { ? ? ? ? ? ? var pointXY = points[points.size - 1].NINE_CHILD_INF ? ? ? ? ? ? canvas.drawLine(pointXY.centerX, pointXY.centerY, lastX, lastY, paint) ? ? ? ? } ? ? }
四、進(jìn)行到這一步,大致的步驟就是這了。
但是還有一些細(xì)節(jié):比如連線中需要判斷中間是否含有小格子、判斷觸點(diǎn)是否在小格子上、連接完成后的回調(diào)、錯(cuò)誤狀態(tài)顯示、恢復(fù)初始狀態(tài)等。粘出部分代碼片段(這些只是能實(shí)現(xiàn)效果,還可以優(yōu)化,交給大家了):
1.判斷觸點(diǎn)是否在小格子上
private fun childContains(x: Float, y: Float): Boolean { ? ? ? ? (0 until childCount).forEach { ? ? ? ? ? ? var childAt = getChildAt(it) ? ? ? ? ? ? //這一句,循環(huán)判斷,是否屬于其范圍 ? ? ? ? ? ? if (x >= childAt.left && x < childAt.right && y >= childAt.top && y < childAt.bottom) { ? ? ? ? ? ? ? ? return if (!childViews[it].NINE_CHILD_INF.isLight) { ? ? ? ? ? ? ? ? ? ? if (points.size > 0) { ? ? ? ? ? ? ? ? ? ? ? ? checkMiddleChild(points[points.size - 1], childViews[it])?.run { ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (!NINE_CHILD_INF.isLight) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? buffer.append(NINE_CHILD_INF.index) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? changeLightStatue(this) ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? buffer.append(it + 1) ? ? ? ? ? ? ? ? ? ? //TODO 改變子view的UI狀態(tài) ? ? ? ? ? ? ? ? ? ? changeLightStatue(childViews[it]) ? ? ? ? ? ? ? ? ? ? true ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? false ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return false ? ? }
2.判斷中間是否含有小格子
private fun checkMiddleChild(nineChildParent: NineChildParent<*>, nineChildParent1: NineChildParent<*>): NineChildParent<*>? { ? ? ? ? var index = nineChildParent.NINE_CHILD_INF.index ? ? ? ? var index1 = nineChildParent1.NINE_CHILD_INF.index ? ? ? ? var sum = index + index1 ? ? ? ? if (sum == 10) { ? ? ? ? ? ? return childViews[4] ? ? ? ? } else if (index % 2 != 0 && index1 % 2 != 0) { ? ? ? ? ? ? if ((sum == 4 || sum == 16) || (sum == 8 && (index == 1 || index1 == 1))||(sum == 12 && (index == 3 || index1 == 3))) ? ? ? ? ? ? ? ? return childViews[sum / 2 - 1] ? ? ? ? } ? ? ? ? return null ? ? }
五、如有bug歡迎留言指出,下面粘出九宮格容器的全部代碼。
/** ?* Created by XinHeng on 2019/01/29. ?* describe:九宮格的容器 ?*/ class NineViewGroup @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ViewGroup(context, attrs, defStyleAttr) { ? ? /** ? ? ?* 水平間的間隔 ? ? ?*/ ? ? private var paddingH = 60 ? ? /** ? ? ?* 垂直間的間隔 ? ? ?*/ ? ? private var paddingV = 60 ? ? /** ? ? ?* 是否有第一個(gè)選中 ? ? ?*/ ? ? private var firstSelect = true ? ? private val ERROR_STATUE = 2 ? ? private val LINKING_STATUE = 1 ? ? private val DEFAULT_STATUE = 0 ? ? /** ? ? ?* 是否顯示線條 ? ? ?*/ ? ? var showLine = false ? ? /** ? ? ?* 連線最小有效數(shù)字 ? ? ?*/ ? ? var minEffectiveSize = 4 ? ? /** ? ? ?* 當(dāng)前狀態(tài) ? ? ?* 0->最初狀態(tài) DEFAULT_STATUE ? ? ?* 1->正在連線中 LINKING_STATUE ? ? ?* 2->錯(cuò)誤狀態(tài) ERROR_STATUE ? ? ?*/ ? ? private var nowStatue = DEFAULT_STATUE ? ? /** ? ? ?* 一次密碼設(shè)置完成標(biāo)志 ? ? ?*/ ? ? private var complete = false ? ? /** ? ? ?* 線條寬度 ? ? ?*/ ? ? private var lineWidth = 5 ? ? private var lastX: Float = 0f ? ? private var lastY: Float = 0f ? ? private var buffer = StringBuilder() ? ? private var points = ArrayList<NineChildParent<*>>(9) ? ? private var childViews = ArrayList<NineChildParent<*>>(9) ? ? /** ? ? ?* 小格子的寬高 ? ? ?*/ ? ? private var childSlide: Int = 30 ? ? private var lineColor = Color.parseColor("#33b5e5") ? ? private var errorLineColor = Color.RED ? ? var onNineViewGroupListener: OnNineViewGroupListener? = null ? ? ? ? set(value) { ? ? ? ? ? ? field = value ? ? ? ? ? ? value?.let { ? ? ? ? ? ? ? ? setChildMode(it) ? ? ? ? ? ? } ? ? ? ? } ? ? private val paint = Paint().apply { ? ? ? ? isAntiAlias = true ? ? ? ? isDither = true ? ? } ? ? ? init { ? ? ? ? //使能調(diào)用onDraw()方法 ? ? ? ? setWillNotDraw(false) ? ? ? ? var array = context.obtainStyledAttributes(attrs, R.styleable.NineViewGroup, defStyleAttr, 0) ? ? ? ? (0..array.indexCount).forEach { ? ? ? ? ? ? var index = array.getIndex(it) ? ? ? ? ? ? when (index) { ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_child_size -> childSlide = array.getDimensionPixelSize(index, childSlide) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_line_color -> lineColor = array.getColor(index, lineColor) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_error_line_color -> errorLineColor = array.getColor(index, errorLineColor) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_effective_size -> minEffectiveSize = array.getInt(index, minEffectiveSize) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_padding_h -> paddingH = array.getDimensionPixelSize(index, paddingH) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_padding_v -> paddingV = array.getDimensionPixelSize(index, paddingV) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_show_line -> showLine = array.getBoolean(index, showLine) ? ? ? ? ? ? ? ? R.styleable.NineViewGroup_nine_line_width -> lineWidth = array.getDimensionPixelSize(index, lineWidth) ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? array.recycle() ? ? ? ? paint.strokeWidth = lineWidth.toFloat() ? ? } ? ? ? private fun setChildMode(onNineViewGroupListener: OnNineViewGroupListener) { ? ? ? ? removeAllViews() ? ? ? ? childViews.clear() ? ? ? ? (0..8).forEach { ? ? ? ? ? ? var mode = onNineViewGroupListener.getChildMode() ? ? ? ? ? ? mode.NINE_CHILD_INF.index = it + 1 ? ? ? ? ? ? mode.setDefaultStatue() ? ? ? ? ? ? addView(mode.view, getLp()) ? ? ? ? ? ? childViews.add(mode) ? ? ? ? } ? ? } ? ? ? private fun getLp(): LayoutParams { ? ? ? ? return LayoutParams(childSlide, childSlide) ? ? } ? ? ? override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { ? ? ? ? var width = childSlide * 3 + paddingLeft + paddingRight + paddingH * 2 ? ? ? ? var height = childSlide * 3 + paddingTop + paddingBottom + paddingV * 2 ? ? ? ? setMeasuredDimension(width, height) ? ? ? ? //又忘了計(jì)算子view的大小了。。。 ? ? ? ? measureChildren(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)) ? ? } ? ? ? override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { ? ? ? ? var childView: View ? ? ? ? var top: Int = paddingTop ? ? ? ? var left: Int = paddingLeft ? ? ? ? var right: Int ? ? ? ? var bottom: Int ? ? ? ? if (childCount > 0) { ? ? ? ? ? ? (0 until childCount).forEach { ? ? ? ? ? ? ? ? childView = getChildAt(it) ? ? ? ? ? ? ? ? right = left + childView.measuredWidth ? ? ? ? ? ? ? ? bottom = top + childView.measuredHeight ? ? ? ? ? ? ? ? //Log.e("TAG", "onLayout: $left $top $right $bottom") ? ? ? ? ? ? ? ? var nineChildInf = (childViews[it]).NINE_CHILD_INF ? ? ? ? ? ? ? ? nineChildInf.setContent(it + 1, (left + right) / 2f, (top + bottom) / 2f) ? ? ? ? ? ? ? ? //Log.e("TAG", "onLayout: child=$nineChildInf") ? ? ? ? ? ? ? ? childView.layout(left, top, right, bottom) ? ? ? ? ? ? ? ? if ((it + 1) % 3 == 0) { ? ? ? ? ? ? ? ? ? ? left = paddingLeft ? ? ? ? ? ? ? ? ? ? top = bottom + paddingV ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? left = right + paddingH ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { ? ? ? ? return true ? ? } ? ? override fun onTouchEvent(event: MotionEvent): Boolean { ? ? ? ? if (childCount == 0 || complete) { ? ? ? ? ? ? return super.onTouchEvent(event) ? ? ? ? } ? ? ? ? when (event.action) { ? ? ? ? ? ? MotionEvent.ACTION_DOWN -> { ? ? ? ? ? ? ? ? //記錄落點(diǎn) ? ? ? ? ? ? ? ? lastX = event.x ? ? ? ? ? ? ? ? lastY = event.y ? ? ? ? ? ? ? ? downUpdateChild(lastX, lastY) ? ? ? ? ? ? } ? ? ? ? ? ? MotionEvent.ACTION_MOVE -> { ? ? ? ? ? ? ? ? lastX = event.x ? ? ? ? ? ? ? ? lastY = event.y ? ? ? ? ? ? ? ? moveUpdateChild(lastX, lastY) ? ? ? ? ? ? } ? ? ? ? ? ? MotionEvent.ACTION_UP -> { ? ? ? ? ? ? ? ? complete = true ? ? ? ? ? ? ? ? //統(tǒng)計(jì) ? ? ? ? ? ? ? ? upUpdateChild() ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return true ? ? } ? ? ? private fun downUpdateChild(x: Float, y: Float) { ? ? ? ? firstSelect = childContains(x, y) ? ? } ? ? ? private fun moveUpdateChild(x: Float, y: Float) { ? ? ? ? if (firstSelect) { ? ? ? ? ? ? moveUpdateLineAndChildView(x, y) ? ? ? ? } else { ? ? ? ? ? ? downUpdateChild(x, y) ? ? ? ? } ? ? } ? ? ? private fun moveUpdateLineAndChildView(x: Float, y: Float) { ? ? ? ? if (points.size != childCount) ? ? ? ? ? ? childContains(x, y) ? ? ? ? invalidate() ? ? } ? ? ? private fun upUpdateChild() { ? ? ? ? var effective = points.size >= minEffectiveSize ? ? ? ? onNineViewGroupListener?.complete(effective, buffer.toString()) ? ? } ? ? ? /** ? ? ?* 錯(cuò)誤狀態(tài)展示 ? ? ?*/ ? ? fun showErrorStatue() { ? ? ? ? nowStatue = ERROR_STATUE ? ? ? ? points.forEach { ? ? ? ? ? ? it.setErrorStatue() ? ? ? ? } ? ? ? ? invalidate() ? ? ? ? resetStatueDelayed(500) ? ? } ? ? ? /** ? ? ?* 恢復(fù)初始狀態(tài) ? ? ?*/ ? ? private fun resetStatue() { ? ? ? ? points.clear() ? ? ? ? firstSelect = false ? ? ? ? lastX = 0f ? ? ? ? lastY = 0f ? ? ? ? buffer.clear() ? ? ? ? nowStatue = DEFAULT_STATUE ? ? ? ? (0 until childCount).forEach { ? ? ? ? ? ? var nineChildParent = childViews[it] ? ? ? ? ? ? nineChildParent.setDefaultStatue() ? ? ? ? ? ? nineChildParent.NINE_CHILD_INF.isLight = false ? ? ? ? } ? ? ? ? invalidate() ? ? ? ? complete = false ? ? } ? ? ? fun resetStatueDelayed(time: Int) { ? ? ? ? postDelayed({ resetStatue() }, time.toLong()) ? ? } ? ? ? private fun childContains(x: Float, y: Float): Boolean { ? ? ? ? (0 until childCount).forEach { ? ? ? ? ? ? var childAt = getChildAt(it) ? ? ? ? ? ? if (x >= childAt.left && x < childAt.right && y >= childAt.top && y < childAt.bottom) { ? ? ? ? ? ? ? ? return if (!childViews[it].NINE_CHILD_INF.isLight) { ? ? ? ? ? ? ? ? ? ? if (points.size > 0) { ? ? ? ? ? ? ? ? ? ? ? ? checkMiddleChild(points[points.size - 1], childViews[it])?.run { ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (!NINE_CHILD_INF.isLight) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? buffer.append(NINE_CHILD_INF.index) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? changeLightStatue(this) ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? buffer.append(it + 1) ? ? ? ? ? ? ? ? ? ? //TODO 改變子view的UI狀態(tài) ? ? ? ? ? ? ? ? ? ? changeLightStatue(childViews[it]) ? ? ? ? ? ? ? ? ? ? true ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? false ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return false ? ? } ? ? ? private fun changeLightStatue(childParent: NineChildParent<*>) { ? ? ? ? childParent.NINE_CHILD_INF.isLight = true ? ? ? ? childParent.setLightStatue() ? ? ? ? points.add(childParent)//記錄 ? ? } ? ? ? private fun checkMiddleChild(nineChildParent: NineChildParent<*>, nineChildParent1: NineChildParent<*>): NineChildParent<*>? { ? ? ? ? var index = nineChildParent.NINE_CHILD_INF.index ? ? ? ? var index1 = nineChildParent1.NINE_CHILD_INF.index ? ? ? ? var sum = index + index1 ? ? ? ? if (sum == 10) { ? ? ? ? ? ? return childViews[4] ? ? ? ? } else if (index % 2 != 0 && index1 % 2 != 0) { ? ? ? ? ? ? if ((sum == 4 || sum == 16) || (sum == 8 && (index == 1 || index1 == 1))||(sum == 12 && (index == 3 || index1 == 3))) ? ? ? ? ? ? ? ? return childViews[sum / 2 - 1] ? ? ? ? } ? ? ? ? return null ? ? } ? ? ? override fun onDraw(canvas: Canvas) { ? ? ? ? super.onDraw(canvas) ? ? ? ? if (!showLine) { ? ? ? ? ? ? return ? ? ? ? } ? ? ? ? paint.color = when (nowStatue) { ? ? ? ? ? ? ERROR_STATUE -> errorLineColor ? ? ? ? ? ? else -> lineColor ? ? ? ? } ? ? ? ? if (points.size > 1) { ? ? ? ? ? ? (1 until points.size).forEach { ? ? ? ? ? ? ? ? var pointXYStart = points[it - 1].NINE_CHILD_INF ? ? ? ? ? ? ? ? var pointXYEnd = points[it].NINE_CHILD_INF ? ? ? ? ? ? ? ? canvas.drawLine(pointXYStart.centerX, pointXYStart.centerY, pointXYEnd.centerX, pointXYEnd.centerY, paint) ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? if (lastX > 0 && points.size > 0) { ? ? ? ? ? ? var pointXY = points[points.size - 1].NINE_CHILD_INF ? ? ? ? ? ? canvas.drawLine(pointXY.centerX, pointXY.centerY, lastX, lastY, paint) ? ? ? ? } ? ? } ? ? ? interface OnNineViewGroupListener { ? ? ? ? /** ? ? ? ? ?* 子view ? ? ? ? ?*/ ? ? ? ? fun getChildMode(): NineChildParent<*> ? ? ? ? ? /** ? ? ? ? ?* 密碼設(shè)置結(jié)束 ? ? ? ? ?* @param effective 是否有效 ? ? ? ? ?* @param password 密碼 ? ? ? ? ?*/ ? ? ? ? fun complete(effective: Boolean, password: String) ? ? } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android傳感器SensorEventListener之加速度傳感器
今天小編就為大家分享一篇關(guān)于Android傳感器SensorEventListener之加速度傳感器,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02RecyclerView實(shí)現(xiàn)拖拽排序效果
這篇文章主要為大家詳細(xì)介紹了RecyclerView實(shí)現(xiàn)拖拽排序效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06android TextView設(shè)置中文字體加粗實(shí)現(xiàn)方法
android TextView設(shè)置中文字體加粗如何實(shí)現(xiàn),接下來介紹實(shí)現(xiàn)方法,有需要的朋友可以參考下2013-01-01Android6.0 動(dòng)態(tài)權(quán)限機(jī)制深入講解
這篇文章主要給大家介紹了關(guān)于Android6.0 動(dòng)態(tài)權(quán)限機(jī)制的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08Android自定義View實(shí)現(xiàn)左右滑動(dòng)選擇出生年份
這篇文章主要介紹了Android自定義View實(shí)現(xiàn)左右滑動(dòng)選擇出生年份,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06Android開發(fā)中l(wèi)ibs和jinLibs文件夾的作用詳解
這篇文章主要給大家介紹了關(guān)于Android開發(fā)中l(wèi)ibs和jinLibs文件夾的作用的相關(guān)資料,文中通過圖文及示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-09-09Android編輯框EditText與焦點(diǎn)變更監(jiān)視器及文本變化監(jiān)視器實(shí)現(xiàn)流程詳解
這篇文章主要介紹了Android編輯框EditText與焦點(diǎn)變更監(jiān)視器及文本變化監(jiān)視器實(shí)現(xiàn)流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-09-09Android Rreact Native 常見錯(cuò)誤總結(jié)
這篇文章主要介紹了Android Rreact Native 常見錯(cuò)誤總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-06-06