|
|
|
|
公众号矩阵

鸿蒙开源第三方组件—粒子破碎效果组件Azexplosion_ohos

Azexplosion_ohos是一个实现粒子破碎动画效果的组件,用户可以通过点击手机屏幕上的破碎对象(一般是指手机屏幕上显示的图片或文字),来达到将该对象破碎的效果。

作者:朱伟ISRC来源:鸿蒙社区|2021-07-20 15:20

想了解更多内容,请访问:

51CTO和华为官方战略合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

前言

基于安卓平台的粒子破碎效果组件Azexplosion(https://github.com/Xieyupeng520/AZExplosion), 实现了鸿蒙的功能化迁移和重构。代码已经开源到(https://gitee.com/isrc_ohos/azexplosion_ohos),欢迎各位开发者下载使用并提出宝贵意见!

背景

Azexplosion_ohos是一个实现粒子破碎动画效果的组件,用户可以通过点击手机屏幕上的破碎对象(一般是指手机屏幕上显示的图片或文字),来达到将该对象破碎的效果。该组件可以设置手机屏幕上的对象是否具有破碎效果,同时也可以更换破碎对象和破碎对象的背景。Azexplosion_ohos组件视觉效果突出、使用方便、可扩展性强,与小米手机删除APP时的动态效果类似。

组件效果展示

组件应用仅包含一个主界面,在界面中存在图片和文字两种破碎对象。当手指触碰图片(或文字)时,该图片(或文字)在视觉上呈现破碎效果,且破碎粒子的颜色与原图片(或文字)的颜色相对应,如图1所示,效果看起来很解压,非常好用~

鸿蒙开源第三方组件——粒子破碎效果组件Azexplosion_ohos-鸿蒙HarmonyOS技术社区

图1 破碎效果展示

Sample解析

Azexplosion_ohos组件的核心功能主要被封装在Library中,Sample的功能实现很简洁,只需要构建整体的布局,并调用Library提供的监听接口为整体显示布局设置监听,即可实现效果执行的对象的破碎效果,具体的实现步骤如下:

步骤1. 创建布局。

步骤2. 设置整体显示布局。

步骤3. 导入相关类并实例化对象。

步骤4. 为整体显示布局设置监听。

接下来我们来看一下每一个步骤涉及的详细操作。

(1)创建布局

首先在XML文件中创建一个DirectionalLayout的布局,宽度和高度都跟随父控件变化而调整。后在DirectionalLayout加入需要的破碎对象,可以是图片或文字,如图1所示,代码如下所示。

  1. <DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  2.               ohos:id="$+id:root" 
  3.               ohos:width="match_parent" 
  4.               ohos:height="match_parent" 
  5.               ohos:orientation="vertical"
  6.     <Text 
  7.             ohos:width="match_content"     //文字破碎对象 
  8.             ohos:text="破碎效果"                 
  9.             ohos:text_size="60vp" 
  10.             ohos:top_margin="10vp" 
  11.             ohos:left_margin="20vp" 
  12.             ohos:bottom_margin="15vp" 
  13.             ohos:right_padding="10vp" 
  14.             ohos:left_padding="40vp" 
  15.             ohos:height="match_content"/> 
  16.  
  17.     <DirectionalLayout ohos:id="$+id:group1" 
  18.             ohos:width="match_parent" 
  19.             ohos:height="100vp" 
  20.             ohos:top_margin="10vp" 
  21.             ohos:orientation="horizontal"
  22.  
  23.         <Image                           //图片破碎对象 
  24.             ohos:id="$+id:qq" 
  25.             ohos:width="match_content" 
  26.             ohos:height="match_content" 
  27.             ohos:image_src="$media:qq" 
  28.             ohos:left_margin="25vp" 
  29.             ohos:right_margin="25vp" 
  30.             ohos:top_margin="15vp"/> 
  31.         ...... 

(2)设置整体显示布局

在MainAbility文件的onStart()方法中,通过setUIContent为应用设置整体显示布局,将步骤(1)中的布局设置为应用的主界面布局。为了显示的美观性,可以通过setBackground设置主界面的背景颜色。

  1. //directionalLayout 指向步骤(1)中的布局 
  2. DirectionalLayout directionalLayout = (DirectionalLayout) LayoutScatter.getInstance(this).parse(ResourceTable.Layout_mian_activity, nullfalse); 
  3. ShapeElement element = new ShapeElement();    
  4. element.setRgbColor(new RgbColor(255,239,213));  
  5. directionalLayout.setBackground(element);      //背景颜色设置 
  6. super.setUIContent(directionalLayout);      //设置显示布局 

(3) 导入相关类并实例化对象

在MainAbility中,通过import关键字导入Library中的ExplosionField 类,并在onStart()方法中实例化ExplosionField类对象。

  1. ExplosionField explosionField = new ExplosionField(this); 

(4)为整体显示布局设置监听

调用ExplosionField类对象的内部方法addListener,用于为整体显示布局设置监听。整体显示布局设置监听后,用户点击布局内某个组件,组件就会出现破碎现象。

  1. explosionField.addListener((ComponentContainer)findComponentById(ResourceTable.Id_root)); 

 Library解析

在Sample中介绍了为整体显示布局设置监听后,点击布局内的组件就会出现破碎现象。本节,我们来讲组件破碎现象形成的详细原理。

先来看看Azexplosion_ohos组件的Library组成结构,如图2所示,该部分主要由三个类组成,分别是ExplosionAnimator、ExplosionField、Particle。ExplosionAnimator主要用于生成粒子并执行粒子破碎动画,改变不同时刻的粒子状态;ExplosionField主要功能负责粒子集的画布显示;Particle类主要用于描述粒子的颜色、透明度等属性。

鸿蒙开源第三方组件——粒子破碎效果组件Azexplosion_ohos-鸿蒙HarmonyOS技术社区

图2 Library项目结构

下面我们介绍Library内部逻辑的执行步骤。当用户点击破碎对象后,Library负责生成破碎对象对应的矩阵图像(PixelMap),然后把矩阵图像分解成若干个粒子,最后再让粒子动起来形成破碎的动画,具体流程如图3所示 。

鸿蒙开源第三方组件——粒子破碎效果组件Azexplosion_ohos-鸿蒙HarmonyOS技术社区

图3 Library内部逻辑的执行步骤

1、图像或文字转换成PixelMap

为整体显示布局添加listener后,会通过for循环的方式,为每一个布局内的组件添加点击监听。在getOnClickListener()方法中,会继续调用ExplosionField类createBitmapFromView()方法,而createBitmapFromView()方法就是完成图像或文字转换成PixelMap(位图)的关键方法。

在createBitmapFromView()方法中首先会创建一个100*100的空的PixelMap,若破碎对象为图片,则通过调用ExplosionField类的getPixelMap()方法获取Image的PixelMap;若破碎对象为文字,则直接返回空的PixelMap。此时,图片的PixelMap自带图片原本的像素信息,而由于文字得到的PixelMap是空的,所以默认显示黑色的破碎效果。

  1. //为每一个布局内的组件添加点击监听 
  2. public void addListener(Component view) { 
  3.     if (view instanceof ComponentContainer) { 
  4.         ComponentContainer viewGroup = (ComponentContainer) view
  5.         int count = viewGroup.getChildCount(); 
  6.         // 逐个取出布局内的破碎对象 
  7.         for (int i = 0 ; i < count; i++) { 
  8.             addListener(viewGroup.getComponentAt(i)); 
  9.         } 
  10.     } else { 
  11.         //为每一个破碎对象设置点击监听 
  12.         view.setClickable(true); 
  13.         view.setClickedListener(getOnClickListener()); 
  14.     } 
  15.  
  16. //将每一个破碎对象转换为PixelMap 
  17.  private PixelMap createBitmapFromView(Component view) { 
  18.     //PixelMap参数初始化操作 
  19.     PixelMap.InitializationOptions options = new PixelMap.InitializationOptions(); 
  20.     options.size = new Size(100,100); 
  21.     //创建位图对象 
  22.     PixelMap   = PixelMap.create(options); 
  23.     if(view.getName().equals("Id_qq")){ 
  24.         bitmap =getPixelMap(ResourceTable.Media_qq);   //qq的PixelMap 
  25.     } 
  26.     if(view.getName().equals("Id_qzone")) 
  27.         bitmap =getPixelMap(ResourceTable.Media_qzone);  //qzone的PixelMap 
  28.     if(view.getName().equals("Id_vx")) 
  29.         bitmap =getPixelMap(ResourceTable.Media_vx);    //微信的PixelMap 
  30.         ......     
  31.     return bitmap;  //将获取的PixelMap返回 

2、生成破碎粒子

生成破碎粒子是ExplosionAnimator的功能之一,主要是对来自ExplosionField类的PixelMap进行处理。首先根据PixelMap的宽高,算出横竖粒子的个数。然后计算出粒子所在位置的颜色。接着调用Particle类的generateParticle()方法生成粒子,生成的破碎粒子如图4所示。

  1. //生成粒子 
  2.    private Particle[][] generateParticles(PixelMap bitmap, Rect bound) { 
  3.        int w = bound.getWidth();  //PixelMap的宽 
  4.        int h = bound.getHeight(); // PixelMap的高 
  5.        int partW_Count = w / Particle.PART_WH; //横向粒子个数 
  6.        int partH_Count = h / Particle.PART_WH; //竖向粒子个数 
  7.        //粒子的宽 
  8.        int bitmap_part_w = bitmap.getImageInfo().size.width / partW_Count; 
  9.        //粒子的高 
  10.        int bitmap_part_h = bitmap.getImageInfo().size.height / partH_Count; 
  11.        //粒子矩阵 
  12.        Particle[][] particles = new Particle[partH_Count][partW_Count]; 
  13.        Point point = null
  14.        for (int row = 0; row < partH_Count; row ++) { //行 
  15.            for (int column = 0; column < partW_Count; column ++) { //列 
  16.                //取得当前粒子所在位置的颜色 
  17.                int color = bitmap.readPixel(new Position(column* bitmap_part_w, row * bitmap_part_h)); 
  18.                point = new Point(column, row); //x是列,y是行 
  19.                particles[row][column] = Particle.generateParticle(color, bound, point); 
  20.            } 
  21.        } 
  22.        return particles;   //返回粒子矩阵 
  23.    } 
鸿蒙开源第三方组件——粒子破碎效果组件Azexplosion_ohos-鸿蒙HarmonyOS技术社区

图4 破碎粒子效果图

3、执行破碎动画

接下来我们需要为粒子加上动画,让它们动起来,实现一个完整的动态效果。动画效果的实现需要依赖ExplosionAnimator 类,ExplosionAnimator 类继承自AnimatorValue类,可用于绘制动画。下面我们具体分析动画效果是如何实现的。

(1)创建ExplosionAnimator 类对象

在创建ExplosionAnimator 类对象的过程中,将被点击的破碎对象的PixelMap作为参数传入,得到ExplosionAnimator 类对象的成员变量包含上述PixelMap生成的粒子集。

  1. //创建元素为列表ExplosionAnimator类对象的数组列表 
  2. private ArrayList<ExplosionAnimator> explosionAnimators; 
  3. explosionAnimators = new ArrayList<ExplosionAnimator>();   
  4. //创建ExplosionAnimator 类对象  
  5. final ExplosionAnimator animator = new ExplosionAnimator(this, createBitmapFromView(view), rect);    
  6. //ExplosionAnimator 类对象添加到列表中 
  7. explosionAnimators.add(animator);  

(2)start()

当监听器监听到屏幕被触碰时,通过(1)中创建的ExplosionAnimator 类对象调用start() 方法,通过invalidate()来刷新将要破碎的图片所对应的区块,invalidate()方法会调用onDraw()方法进行动画绘制。

  1. public void start() { 
  2.         super.start(); 
  3.         mContainer.invalidate(); 

(3)onDraw()

在onDraw()方法里,首先保存画布的绘制状态并修正因为状态栏导致的错位,然后循环调用ExplosionAnimator 的draw()方法。

  1. public void onDraw(Component component, Canvas canvas) { 
  2.     canvas.save(); // 保存画布的绘制状态 
  3.     canvas.translate(0,positions[1]); //修正因为状态栏导致的错位 
  4.     for (ExplosionAnimator animator : explosionAnimators) { 
  5.         animator.draw(canvas); 
  6.     } 
  7.     canvas.restore(); 

(4)draw()

在draw方法中,每次绘制都调用一次advance()方法让粒子“前进一步”(逐渐向下扩散),然后设置画笔的新属性并重新绘制。

  1. public void draw(Canvas canvas) { 
  2.         //动画结束时停止 
  3.         if(!isRunning()) { 
  4.             return
  5.         } 
  6.         for (Particle[] particle : mParticles) { 
  7.             for (Particle p : particle) { 
  8.                 p.advance(myvalue); 
  9.                 mPaint.setColor(new Color(p.color)); 
  10.                 //只是这样设置,透明色会显示为黑色 
  11.                 mPaint.setAlpha((int) (p.alpha)); 
  12.                 canvas.drawCircle(p.cx, p.cy, p.radius, mPaint); 
  13.             } 
  14.         } 
  15.         mContainer.invalidate(); 
  16.     } 

最后,我们总结一下整体的动画绘制的过程是如何实现的。首先在ExplosionField中调用ExplosionAnimator的start()方法开启动画,start()方法中会调用invalidate()方法来使ExplosionField重绘(调用onDraw方法)。

onDraw方法调用draw方法,draw方法中也使用invalidate强制ExplosionField重绘(调用onDraw方法),每一次循环完成一次重绘。 这样两者相互调用,不停地刷新,直到所有粒子都绘制完成,刷新停止,动画绘制流程如图5所示。

鸿蒙开源第三方组件——粒子破碎效果组件Azexplosion_ohos-鸿蒙HarmonyOS技术社区

图5 动画绘制流程

想了解更多内容,请访问:

51CTO和华为官方战略合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

【编辑推荐】

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区
  2. Hi3516驱动开发全面详解
  3. HarmonyOS应用如何打包HAP并安装到真机
  4. JS UI框架下FA与PA是如何交互的
  5. HarmonyOS原子化服务原理和架构分析
  6. 【软通动力】HarmonyOS服务卡片-古诗词学习
【责任编辑:jianghua TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢
24H热文
一周话题
本月获赞

订阅专栏+更多

带你轻松入门 RabbitMQ

带你轻松入门 RabbitMQ

轻松入门RabbitMQ
共4章 | loong576

26人订阅学习

数据湖与数据仓库的分析实践攻略

数据湖与数据仓库的分析实践攻略

助力现代化数据管理:数据湖与数据仓库的分析实践攻略
共3章 | 创世达人

12人订阅学习

云原生架构实践

云原生架构实践

新技术引领移动互联网进入急速赛道
共3章 | KaliArch

41人订阅学习

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO官微