kotlin 仿黑客帝国代码雨
我们看代码之前先看一下效果这个是我做的一个效果,可能没有100%还原,但是也有80%的相似度,主要是看一下实现的逻辑
如果不懂kotlin的,建议用gpt去翻译成你所熟悉的语言,我想大多数程序员都还是想自己去搞一些比较炫酷的操作的,接下来大家就看一下代码
package com.ghn.cocknovel
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import kotlin.random.Random
/**
* @author 浩楠
*
* @date 2024/6/1-16:43.
*
* _ _ _ _ ____ _ _ _
* / \ _ __ __| |_ __ ___ (_) __| | / ___|| |_ _ _ __| (_) ___
* / _ \ | '_ \ / _` | '__/ _ \| |/ _` | \___ \| __| | | |/ _` | |/ _ \
* / ___ \| | | | (_| | | | (_) | | (_| | ___) | |_| |_| | (_| | | (_) |
* /_/ \_\_| |_|\__,_|_| \___/|_|\__,_| |____/ \__|\__,_|\__,_|_|\___/
* @Description: TODO 实现矩阵雨效果
*/
class MatrixEffectView(context: Context, attrs: AttributeSet) : View(context, attrs) {
// 画笔对象,用于绘制字符
private val paint = Paint().apply {
textSize = FONT_SIZE.toFloat()
isAntiAlias = true
}
// 背景画笔对象,用于绘制背景
private val bgPaint = Paint().apply {
color = Color.argb(150, 0, 0, 0)
}
// 列数
private var columns: Int = 0
// 存储每列字符下落的位置
private lateinit var drops: FloatArray
// 字符矩阵
private lateinit var matrix: Array<CharArray>
// 可见性矩阵
private lateinit var visibilities: Array<FloatArray>
init {
// 设置背景颜色为黑色
setBackgroundColor(Color.BLACK)
}
// 当视图大小改变时调用此方法
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
// 计算列数
columns = w / (FONT_SIZE + COLUMN_SPACING)
// 初始化各数组
drops = FloatArray(columns) { -Random.nextFloat() * h / FONT_SIZE }
matrix = Array(columns) { CharArray(h / FONT_SIZE) { getRandomChar() } }
visibilities = Array(columns) { FloatArray(h / FONT_SIZE) { 0f } }
}
// 绘制方法
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 绘制背景
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), bgPaint)
// 遍历每列
drops.forEachIndexed { i, drop ->
val x = i * (FONT_SIZE + COLUMN_SPACING)
// 遍历每列中的每个字符
matrix[i].forEachIndexed { j, char ->
val y = (j + drop) * FONT_SIZE
// 绘制字符
if (y >= 0 && y < height) {
paint.color = getGradientColor(j, matrix[i].size, visibilities[i][j])
canvas.drawText(char.toString(), x.toFloat(), y.toFloat(), paint)
}
// 增加字符的可见性,使其逐渐显示出来
if (visibilities[i][j] < 1f && y >= 0 && y < height) {
visibilities[i][j] += 0.05f
}
}
// 更新下落位置
drops[i] += DROP_SPEED
// 如果字符下落超出屏幕,重置位置和字符
if (drops[i] * FONT_SIZE > height) {
resetColumn(i, height)
}
}
// 延迟刷新
postInvalidateDelayed(50)
}
// 获取随机字符
private fun getRandomChar() = MESSAGE.random()
// 获取渐变颜色
private fun getGradientColor(position: Int, length: Int, visibility: Float): Int {
val factor = position.toFloat() / length
val greenValue = (150 + (255 - 150) * factor).toInt()
val alphaValue = (255 * visibility).toInt()
return Color.argb(alphaValue, 0, greenValue, 0)
}
// 重置列数据
private fun resetColumn(i: Int, height: Int) {
drops[i] = -Random.nextInt(height / FONT_SIZE).toFloat()
matrix[i] = CharArray(height / FONT_SIZE) { getRandomChar() }
visibilities[i] = FloatArray(height / FONT_SIZE) { 0f }
}
// 常量定义
companion object {
private const val FONT_SIZE = 26 // 字体大小
private const val COLUMN_SPACING = 10 // 列间距
private const val DROP_SPEED = 0.5f // 下落速度
private const val MESSAGE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // 字符集
}
}