上篇文章 Android子线程真的不能刷新UI吗?(一)复现异常 中可以看出子线程更新main线程创建的View,会抛出异常。SurfaceView不依赖main线程,可以直接使用自己的线程控制绘制逻辑。具体代码怎么实现了?
这篇文章用SurfaceView实现落花动画效果。
效果展示
录像帧率低,实际效果比下面的流畅。
SurfaceView控制原理
背景图片通过:android:background="@drawable/bg"
控制,Activity布局如下:
<?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.FlowerViewandroid: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
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);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mFlag = true;new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {mFlowerList.clear();}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mFlag = false;}@Overridepublic 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);}
}