<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文範例為大家分享了vue + element ui實現錨點定位的具體程式碼,供大家參考,具體內容如下
介紹下自己編寫的九宮格手勢密碼。先見圖
思路:首先是9個格子,接著是格子連線;那麼我們的步驟就有了。
1.手勢監聽,進行連線
2.格子的狀態未連線(初始狀態)、已連線的(沒有結果前)、錯誤狀態(有結果後)。(先這三個,可延伸,比如按下狀態)
3.自定義viewgroup作為九宮格的容器,裡面包含9個view(小格子)
為了擴充套件性,不自定義view,將三個狀態和有關屬性提取
1.提取屬性,程式碼如下:
class NineChildInf { /** * 當前所在9宮格的位置 * 從1開始 */ var index = 0 /** * 是否被點亮 */ var isLight = false /** * 中心點所在父類別容器內的座標 */ 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.三個狀態,程式碼如下
/** * Created by XinHeng on 2019/02/27. * describe:9宮格子view必須實現此介面 */ abstract class NineChildParent<T : View>(var view: T) { protected open var context = view.context.applicationContext val NINE_CHILD_INF = NineChildInf() /** * 密碼錯誤時的顯示 */ abstract fun setErrorStatue() /** * 被選中時的顯示 */ abstract fun setLightStatue() /** * 預設顯示 */ abstract fun setDefaultStatue() }
既然是九宮格,那自然少不了這些屬性,水平間隔、垂直間隔、最小有效連線數、當前狀態、密碼是否設定完成等。還需要將開啟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 /** * 連線最小有效數位 */ var minEffectiveSize = 4 /** * 小格子的寬高 */ private var childSlide: Int = 30 private val ERROR_STATUE = 2 private val LINKING_STATUE = 1 private val DEFAULT_STATUE = 0 /** * 當前狀態 * 0->最初狀態 DEFAULT_STATUE * 1->正在連線中 LINKING_STATUE * 2->錯誤狀態 ERROR_STATUE */ private var nowStatue = DEFAULT_STATUE /** * 一次密碼設定完成標誌 */ 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 { //使能呼叫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) //又忘了計運算元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 } } } } }
1.手勢監聽,重寫onTouchEvent()方法,必要需要時重寫onInterceptTouchEvent()方法進行攔截(跟情況而定,這裡就不多說了)。簡單的三個手勢狀態按下、移動、擡起。在各個狀態下,記錄座標,並且更新子view(小格子)的ui,還有線條。程式碼片段如下:
override fun onTouchEvent(event: MotionEvent): Boolean { if (childCount == 0 || complete) { return super.onTouchEvent(event) } when (event.action) { MotionEvent.ACTION_DOWN -> { //記錄落點 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 //統計 upUpdateChild() } } return true }
2.連線,在容器的onDraw()方法,進行畫線操作,程式碼片段如下:
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) } }
但是還有一些細節:比如連線中需要判斷中間是否含有小格子、判斷觸點是否在小格子上、連線完成後的回撥、錯誤狀態顯示、恢復初始狀態等。粘出部分程式碼片段(這些只是能實現效果,還可以優化,交給大家了):
1.判斷觸點是否在小格子上
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狀態 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 }
/** * 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 /** * 是否有第一個選中 */ private var firstSelect = true private val ERROR_STATUE = 2 private val LINKING_STATUE = 1 private val DEFAULT_STATUE = 0 /** * 是否顯示線條 */ var showLine = false /** * 連線最小有效數位 */ var minEffectiveSize = 4 /** * 當前狀態 * 0->最初狀態 DEFAULT_STATUE * 1->正在連線中 LINKING_STATUE * 2->錯誤狀態 ERROR_STATUE */ private var nowStatue = DEFAULT_STATUE /** * 一次密碼設定完成標誌 */ 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 { //使能呼叫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) //又忘了計運算元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 -> { //記錄落點 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 //統計 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()) } /** * 錯誤狀態展示 */ fun showErrorStatue() { nowStatue = ERROR_STATUE points.forEach { it.setErrorStatue() } invalidate() resetStatueDelayed(500) } /** * 恢復初始狀態 */ 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狀態 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<*> /** * 密碼設定結束 * @param effective 是否有效 * @param password 密碼 */ fun complete(effective: Boolean, password: String) } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45