用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);
    }
}
相关推荐
2501_9159090621 小时前
原生与 H5 共存情况下的测试思路,混合开发 App 的实际测试场景
android·ios·小程序·https·uni-app·iphone·webview
鸣弦artha21 小时前
Flutter框架跨平台鸿蒙开发——Extension扩展方法
android·javascript·flutter
小陈phd1 天前
langGraph从入门到精通(六)——基于 LangGraph 实现结构化输出与智能 Router 路由代理
android·网络·数据库
游戏开发爱好者81 天前
了解 Xcode 在 iOS 开发中的作用和功能有哪些
android·ios·小程序·https·uni-app·iphone·webview
_昨日重现1 天前
Jetpack系列之Compose TopBar
android·android jetpack
林胖子的私生活1 天前
绘制K线第五章:双指放大缩小
android
2501_937189231 天前
IPTV 2026 优化版:解码适配 + 安全运维双升级,筑牢使用体验基石
android·源码·开源软件·源代码管理
朽木成才1 天前
Android+Flutter混合开发实战
android·flutter
天燹1 天前
Qt 6 嵌入 Android 原生应用完整教程
android·开发语言·qt
美狐美颜sdk1 天前
企业级直播美颜SDK与动态贴纸SDK开发技术方案拆解与落地实践
android·人工智能·计算机视觉·第三方美颜sdk·人脸美型sdk