上篇文章 Android子线程真的不能刷新UI吗?(一)复现异常 中可以看出子线程更新main线程创建的View,会抛出异常。SurfaceView不依赖main线程,可以直接使用自己的线程控制绘制逻辑。具体代码怎么实现了?
这篇文章用SurfaceView实现落花动画效果。
效果展示
录像帧率低,实际效果比下面的流畅。
SurfaceView控制原理
背景图片通过:android:background="@drawable/bg"
控制,Activity布局如下:
xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ShowFlowerActivity">
<com.exp.showwavedemo.FlowerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg" />
</LinearLayout>
小红花下落效果原理是:开启一个子线程,每80毫秒增加一朵小红花,并绘制一次。
完整代码
整个demo上传到gitee上了,要下载图片去gitee,地址:https://gitee.com/zhagnjinaaaa/show-flower-demo
FlowerView.java
java
package com.exp.showflowerdemo;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;
import java.util.Random;
public class FlowerView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder mHolder;
private boolean mFlag = true;//绘制小花线程的开关标志
private ArrayList<PointF> mFlowerList;//小花点的坐标集合
private Random mRandom;//负责随机数生成
private Bitmap mBitmap;//小花的图案
public FlowerView(Context context) {
super(context);
init();
}
public FlowerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FlowerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mHolder = getHolder();
mHolder.addCallback(this);
//设置背景透明
this.setZOrderOnTop(true);
mHolder.setFormat(PixelFormat.TRANSLUCENT);
mFlowerList = new ArrayList<>();
mRandom = new Random();
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_small_hua_15);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mFlag = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mFlowerList.clear();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mFlag = false;
}
@Override
public void run() {
while (mFlag) {
try {
Thread.sleep(80);
Canvas canvas = mHolder.lockCanvas();
PointF pointF = null;
//清屏操作
if (canvas != null) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
} else {
continue;
}
for (PointF point : mFlowerList) {
pointF = point;
canvas.drawBitmap(mBitmap, pointF.x, pointF.y, null);
int i = mRandom.nextInt(getHeight() / 50) + getHeight() / 50;//修改雨滴线的纵坐标,使其看起来在下雨
pointF.y = pointF.y + i;
}
mHolder.unlockCanvasAndPost(canvas);
addFlower();
if (mFlowerList.size() > 0 && pointF != null && pointF.y >= getHeight()) {
mFlowerList.remove(pointF);
}
} catch (Exception e) {
}
}
}
/**
* 添加花朵
*/
private void addFlower() {
PointF point = new PointF();
point.x = mRandom.nextInt(getWidth());
point.y = -mBitmap.getHeight();
mFlowerList.add(point);
}
}