【1024个人爆款文章】Android 安卓原生UI实现游戏《俄罗斯方块》,算法太多

最后

都说三年是程序员的一个坎,能否晋升或者提高自己的核心竞争力,这几年就十分关键。

技术发展的这么快,从哪些方面开始学习,才能达到高级工程师水平,最后进阶到Android架构师/技术专家?我总结了这 5大块;

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

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

2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

gameMap[boxMinX + 1][boxMinY + 1] = 13

gameMap[boxMinX + 2][boxMinY] = 13

rotate = 2

}

}

2 -> {

if (

boxMinX + 1 < 20

&& boxMinY + 2 < 10

&& gameMap[boxMinX][boxMinY] !in 1…7

&& gameMap[boxMinX][boxMinY + 1] !in 1…7

&& gameMap[boxMinX + 1][boxMinY + 1] !in 1…7

&& gameMap[boxMinX + 1][boxMinY + 2] !in 1…7

) {

reset()

gameMap[boxMinX][boxMinY] = 13

gameMap[boxMinX][boxMinY + 1] = 13

gameMap[boxMinX + 1][boxMinY + 1] = 13

gameMap[boxMinX + 1][boxMinY + 2] = 13

rotate = 1

}

}

}

}

14 -> {

when (rotate) {

1 -> {

if (boxMinX + 2 < 20

&& boxMinY + 1 < 10

&& gameMap[boxMinX][boxMinY] !in 1…7

&& gameMap[boxMinX + 1][boxMinY] !in 1…7

&& gameMap[boxMinX + 1][boxMinY + 1] !in 1…7

&& gameMap[boxMinX + 2][boxMinY + 1] !in 1…7

) {

reset()

gameMap[boxMinX][boxMinY] = 14

gameMap[boxMinX + 1][boxMinY] = 14

gameMap[boxMinX + 1][boxMinY + 1] = 14

gameMap[boxMinX + 2][boxMinY + 1] = 14

rotate = 2

}

}

2 -> {

if (boxMinX + 2 < 20

&& boxMinY + 1 < 10

&& gameMap[boxMinX][boxMinY + 1] !in 1…7

&& gameMap[boxMinX][boxMinY + 2] !in 1…7

&& gameMap[boxMinX + 1][boxMinY] !in 1…7

&& gameMap[boxMinX + 1][boxMinY + 1] !in 1…7

) {

reset()

gameMap[boxMinX][boxMinY + 1] = 14

gameMap[boxMinX][boxMinY + 2] = 14

gameMap[boxMinX + 1][boxMinY] = 14

gameMap[boxMinX + 1][boxMinY + 1] = 14

rotate = 1

}

}

}

}

15 -> {

when (rotate) {

1 -> {

if (boxMinX + 2 < 20

&& boxMinY + 1 < 10

&& gameMap[boxMinX][boxMinY + 1] !in 1…7

&& gameMap[boxMinX + 1][boxMinY + 1] !in 1…7

&& gameMap[boxMinX + 2][boxMinY] !in 1…7

&& gameMap[boxMinX + 2][boxMinY + 1] !in 1…7

) {

reset()

gameMap[boxMinX][boxMinY + 1] = 15

gameMap[boxMinX + 1][boxMinY + 1] = 15

gameMap[boxMinX + 2][boxMinY] = 15

gameMap[boxMinX + 2][boxMinY + 1] = 15

rotate = 2

}

}

2 -> {

if (boxMinX + 1 < 20

&& boxMinY + 2 < 10

&& gameMap[boxMinX][boxMinY] !in 1…7

&& gameMap[boxMinX][boxMinY + 1] !in 1…7

&& gameMap[boxMinX][boxMinY + 2] !in 1…7

&& gameMap[boxMinX + 1][boxMinY + 2] !in 1…7

) {

reset()

gameMap[boxMinX][boxMinY] = 15

gameMap[boxMinX][boxMinY + 1] = 15

gameMap[boxMinX][boxMinY + 2] = 15

gameMap[boxMinX + 1][boxMinY + 2] = 15

rotate = 3

}

}

3 -> {

if (boxMinX + 1 < 20

&& boxMinY + 2 < 10

&& gameMap[boxMinX][boxMinY] !in 1…7

&& gameMap[boxMinX][boxMinY + 1] !in 1…7

&& gameMap[boxMinX + 1][boxMinY] !in 1…7

&& gameMap[boxMinX + 2][boxMinY] !in 1…7

) {

reset()

gameMap[boxMinX][boxMinY] = 15

gameMap[boxMinX][boxMinY + 1] = 15

gameMap[boxMinX + 1][boxMinY] = 15

gameMap[boxMinX + 2][boxMinY] = 15

rotate = 4

}

}

4 -> {

if (boxMinX + 1 < 20

&& boxMinY + 2 < 10

&& gameMap[boxMinX][boxMinY] !in 1…7

&& gameMap[boxMinX + 1][boxMinY] !in 1…7

&& gameMap[boxMinX + 1][boxMinY + 1] !in 1…7

&& gameMap[boxMinX + 1][boxMinY + 2] !in 1…7

) {

reset()

gameMap[boxMinX][boxMinY] = 15

gameMap[boxMinX + 1][boxMinY] = 15

gameMap[boxMinX + 1][boxMinY + 1] = 15

gameMap[boxMinX + 1][boxMinY + 2] = 15

rotate = 1

}

}

}

}

16 -> {

when (rotate) {

1 -> {

val midpoint = boxArr[2]

if (midpoint.x - 1 >= 0

&& midpoint.x + 1 < 20

&& midpoint.y - 1 >= 0

) {

reset()

gameMap[midpoint.x - 1][midpoint.y] = 16

gameMap[midpoint.x][midpoint.y] = 16

gameMap[midpoint.x][midpoint.y - 1] = 16

gameMap[midpoint.x + 1][midpoint.y] = 16

rotate = 2

}

}

2 -> {

val midpoint = boxArr[2]

if (midpoint.x - 1 >= 0

&& midpoint.x + 1 < 20

&& midpoint.y - 1 >= 0

&& midpoint.y + 1 < 10

) {

reset()

gameMap[midpoint.x][midpoint.y - 1] = 16

gameMap[midpoint.x][midpoint.y] = 16

gameMap[midpoint.x][midpoint.y + 1] = 16

gameMap[midpoint.x + 1][midpoint.y] = 16

rotate = 3

}

}

3 -> {

val midpoint = boxArr[1]

reset()

gameMap[midpoint.x - 1][midpoint.y] = 16

gameMap[midpoint.x][midpoint.y] = 16

gameMap[midpoint.x][midpoint.y + 1] = 16

gameMap[midpoint.x + 1][midpoint.y] = 16

rotate = 4

}

4 -> {

val midpoint = boxArr[1]

if (midpoint.y - 1 >= 0) {

reset()

gameMap[midpoint.x - 1][midpoint.y] = 16

gameMap[midpoint.x][midpoint.y - 1] = 16

gameMap[midpoint.x][midpoint.y] = 16

gameMap[midpoint.x][midpoint.y + 1] = 16

rotate = 1

}

}

}

}

17 -> {

val midpoint = boxArr[1]

when (rotate) {

1 -> {

if (midpoint.x - 1 >= 0 && midpoint.x + 2 < 20) {

reset()

gameMap[midpoint.x - 1][midpoint.y] = 17

gameMap[midpoint.x][midpoint.y] = 17

gameMap[midpoint.x + 1][midpoint.y] = 17

gameMap[midpoint.x + 2][midpoint.y] = 17

rotate = 2

}

}

2 -> {

if (midpoint.y - 1 >= 0 && midpoint.y + 2 < 10) {

reset()

gameMap[midpoint.x][midpoint.y - 1] = 17

gameMap[midpoint.x][midpoint.y] = 17

gameMap[midpoint.x][midpoint.y + 1] = 17

gameMap[midpoint.x][midpoint.y + 2] = 17

rotate = 1

}

}

}

}

}

changeListener?.onChange()

}

}

/**

  • 向左移动正在下落的方块

*/

fun toLeft() {

val leftArr = mutableListOf()

for (i in gameMap.indices) for (j in gameMap[i].indices) if (gameMap[i][j] in 11…17)

leftArr.add(Coordinate(i, j, gameMap[i][j]))

if (0 == leftArr.size) return

//是否允许向左移动

var toLeftStatus = true

//向左移动条件:符合移动方块并且任何左侧为空方块

for (coordinate in leftArr) {

if (coordinate.y == 0 || (coordinate.y > 0 && gameMap[coordinate.x][coordinate.y - 1] in 1…7)) {

toLeftStatus = false

break

}

}

//向左移动

if (toLeftStatus) {

for (i in 0 until leftArr.size) {

gameMap[leftArr[i].x][leftArr[i].y - 1] = leftArr[0].value

gameMap[leftArr[i].x][leftArr[i].y] = 0

}

changeListener?.onChange()

}

}

/**

  • 向右移动正在下落的方块

*/

fun toRight() {

val rightArr = mutableListOf()

for (i in gameMap.indices) for (j in gameMap[i].indices) if (gameMap[i][j] in 11…17)

rightArr.add(Coordinate(i, j, gameMap[i][j]))

if (0 == rightArr.size) return

//是否允许向右移动

var toRightStatus = true

//向右移动条件:符合移动方块并且任何右侧为空方块

for (coordinate in rightArr) if (coordinate.y == 9 || (coordinate.y < 10 && gameMap[coordinate.x][coordinate.y + 1] in 1…7)) {

toRightStatus = false

break

}

//向右移动

if (toRightStatus) {

for (i in rightArr.size - 1 downTo 0) {

gameMap[rightArr[i].x][rightArr[i].y + 1] = rightArr[0].value

gameMap[rightArr[i].x][rightArr[i].y] = 0

}

changeListener?.onChange()

}

}

/**

  • 直接下落到底部

*/

fun downBottom() {

val downArr = mutableListOf()

for (i in gameMap.size - 1 downTo 0) for (j in gameMap[i].size - 1 downTo 0) {

val coordinate = gameMap[i][j]

if (coordinate in 11…17) downArr.add(Coordinate(i, j, coordinate))

}

if (0 != downArr.size) {

var isFixed = false

val valueTemp = downArr[0].value

for (coordinate in downArr) if (coordinate.x + 1 >= 20 || gameMap[coordinate.x + 1][coordinate.y] in 1…7) return

for (coordinate in downArr) {

gameMap[coordinate.x][coordinate.y] = 0

gameMap[coordinate.x + 1][coordinate.y] = valueTemp

//判断是否落到了最后

if (coordinate.x + 1 >= 19 || gameMap[coordinate.x + 2][coordinate.y] in 1…7)

isFixed = true

}

if (!isFixed) downBottom() else changeListener?.onChange()

} else changeListener?.onChange()

}

/**

  • 在顶部创建一个新的模块

*/

private fun createTopBox() {

//判断是否有预测,没有预测则生成方块

if (0 == forecastType) forecastType = (1…7).random()

//重置旋转度数

rotate = 1

//每生成5个方块增加一次方块下落速度

if (++boxNum % 5 == 0 && speed > 150) speed -= 20

//游戏是否结束

var gameOverStatus = false

//生成下落方块

when (forecastType) {

1 -> if (gameMap[0][4] !in 1…7

&& gameMap[0][5] !in 1…7

&& gameMap[1][4] !in 1…7

&& gameMap[1][5] !in 1…7

) {

gameMap[0][4] = 11

gameMap[0][5] = 11

gameMap[1][4] = 11

gameMap[1][5] = 11

} else gameOverStatus = true

2 -> if (gameMap[0][5] !in 1…7

&& gameMap[1][3] !in 1…7

&& gameMap[1][4] !in 1…7

&& gameMap[1][5] !in 1…7

) {

gameMap[0][5] = 12

gameMap[1][3] = 12

gameMap[1][4] = 12

gameMap[1][5] = 12

} else gameOverStatus = true

3 -> if (gameMap[0][3] !in 1…7

&& gameMap[0][4] !in 1…7

&& gameMap[1][4] !in 1…7

&& gameMap[1][5] !in 1…7

) {

gameMap[0][3] = 13

gameMap[0][4] = 13

gameMap[1][4] = 13

gameMap[1][5] = 13

} else gameOverStatus = true

4 -> if (gameMap[0][4] !in 1…7

&& gameMap[0][5] !in 1…7

&& gameMap[1][3] !in 1…7

&& gameMap[1][4] !in 1…7

) {

gameMap[0][4] = 14

gameMap[0][5] = 14

gameMap[1][3] = 14

gameMap[1][4] = 14

} else gameOverStatus = true

5 -> if (gameMap[0][3] !in 1…7

&& gameMap[1][3] !in 1…7

&& gameMap[1][4] !in 1…7

&& gameMap[1][5] !in 1…7

) {

gameMap[0][3] = 15

gameMap[1][3] = 15

gameMap[1][4] = 15

gameMap[1][5] = 15

} else gameOverStatus = true

6 -> if (gameMap[0][4] !in 1…7

&& gameMap[1][3] !in 1…7

&& gameMap[1][4] !in 1…7

&& gameMap[1][5] !in 1…7

) {

gameMap[0][4] = 16

gameMap[1][3] = 16

gameMap[1][4] = 16

gameMap[1][5] = 16

} else gameOverStatus = true

7 -> if (gameMap[0][3] !in 1…7

&& gameMap[0][4] !in 1…7

&& gameMap[0][5] !in 1…7

&& gameMap[0][6] !in 1…7

) {

gameMap[0][3] = 17

gameMap[0][4] = 17

gameMap[0][5] = 17

gameMap[0][6] = 17

} else gameOverStatus = true

}

//生成预测方块

forecastType = (1…7).random()

if (gameOverStatus) {

//回调游戏结束

changeListener?.gameOver(score)

//重置游戏数据

speed = 750L

isInGame = false

rotate = 1

score = 0L

forecastType = 0

boxNum = 0

for (i in gameMap.indices) for (j in gameMap[i].indices) gameMap[i][j] = 0

}

}

/**

  • 固定移动中的方块方块

*/

private fun fixedMoveBox() {

for (i in gameMap.indices) for (j in gameMap[i].indices) if (gameMap[i][j] in 11…17)

gameMap[i][j] = gameMap[i][j] - 10

}

/**

  • 方块下落

*/

private fun downBox(): Boolean {

//扫描需要下落的方块

val downArr = mutableListOf()

for (i in gameMap.size - 1 downTo 0) for (j in gameMap[i].size - 1 downTo 0) if (gameMap[i][j] in 11…17)

downArr.add(Coordinate(i, j, gameMap[i][j]))

//判断是否无法继续下移

if (downArr.size == 0) return false

//判断是否还能继续下移

//判断条件:任何一个正在移动的方块是否达到了第20行或者触碰到了固定方块

for (i in 0 until downArr.size) if (downArr[i].x + 1 > 19 || gameMap[downArr[i].x + 1][downArr[i].y] in 1…7) return false

val coordinateTempValue = downArr[0]

for (j in 0 until downArr.size) {

val coordinateTemp = downArr[j]

gameMap[coordinateTemp.x][coordinateTemp.y] = 0

gameMap[coordinateTemp.x + 1][coordinateTemp.y] = coordinateTempValue.value

}

return true

}

//游戏实时变化回调

var changeListener: ChangeListener? = null

/**

  • 游戏实时变化回调

*/

interface ChangeListener {

fun onChange()

fun gameOver(score: Long)

}

/**

  • 坐标实体类

*/

data class Coordinate(

var x: Int,

var y: Int,

var value: Int

)

}


可视化View

数据逻辑写完了,要让用户看的见呀,通过自定义View来实现,详细看以下注释

package com.blog.tetris.view

import android.content.Context

import android.graphics.*

import android.util.AttributeSet

import android.util.Log

import android.view.View

import com.blog.tetris.operation.Operation

class GameView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {

//方块大小

val boxSize = 70F

//方块边框大小

private val edge = boxSize / 4F

//地图绘制

private var mapPaint: Paint = Paint()

//方块绘制

private var boxPaint: Paint = Paint()

//预测方块绘制

private var forecastPaint: Paint = Paint()

//分数绘制

private var scorePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

private var leftMargin = 0

private var topMargin = 5 * boxSize

//方块颜色

private var color10 = Color.parseColor(“#0302FF”)

private var color11 = Color.parseColor(“#3437F9”)

private var color12 = Color.parseColor(“#6568FC”)

private var color13 = Color.parseColor(“#00089C”)

private var color14 = Color.parseColor(“#00027B”)

private var color20 = Color.parseColor(“#FEFF04”)

private var color21 = Color.parseColor(“#FDFE3E”)

private var color22 = Color.parseColor(“#FCFD65”)

private var color23 = Color.parseColor(“#ACA706”)

private var color24 = Color.parseColor(“#717804”)

private var color30 = Color.parseColor(“#FB0101”)

private var color31 = Color.parseColor(“#F33A36”)

private var color32 = Color.parseColor(“#F66A64”)

private var color33 = Color.parseColor(“#A80400”)

private var color34 = Color.parseColor(“#7E0003”)

private var color40 = Color.parseColor(“#06FD06”)

private var color41 = Color.parseColor(“#37F936”)

private var color42 = Color.parseColor(“#68FD67”)

private var color43 = Color.parseColor(“#0AA109”)

private var color44 = Color.parseColor(“#037407”)

private var color50 = Color.parseColor(“#FF7F04”)

private var color51 = Color.parseColor(“#F89A38”)

private var color52 = Color.parseColor(“#F8B56A”)

private var color53 = Color.parseColor(“#A75304”)

private var color54 = Color.parseColor(“#723709”)

private var color60 = Color.parseColor(“#F505F8”)

private var color61 = Color.parseColor(“#FB36FB”)

private var color62 = Color.parseColor(“#FF66F9”)

private var color63 = Color.parseColor(“#A801A7”)

private var color64 = Color.parseColor(“#780378”)

private var color70 = Color.parseColor(“#01FFFD”)

private var color71 = Color.parseColor(“#37FDFE”)

private var color72 = Color.parseColor(“#69FAF9”)

private var color73 = Color.parseColor(“#08A5AA”)

private var color74 = Color.parseColor(“#01746F”)

init {

scorePaint.color = Color.parseColor(“#FFFFFF”)

mapPaint.color = Color.parseColor(“#000000”)

scorePaint.textSize = boxSize / 1.8F

boxPaint.isAntiAlias = true

forecastPaint.isAntiAlias = true

}

override fun onDraw(canvas: Canvas?) {

canvas?.let {

//算出地图边界距离屏幕左侧距离(游戏地图放置在View中间)

leftMargin = width / 2 - boxSize.toInt() * 5

//绘制地图

drawMap(it)

//绘制方块

drawBoxByArr(it)

//绘制分数

drawScore(it)

//绘制预测

drawForecast(it)

}

}

/**

  • 绘制分数

*/

private fun drawScore(canvas: Canvas) {

//绘制标题

canvas.drawText(

“得分”,

leftMargin.toFloat() + boxSize / 2,

scorePaint.textSize + boxSize / 2,

scorePaint

)

//绘制得分

canvas.drawText(

Operation.score.toString(),

leftMargin.toFloat() + boxSize / 2,

scorePaint.textSize + boxSize / 2 + boxSize,

scorePaint

)

}

/**

  • 绘制预测

*/

private fun drawForecast(canvas: Canvas) {

//绘制标题

canvas.drawText(

“下一个”,

width / 2F,

scorePaint.textSize + boxSize / 2,

scorePaint

)

//绘制方块

val forecastMap = Array(2) { Array(4) { 0 } }

when (Operation.forecastType) {

1 -> {

forecastMap[0][0] = 1

forecastMap[0][1] = 1

forecastMap[1][0] = 1

forecastMap[1][1] = 1

}

2 -> {

forecastMap[0][2] = 2

forecastMap[1][0] = 2

forecastMap[1][1] = 2

forecastMap[1][2] = 2

}

3 -> {

forecastMap[0][0] = 3

forecastMap[0][1] = 3

forecastMap[1][1] = 3

forecastMap[1][2] = 3

}

4 -> {

forecastMap[0][1] = 4

forecastMap[0][2] = 4

forecastMap[1][0] = 4

forecastMap[1][1] = 4

}

5 -> {

forecastMap[0][0] = 5

forecastMap[1][0] = 5

forecastMap[1][1] = 5

forecastMap[1][2] = 5

}

6 -> {

forecastMap[0][1] = 6

forecastMap[1][0] = 6

forecastMap[1][1] = 6

forecastMap[1][2] = 6

}

7 -> {

forecastMap[0][0] = 7

forecastMap[0][1] = 7

forecastMap[0][2] = 7

forecastMap[0][3] = 7

}

}

//绘制预测方块

val boxColor = getBoxColor(Operation.forecastType)

for (i in forecastMap.indices) {

for (j in forecastMap[i].indices) {

if (forecastMap[i][j] > 0) {

val left = width / 2F + boxSize * j

val top = i * boxSize + boxSize * 1.5F

val right = width / 2F + boxSize * j + boxSize

val bottom = (i + 1) * boxSize + boxSize * 1.5F

//绘制方块

forecastPaint.color = boxColor[0]

canvas.drawRect(left, top, right, bottom, forecastPaint)

//绘制单个模块四周梯形

val path1 = Path()

path1.moveTo(left, bottom)

path1.lineTo(left, bottom - boxSize)

path1.lineTo(left + edge, bottom - boxSize + edge)

path1.lineTo(left + edge, bottom - edge)

path1.close()

val path2 = Path()

path2.moveTo(left + edge, top + edge)

path2.lineTo(left, top)

path2.lineTo(right, top)

path2.lineTo(right - edge, top + edge)

path2.close()

val path3 = Path()

path3.moveTo(right - edge, bottom - edge)

path3.lineTo(right - edge, top + edge)

path3.lineTo(right, top)

path3.lineTo(right, bottom)

path3.close()

val path4 = Path()

path4.moveTo(left, bottom)

path4.lineTo(left + edge, bottom - edge)

path4.lineTo(right - edge, bottom - edge)

path4.lineTo(right, bottom)

path4.close()

boxPaint.color = boxColor[1]

canvas.drawPath(path1, boxPaint)

boxPaint.color = boxColor[2]

canvas.drawPath(path2, boxPaint)

boxPaint.color = boxColor[3]

canvas.drawPath(path3, boxPaint)

boxPaint.color = boxColor[4]

canvas.drawPath(path4, boxPaint)

}

}

}

}

/**

  • 绘制地图

*/

private fun drawMap(canvas: Canvas) {

//绘制地图

for (i in 0 until 20) for (j in 0 until 10) canvas.drawRect(

j * boxSize + leftMargin,

i * boxSize + topMargin,

(j + 1) * boxSize + leftMargin,

(i + 1) * boxSize + topMargin,

mapPaint

)

//绘制顶部状态图

for (i in 0 until 4) for (j in 0 until 10) canvas.drawRect(

j * boxSize + leftMargin,

i * boxSize,

(j + 1) * boxSize + leftMargin,

(i + 1) * boxSize,

mapPaint

)

}

/**

  • 根据数组绘制图形

*/

private fun drawBoxByArr(canvas: Canvas) {

val mapArr = Operation.gameMap

for (i in mapArr.indices) {

for (j in mapArr[i].indices) {

if (mapArr[i][j] > 0) {

boxPaint.color = getBoxColor(mapArr[i][j])[0]

val left = j * boxSize + leftMargin

val top = i * boxSize + topMargin

val right = (j + 1) * boxSize + leftMargin

val bottom = (i + 1) * boxSize + topMargin

canvas.drawRect(left, top, right, bottom, boxPaint)

//绘制单个模块四周梯形

val path1 = Path()

path1.moveTo(left, top)

path1.lineTo(left + edge, i * boxSize + edge + topMargin)

最后

总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。

在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ze + leftMargin,

i * boxSize + topMargin,

(j + 1) * boxSize + leftMargin,

(i + 1) * boxSize + topMargin,

mapPaint

)

//绘制顶部状态图

for (i in 0 until 4) for (j in 0 until 10) canvas.drawRect(

j * boxSize + leftMargin,

i * boxSize,

(j + 1) * boxSize + leftMargin,

(i + 1) * boxSize,

mapPaint

)

}

/**

  • 根据数组绘制图形

*/

private fun drawBoxByArr(canvas: Canvas) {

val mapArr = Operation.gameMap

for (i in mapArr.indices) {

for (j in mapArr[i].indices) {

if (mapArr[i][j] > 0) {

boxPaint.color = getBoxColor(mapArr[i][j])[0]

val left = j * boxSize + leftMargin

val top = i * boxSize + topMargin

val right = (j + 1) * boxSize + leftMargin

val bottom = (i + 1) * boxSize + topMargin

canvas.drawRect(left, top, right, bottom, boxPaint)

//绘制单个模块四周梯形

val path1 = Path()

path1.moveTo(left, top)

path1.lineTo(left + edge, i * boxSize + edge + topMargin)

最后

总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。

在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

[外链图片转存中…(img-2RzLaKkb-1715271943557)]

[外链图片转存中…(img-QfWxGowU-1715271943557)]

[外链图片转存中…(img-Ul7lKHqj-1715271943558)]

还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 28
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值