Custom Matrix effect class
View
class. Firstly, we define some variables for the Digital Rain Effect with the size of the code, the size of a column, the position of the bottom text for each column and then the characters that will be used for the code (I will use only alphabet chars). Note that you can put the characters you want here or why not a custom font:
public class MatrixEffect extends View {
private static Random random;
private int width, height;
private Canvas canvas;
private Bitmap canvasBmp;
private int fontSize = 40;
private int columnSize;
private char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWSYZabcdefghijklmnopqrstuvwyz".toCharArray();
private int[] txtPosByColumn;
private Paint paintTxt, paintBg, paintBgBmp, paintInitBg;
}
Now, in the constructor, we'll initialize all Paint
variables, which define that the text (running code) color is green, the background is black. You also need to create a new Random
object here (to random text codes later):
public MatrixEffect(Context context, AttributeSet attrs) {
super(context, attrs);
random = new Random();
paintTxt = new Paint();
paintTxt.setStyle(Paint.Style.FILL);
paintTxt.setColor(Color.GREEN);
paintTxt.setTextSize(fontSize);
paintBg = new Paint();
paintBg.setColor(Color.BLACK);
paintBg.setAlpha(5);
paintBg.setStyle(Paint.Style.FILL);
paintBgBmp = new Paint();
paintBgBmp.setColor(Color.BLACK);
paintInitBg = new Paint();
paintInitBg.setColor(Color.BLACK);
paintInitBg.setAlpha(255);
paintInitBg.setStyle(Paint.Style.FILL);
}
To get view width and height, we override the onSizeChanged()
method of the View
class. We initialize the position of the first character for each column. We use a random position between the top of the screen and the middle of the screen and save in the txtPosByColumn
array:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
canvasBmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
canvas = new Canvas(canvasBmp);
canvas.drawRect(0, 0, width, height, paintInitBg);
columnSize = width / fontSize;
txtPosByColumn = new int[columnSize + 1];
for (int x = 0; x < columnSize; x++) {
txtPosByColumn[x] = random.nextInt(height / 2) + 1;
}
}
Finally, we override the onDraw()
of our custom view, call the drawCanvas
method and invalidate the view to force a redraw. With that call, the Matrix Effect could progress from top to bottom in infinite mode. Inside drawCanvas()
, call drawText()
method used to draw a random character for each column at the position indicated by txtPosByColumn
variable above:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(canvasBmp, 0, 0, paintBgBmp);
drawCanvas();
invalidate();
}
private void drawText() {
for (int i = 0; i < txtPosByColumn.length; i++) {
canvas.drawText("" + chars[random.nextInt(chars.length)], i * fontSize, txtPosByColumn[i] * fontSize, paintTxt);
if (txtPosByColumn[i] * fontSize > height && Math.random() > 0.975) {
txtPosByColumn[i] = 0;
}
txtPosByColumn[i]++;
}
}
private void drawCanvas() {
canvas.drawRect(0, 0, width, height, paintBg);
drawText();
}
Usage in Activity/Fragment
MatrixEffectView
in your activity/fragment layout (XML) file:
activity_main.xml
And there is no special point in your activity programmatically code, just need <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="info.devexchanges.androidmatrixeffect.MainActivity">
<info.devexchanges.androidmatrixeffect.MatrixEffectView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
setContentView()
:
MainActivity.java
You may have this output when running this application:
package info.devexchanges.androidmatrixeffect;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
References: from original post in Ssaurel's blog.