return false } } return true; }

完整代码

当然还有些细节没提到,可在以下代码啊中查看,比如在长按后,显示原图,

package com.example.kotlindemo

import android.animation.Animator import android.animation.Animator.AnimatorListener import android.animation.AnimatorSet import android.animation.ValueAnimator import android.content.Context import android.graphics.* import android.os.Handler import android.util.AttributeSet import android.util.Log import android.view.GestureDetector import android.view.MotionEvent import android.view.View import android.view.animation.* import android.view.animation.Interpolator import android.widget.Toast import kotlin.math.min import kotlin.random.Random

class JigsawView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr), GestureDetector.OnGestureListener {

private var TAG = “TAG”;

//表格大小 private var tableSize = 3;

//二维数组,存放图标块 private val pictureBlock2dMap = Array(tableSize) { Array(tableSize) { null } }

//手势监听 private var gestureDetector: GestureDetector = GestureDetector(context, this);

//是否开始 private var isStart: Boolean = false;

//空白点坐标 private var moveBlockPoint: Point = Point(-1, -1);

//top偏移 private var offsetTop: Int = 0;

//图片大小 private var gridItemSize = 0; private var slideAnimatorDuration: Long = 150; private var showSourceBitmap = false; //移动步数 private var step: Int = 0;

private var itemMovInterpolator:Interpolator=OvershootInterpolator() //目标Bitmap private lateinit var targetPicture: Bitmap;

fun setPicture(bitmap: Bitmap) { post { targetPicture = bitmap.getCenterBitmap(); parsePicture(); step = 0; } }

//分割图片 private fun parsePicture() { var top = 0; var left = 0; var postion = 0; for (i in pictureBlock2dMap.indices) { for (j in pictureBlock2dMap[i].indices) { postion++; left = j * gridItemSize; top = i * gridItemSize; pictureBlock2dMap[i][j] = PictureBlock( createBitmap(left, top, gridItemSize), postion, left, top ) } } pictureBlock2dMap[tableSize - 1][tableSize - 1]!!.bitmap = createSolidColorBitmap(width) isStart = true; randomPostion(); invalidate()

}

private fun randomPostion() { for (i in 1…pictureBlock2dMap.size * pictureBlock2dMap.size) { var srcIndex = Random.nextInt(0, pictureBlock2dMap.size); var dstIndex = Random.nextInt(0, pictureBlock2dMap.size); var srcIndex1 = Random.nextInt(0, pictureBlock2dMap.size); var dstIndex2 = Random.nextInt(0, pictureBlock2dMap.size); pictureBlock2dMap[srcIndex][dstIndex]!!.swap(pictureBlock2dMap[srcIndex1][dstIndex2]!!); }

for (i in pictureBlock2dMap.indices) { for (j in pictureBlock2dMap[i].indices) { var item = pictureBlock2dMap[i][j]!!; if (item.postion == tableSize * tableSize) { moveBlockPoint.set(i, j) return } } } }

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) offsetTop = (h - w) / 2; gridItemSize = w / tableSize; }

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) var min = min(widthMeasureSpec, heightMeasureSpec) setMeasuredDimension(min, min) }

override fun onDraw(canvas: Canvas) { if (!isStart) { return } if (showSourceBitmap) { var pictureRect = Rect(0, 0, targetPicture.width, targetPicture.height); var rect = Rect(0, 0, measuredWidth, measuredHeight); canvas.drawBitmap(targetPicture, pictureRect, rect, Paint()) return } var left: Int = 0; var top: Int = 0; for (i in pictureBlock2dMap.indices) { for (j in pictureBlock2dMap[i].indices) { var item = pictureBlock2dMap[i][j]!!; left = item.left; top = item.top; var bitmap = pictureBlock2dMap[i][j]!!.bitmap; var pictureRect = Rect(0, 0, bitmap.width, bitmap.height); var rect = Rect(left, top + offsetTop, gridItemSize + left, gridItemSize + top + offsetTop); canvas.drawBitmap(bitmap, pictureRect, rect, Paint()) } }

}

//交换内容 private fun PictureBlock.swap(target: PictureBlock) { target.postion = this.postion.also { this.postion = target.postion; } target.bitmap = this.bitmap.also { this.bitmap = target.bitmap; } }

fun Bitmap.getCenterBitmap(): Bitmap { //如果图片宽度大于View宽度 var min = min(this.height, this.width) if (min >= measuredWidth) { val matrix = Matrix() val sx: Float = measuredWidth / min.toFloat() matrix.setScale(sx, sx) return Bitmap.createBitmap( this, 0, (this.height * sx - measuredHeight / 2).toInt(), this.width, this.width, matrix, true ) } return this; }

fun setTarget(targetPicture: Bitmap) { this.targetPicture = targetPicture; }

private fun createSolidColorBitmap(size: Int): Bitmap { var bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) bitmap.eraseColor(Color.TRANSPARENT) return bitmap; }

private fun createBitmap(left: Int, top: Int, size: Int): Bitmap { return Bitmap.createBitmap(targetPicture, left, top, size, size) }

private fun List.isOrder(): Boolean { for (i in 1 until this.size) { if (this[i] - this[i - 1] != 1) { return false } } return true; }

private fun isFinish() { var list = mutableListOf(); for (i in pictureBlock2dMap.indices) { for (j in pictureBlock2dMap[i].indices) { var item = pictureBlock2dMap[i][j]!!; list.add(item.postion) } } if (list.isOrder()) { finish() } }

private fun finish() { Toast.makeText(context, “”, Toast.LENGTH_SHORT).show() }

private fun startAnimator( start: Int, end: Int, srcPoint: Point, dstPoint: Point, type: Boolean ) { val handler = object : AnimatorListener { override fun onAnimationRepeat(animation: Animator?) { }

override fun onAnimationEnd(animation: Animator?) { pictureBlock2dMap[dstPoint.x][dstPoint.y] = pictureBlock2dMap[srcPoint.x][srcPoint.y].also { pictureBlock2dMap[srcPoint.x][srcPoint.y] = pictureBlock2dMap[dstPoint.x][dstPoint.y]!!; } invalidate() isFinish()

}

override fun onAnimationCancel(animation: Animator?) { }

override fun onAnimationStart(animation: Animator?) { }

} var animatorSet = AnimatorSet() animatorSet.addListener(handler) animatorSet.playTogether(ValueAnimator.ofFloat(start.toFloat(), end.toFloat()).apply { duration = slideAnimatorDuration interpolator=itemMovInterpolator addUpdateListener { animation -> var value = animation.animatedValue as Float if (type) { pictureBlock2dMap[srcPoint.x][srcPoint.y]!!.left = value.toInt(); } else { pictureBlock2dMap[srcPoint.x][srcPoint.y]!!.top = value.toInt();

} invalidate() } }, ValueAnimator.ofFloat(end.toFloat(), start.toFloat()).apply { duration = slideAnimatorDuration interpolator=itemMovInterpolator addUpdateListener { animation -> var value = animation.animatedValue as Float if (type) { pictureBlock2dMap[dstPoint.x][dstPoint.y]!!.left = value.toInt(); } else { pictureBlock2dMap[dstPoint.x][dstPoint.y]!!.top = value.toInt();

} invalidate() } }); animatorSet.start()

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

码》]( )收录**

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

相关链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。