160行代码实现代码雨效果

效果

7c882188-540f-4e9a-b797-69e734eed561.gif

序言

很喜欢黑客帝国里面那种代码雨的效果,为了锻炼自己的特效编写能力就尝试了一下,花了一下午写出来了。有需要的小伙伴拿去参考.

代码

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;
    }
}

总结

一切纷繁复杂的效果,都要学会拆解。要用面向对象思想的来开发特效,把功能拆解到各种类中,以小胜换大胜。而驱动一切的就是时间。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值