效果
序言
很喜欢黑客帝国里面那种代码雨的效果,为了锻炼自己的特效编写能力就尝试了一下,花了一下午写出来了。有需要的小伙伴拿去参考.
代码
package com.zgh.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* <pre>
* Created by zhuguohui
* Date: 2024/7/4
* Time: 16:38
* Desc:代码雨
* </pre>
*/
public class CodeRainView extends View {
private Paint paint;
private float fontSize = 30;
private Random random;
private Handler handler = new Handler();
public CodeRainView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
fontSize = 15 * getResources().getDisplayMetrics().density + 0.5f;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(fontSize);
random = new Random();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int colum = (int) (getWidth() / fontSize);
codeList.clear();
for (int i = 0; i < colum; i++) {
float offset = -random.nextInt(getHeight() / 2);
Code code = new Code(offset, h, i * fontSize, fontSize);
codeList.add(code);
}
startAnimation();
}
private Runnable updateRunnable = new Runnable() {
@Override
public void run() {
invalidate();
handler.postDelayed(updateRunnable, 16);
}
};
private void startAnimation() {
//要保证60fps 需要16毫秒执行一次
handler.removeCallbacks(updateRunnable);
handler.post(updateRunnable);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
for (Code code : codeList) {
code.draw(canvas, paint);
}
}
List<Code> codeList = new ArrayList<>();
private class Code {
private final int[] colors;
long startTime;
long duration;
float offset;
float moveY;
float x;
private String[] toShowStrArray;
public Code(float offset, int height, float x, float fontSize) {
startTime = System.currentTimeMillis();
this.duration = getRandomDuration();
this.offset = offset;
this.moveY = (height + str.length() * fontSize) - offset;
colors = new int[str.length()];
getRandomContent();
getRandomColors();
this.x = x;
}
private void getRandomColors() {
for (int i = 0; i < str.length(); i++) {
//255-0;
int alpha = (int) (255 - ((i * 1.0) / (str.length() - 1)) * 255);
colors[i] = getRandomColor(alpha);
}
}
float lastRatio;
void draw(Canvas canvas, Paint paint) {
final long now = System.currentTimeMillis();//当前时间
final float ratio = ((now - startTime) % duration) * 1.0f / duration; //计算动画比例
for (int i = 0; i < str.length(); i++) {
String toShowStr = toShowStrArray[i];
float y = ratio * moveY + offset - (i * fontSize);
paint.setColor(colors[i]);
canvas.drawText(toShowStr, x, y, paint);
}
if (ratio - lastRatio > 0.1) {
getRandomContent();
lastRatio = ratio;
}
if (ratio >= 0.99) {
//重新随机一个速度
startTime = System.currentTimeMillis();
getRandomColors();
duration = getRandomDuration();
getRandomContent();
lastRatio = 0;
}
}
private int getRandomColor(int alpha) {
return Color.argb(alpha, random.nextInt(255), random.nextInt(255), random.nextInt(255));
}
private final String str = "0123456789abcdefghijklmnopqrstuvwxyz";
private String getRandomText() {
return str.charAt(random.nextInt(str.length())) + "";
}
private void getRandomContent() {
toShowStrArray = new String[str.length()];
for (int i = 0; i < str.length(); i++) {
toShowStrArray[i] = getRandomText();
}
}
}
private int getRandomDuration() {
return random.nextInt(3000) + 3000;
}
}
总结
一切纷繁复杂的效果,都要学会拆解。要用面向对象思想的来开发特效,把功能拆解到各种类中,以小胜换大胜。而驱动一切的就是时间。