用SurfaceView实现落花动画效果

上篇文章 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);
    }
}
相关推荐
coderlin_7 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
2501_915918417 小时前
Fiddler中文版全面评测:功能亮点、使用场景与中文网资源整合指南
android·ios·小程序·https·uni-app·iphone·webview
wen's9 小时前
React Native安卓刘海屏适配终极方案:仅需修改 AndroidManifest.xml!
android·xml·react native
编程乐学10 小时前
网络资源模板--基于Android Studio 实现的聊天App
android·android studio·大作业·移动端开发·安卓移动开发·聊天app
没有了遇见12 小时前
Android 通过 SO 库安全存储敏感数据,解决接口劫持问题
android
hsx66612 小时前
使用一个 RecyclerView 构建复杂多类型布局
android
hsx66612 小时前
利用 onMeasure、onLayout、onDraw 创建自定义 View
android
守城小轩12 小时前
Chromium 136 编译指南 - Android 篇:开发工具安装(三)
android·数据库·redis
whysqwhw13 小时前
OkHttp平台抽象机制分析
android
hsx66613 小时前
Android 内存泄漏避坑
android