数字雨

这篇文章介绍一个有趣的数字雨的view

先上效果图

GIF.gif

这个效果是在逛gitbug的时候发现,流动的数字雨颇有骇客的意味。
查看代码发现实现起来相当简单.

看着满屏的数字不断变化,实际上你只需要关注某一列的数字变化即可。而每一列的数字变化实现的原理就是每隔一个新的时间点,在原有的基础上多绘制一个数字。比如原来一列显示两个数字,下一个时间点显示三个数字,这样就能达到数字流动的视觉效果。

不多说了,直接上代码.

分两个步骤
1.将整个界面划分成多个列,用来承载数字

创建NumberRainView.java

public class NumberRainView extends LinearLayout {

private int normalColor = Color.GREEN;
private int highLightColor = Color.WHITE;
private Context context;
private float textSize;

public NumberRainView(Context context) {
    this(context, null);
}

public NumberRainView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
    textSize = 15 * context.getResources().getDisplayMetrics().density;
    if (attrs != null) {
        TypedArray typedArray = this.getContext().obtainStyledAttributes(attrs, R.styleable.NumberRainView);
        normalColor = typedArray.getColor(R.styleable.NumberRainView_normalColor, Color.GREEN);
        highLightColor = typedArray.getColor(R.styleable.NumberRainView_highLightColor, Color.WHITE);
        textSize = typedArray.getDimension(R.styleable.NumberRainView_textSize, textSize);
        typedArray.recycle();
    }

    setOrientation(LinearLayout.HORIZONTAL);
    setBackgroundColor(Color.BLACK);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    addRainItems();
}
//核心代码
private void addRainItems() {
    int count = (int) (getMeasuredWidth() / textSize);
    for (int i = 0; i < count; i++) {
        NumberRainItemView itemView = new NumberRainItemView(context);
        itemView.setNormalColor(normalColor);
        itemView.setHighLightColor(highLightColor);
        itemView.setTextSize(textSize);
        itemView.setStartDelay((long) (Math.random() * 1000));
        LayoutParams params = new LayoutParams((int) textSize + 10, getMeasuredHeight());
        addView(itemView, params);
    }
}

}

2.绘制每一列的随机数字,同时要注意有一个高亮的数字

创建 NumberRainItemView.java

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mPaint.setTextSize(textSize);
    mPaint.setColor(normalColor);
    if (isShowAllNumbers()) {
        drawAllNumbers(canvas);
    } else {
        drawPartNumbers(canvas);
    }
}

判断是显示部分数字还是所有数字,最开始的时候,只显示部分数字,随着时间,才会显示完整的数字

//判断条件
private boolean isShowAllNumbers() {
    return nowHeight >= getHeight();
}

//显示所有数字,根据view的高度来计算count
private void drawAllNumbers(Canvas canvas) {
    int count = (int) (getHeight() / textSize);
    drawSingleNumber(canvas, count);
}

//只显示部分数字,根据当前的变量值nowHeight计算count
private void drawPartNumbers(Canvas canvas) {
    int count = (int) (nowHeight / textSize);
    nowHeight += textSize;
    drawSingleNumber(canvas, count);
}

开始绘制数字

private void drawSingleNumber(Canvas canvas, int count) {
    if (count == 0) {
        //这段延迟为了达到各列数字雨不同步的效果
        postInvalidateDelayed(startDelay);
    } else {
        float numberOffset = 0f;
        for (int i = 0; i < count; i++) {
            String randomNumber = String.valueOf((int) (Math.random() * 2));
            //高亮的字符串
            mPaint.setColor(highLightIndex == i ? highLightColor : normalColor);
            //核心代码,绘制文字,且不停的变化绘制的位置
            canvas.drawText(randomNumber, 0, numberOffset, mPaint);
            numberOffset += textSize;
        }
        
        //计算下一次的高亮位置
        if (isShowAllNumbers()) {
            highLightIndex++;
            highLightIndex = highLightIndex % count;
        } else {
            highLightIndex++;
        }
        postInvalidateDelayed(100);
    }
}

完整代码

NumberRainItemView.java

public class NumberRainItemView extends View {

    private int normalColor = Color.GREEN;
    private int highLightColor = Color.RED;
    private float nowHeight;
    private float textSize;
    private long startDelay;
    private Paint mPaint;
    private int highLightIndex;

    public NumberRainItemView(Context context) {
        super(context);
        textSize = 15 * getResources().getDisplayMetrics().density;
        mPaint = new Paint();
    }

    public void setNormalColor(int normalColor) {
        this.normalColor = normalColor;
    }

    public void setHighLightColor(int highLightColor) {
        this.highLightColor = highLightColor;
    }

    public void setTextSize(float textSize) {
        this.textSize = textSize;
    }

    public void setStartDelay(long startDelay) {
        this.startDelay = startDelay;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setTextSize(textSize);
        mPaint.setColor(normalColor);
        if (isShowAllNumbers()) {
            drawAllNumbers(canvas);
        } else {
            drawPartNumbers(canvas);
        }
    }

    private void drawAllNumbers(Canvas canvas) {
        int count = (int) (getHeight() / textSize);
        drawSingleNumber(canvas, count);
    }

    private void drawPartNumbers(Canvas canvas) {
        int count = (int) (nowHeight / textSize);
        nowHeight += textSize;
        drawSingleNumber(canvas, count);
    }

    private void drawSingleNumber(Canvas canvas, int count) {
        if (count == 0) {
            postInvalidateDelayed(startDelay);
        } else {
            float numberOffset = 0f;
            for (int i = 0; i < count; i++) {
                String randomNumber = String.valueOf((int) (Math.random() * 2));
                mPaint.setColor(highLightIndex == i ? highLightColor : normalColor);
                canvas.drawText(randomNumber, 0, numberOffset, mPaint);
                numberOffset += textSize;
            }

            if (isShowAllNumbers()) {
                highLightIndex++;
                highLightIndex = highLightIndex % count;
            } else {
                highLightIndex++;
            }
            postInvalidateDelayed(100);
        }
    }

    private boolean isShowAllNumbers() {
        return nowHeight >= getHeight();
    }
}

attrs属性


    
    
    

相关链接

仿知乎关注按钮的波纹效果
仿知乎广告效果

最后给出一个原始地址 kotlin版

原始地址github

java版

本文对应的代码地址

你可能感兴趣的:(数字雨)