DUICUO

HarmonyOS オープンソースのサードパーティコンポーネント - 粒子フラグメンテーション効果コンポーネント Azexplosion_ohos

[[412239]]

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHarmonyOSテクノロジーコミュニティ。

https://harmonyos..com

序文

Androidプラットフォームベースのパーティクル破壊エフェクトコンポーネントであるAzexplosion(https://github.com/Xieyupeng520/AZExplosion)は、HarmonyOS向けに機能移行とリファクタリングを実施しました。コードはオープンソース化されています(https://gitee.com/isrc_ohos/azexplosion_ohos)。開発者の皆様はぜひダウンロードしてご利用いただき、貴重なフィードバックをお寄せください。

背景

Azexplosion_ohosは、パーティクル破壊アニメーション効果を実装するコンポーネントです。ユーザーは、破壊オブジェクト(通常はスマートフォン画面に表示される画像またはテキスト)をタップすることで、そのオブジェクトを破壊する効果を得ることができます。このコンポーネントでは、スマートフォン画面上のオブジェクトに破壊効果を与えるかどうかの設定や、破壊オブジェクトとその背景の変更が可能です。Azexplosion_ohosコンポーネントは、印象的な視覚効果、使いやすさ、そして高い拡張性を誇り、Xiaomiスマートフォンでアプリを削除する際のダイナミックな効果に匹敵します。

コンポーネント効果表示

コンポーネントアプリケーションには、画像とテキストという2種類の断片化されたオブジェクトを含むメインインターフェースのみが含まれています。指で画像(またはテキスト)に触れると、視覚的に断片化され、断片化された粒子の色が元の画像(またはテキスト)の色と一致します(図1を参照)。この効果は非常にリラックスでき、使いやすいです。


図1. 断片化効果の表示

サンプル分析

Azexplosion_ohosコンポーネントのコア機能は、主にライブラリにカプセル化されています。サンプルの実装は非常にシンプルです。全体のレイアウトを構築し、ライブラリが提供するリスナーインターフェースを呼び出して全体の表示レイアウトのリスナーを設定するだけで、オブジェクトの断片化効果を実現できます。具体的な実装手順は次のとおりです。

ステップ 1. レイアウトを作成します。

ステップ 2. 全体的な表示レイアウトを設定します。

ステップ 3. 関連するクラスをインポートし、オブジェクトをインスタンス化します。

ステップ 4. 全体的な表示レイアウトのリスナーを設定します。

次に、各ステップに含まれる詳細な操作を見てみましょう。

(1)レイアウトを作成する

まず、XMLファイルでDirectionalLayoutを作成し、親ビューの変更に合わせて幅と高さを調整します。次に、図1に示すように、DirectionalLayoutに必要な断片化されたオブジェクト(画像またはテキスト)を追加します。コードを以下に示します。

  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= "垂直" >
  6. <テキスト
  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= "水平" >
  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, null , false );
  3. ShapeElement 要素 = 新しい ShapeElement();
  4. 要素.setRgbColor(新しいRgbColor(255,239,213));
  5. directionalLayout.setBackground(element); // 背景色を設定する
  6. super.setUIContent(directionalLayout); // 表示レイアウトを設定する

(3)関連クラスをインポートし、オブジェクトをインスタンス化する

MainAbility では、import キーワードを使用して Library 内の ExplosionField クラスがインポートされ、onStart() メソッドで ExplosionField クラス オブジェクトがインスタンス化されます。

  1. 爆発フィールド 爆発フィールド = 新しい爆発フィールド(これ);

(4)ディスプレイレイアウト全体のリスナーを設定する

`ExplosionField` クラスオブジェクトの `addListener` メソッドは、表示レイアウト全体のリスナーを設定するために呼び出されます。表示レイアウト全体のリスナーが設定された後、ユーザーがレイアウト内のコンポーネントをクリックすると、そのコンポーネントが壊れます。

  1. 爆発フィールド.addListener((ComponentContainer)findComponentById(ResourceTable.Id_root));

ライブラリ分析

サンプルでは、​​ディスプレイレイアウト全体にリスナーを設定することで、クリック時にコンポーネントが壊れる様子を示しました。このセクションでは、このコンポーネント破損現象の詳細な原​​理を説明します。

まず、図2に示すように、Azexplosion_ohosコンポーネントのライブラリ構造を見てみましょう。この部分は主に、ExplosionAnimator、ExplosionField、Particleの3つのクラスで構成されています。ExplosionAnimatorは主にパーティクルを生成し、パーティクル破壊アニメーションを実行して、パーティクルの状態をさまざまなタイミングで変化させるために使用されます。ExplosionFieldは主にパーティクルセットのキャンバス表示を担当します。Particleクラスは主にパーティクルの色、透明度、その他の属性を記述するために使用されます。


図2 ライブラリプロジェクトの構造

以下では、ライブラリの内部ロジックの実行手順を紹介します。ユーザーが壊れたオブジェクトをクリックすると、ライブラリは壊れたオブジェクトに対応するマトリックス画像(ピクセルマップ)を生成し、それを複数のパーティクルに分解し、最後にパーティクルを動かして破壊アニメーションを作成します。具体的な処理は図3に示されています。


図3. ライブラリの内部ロジックの実行手順

1. 画像やテキストをピクセルマップに変換する

ディスプレイレイアウト全体にリスナーを追加した後、forループを使用してレイアウト内の各コンポーネントにクリックリスナーを追加します。getOnClickListener() メソッドでは、ExplosionField クラスの createBitmapFromView() メソッドが呼び出されます。createBitmapFromView() メソッドは、画像やテキストを PixelMaps(ビットマップ)に変換するための重要なメソッドです。

`createBitmapFromView()` メソッドでは、まず空の 100x100 ピクセルマップが作成されます。フラグメント化されたオブジェクトが画像の場合、`ExplosionField` クラスの `getPixelMap()` メソッドが呼び出され、画像のピクセルマップが取得されます。フラグメント化されたオブジェクトがテキストの場合、空のピクセルマップが直接返されます。この場合、画像のピクセルマップには元の画像のピクセル情報が含まれていますが、テキストのピクセルマップは空であるため、デフォルトで黒のフラグメント効果が表示されます。

  1. // レイアウト内の各コンポーネントにクリックリスナーを追加します
  2. public void addListener(コンポーネントビュー) {
  3. if ( ComponentContainer のインスタンスを表示) {
  4. ComponentContainer ビューグループ = (ComponentContainer)ビュー;
  5. 整数 カウント= viewGroup.getChildCount();
  6. // レイアウトから断片化されたオブジェクトを1つずつ抽出します
  7. for ( int i = 0 ; i < count ; i++) {
  8. リスナーを追加します(viewGroup.getComponentAt(i));
  9. }
  10. }それ以外{
  11. //壊れたオブジェクトごとにクリックリスナーを設定する
  12. ビューをClickableに設定します( true );
  13. ビュー.setClickedListener(getOnClickListener());
  14. }
  15. }
  16.  
  17. // 壊れたオブジェクトをピクセルマップに変換する
  18. プライベート PixelMap createBitmapFromView(コンポーネントビュー) {
  19. //PixelMapパラメータ初期化操作
  20. PixelMap.InitializationOptions オプション = 新しい PixelMap.InitializationOptions();
  21. options.size = 新しいサイズ(100,100);
  22. // ビットマップオブジェクトを作成する
  23. PixelMap = PixelMap.create (オプション);
  24. if(ビュー.getName().equals( "Id_qq" )){
  25. bitmap =getPixelMap(ResourceTable.Media_qq); //qqのピクセルマップ
  26. }
  27. if(ビュー.getName().equals( "Id_qzone" ))
  28. bitmap =getPixelMap(ResourceTable.Media_qzone); //qzoneのピクセルマップ
  29. if(ビュー.getName().equals( "Id_vx" ))
  30. bitmap = getPixelMap(ResourceTable.Media_vx); // WeChatのピクセルマップ
  31. ……
  32. return bitmap; // 取得したPixelMapを返す
  33. }

2. 壊れた粒子を生成する

破片状のパーティクルの生成はExplosionAnimatorの機能の一つで、主にExplosionFieldクラスのPixelMapの処理を伴います。まず、PixelMapの幅と高さに基づいて、各方向のパーティクル数を計算します。次に、パーティクルの位置の色を計算します。次に、ParticleクラスのgenerateParticle()メソッドを呼び出してパーティクルを生成します。生成された破片状のパーティクルを図4に示します。

  1. //パーティクルを生成する
  2. プライベートParticle[][] generateParticles(PixelMap ビットマップ、矩形境界) {
  3. int w = bound.getWidth(); // ピクセルマップの幅
  4. int h = bound.getHeight(); // ピクセルマップの高さ
  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. パーティクル[][] パーティクル = 新しいパーティクル[partH_Count][partW_Count];
  13. ポイント point = null ;
  14. for ( int row = 0; row < partH_Count; row ++) { //行
  15. ( int )の場合  column = 0; column < partW_Count; column ++) { //列
  16. //現在のパーティクルの位置の色を取得します
  17. int color = bitmap.readPixel(新しい位置(* bitmap_part_w、行 * bitmap_part_h));
  18. point = new Point( column , row); //xは列、yは行
  19. 粒子[行][] = Particle.generateParticle(色、境界、点);
  20. }
  21. }
  22. return particles; // 粒子行列を返す
  23. }

図4. 破砕粒子の影響

3. 粉砕アニメーションを実行します。

次に、パーティクルを動かして完全なダイナミックエフェクトを実現するためのアニメーションを作成する必要があります。このアニメーションエフェクトは、`AnimatorValue`クラスを継承した`ExplosionAnimator`クラスに依存しており、アニメーションを描画するために使用できます。以下では、このアニメーションエフェクトの実装方法を詳細に分析します。

(1) ExplosionAnimatorクラスのオブジェクトを作成する

ExplosionAnimator クラス オブジェクトの作成時に、クリックした壊れたオブジェクトの PixelMap がパラメータとして渡され、ExplosionAnimator クラス オブジェクトのメンバー変数には、前述の PixelMap によって生成されたパーティクル セットが含まれます。

  1. // ExplosionAnimator クラス オブジェクトのリストを要素とするリストの配列を作成します。
  2. プライベート ArrayList<ExplosionAnimator> 爆発アニメーション;
  3. 爆発アニメーション = 新しい ArrayList<爆発アニメーション>();
  4. // ExplosionAnimatorクラスのオブジェクトを作成する
  5. 最終的な ExplosionAnimator アニメーター = 新しい ExplosionAnimator(this、createBitmapFromView( view )、rect);
  6. //ExplosionAnimatorクラスのオブジェクトをリストに追加する
  7. 爆発アニメーションを追加します(アニメーター)

(2)開始()

リスナーは画面がタッチされたことを検知すると、(1)で作成したExplosionAnimatorクラスのオブジェクトを介してstart()メソッドを呼び出し、invalidate()メソッドを介して破壊されようとしている画像に対応するブロックを更新します。invalidate()メソッドはonDraw()メソッドを呼び出し、アニメーションを描画します。

  1. パブリックvoid start() {
  2. super.start();
  3. mContainer.invalidate();
  4. }

(3) onDraw()

onDraw() メソッドでは、まずキャンバスの描画状態を保存し、ステータスバーによるズレを修正します。その後、ExplosionAnimator の draw() メソッドをループで呼び出します。

  1. public void onDraw(Component コンポーネント、Canvas キャンバス) {
  2. canvas.save(); // キャンバスの描画状態を保存します。
  3. canvas.translate(0,positions[1]); // ステータスバーによる位置ずれを修正する
  4. (ExplosionAnimator アニメーター: 爆発アニメーション)の場合{
  5. animator.draw(キャンバス);
  6. }
  7. キャンバスを復元します。
  8. }

(4) 描画()

描画メソッドでは、パーティクルを「一歩前進させる」(徐々に下方に広げる)ために、描画ごとに advance() メソッドが 1 回呼び出され、その後、ブラシの新しいプロパティが設定され、描画が再描画されます。

  1. パブリックvoid 描画(Canvas キャンバス) {
  2. //アニメーションが終了したら停止する
  3. if(!isRunning()) {
  4. 戻る;
  5. }
  6. (Particle[] 粒子: mParticles)の場合{
  7. (粒子 p : 粒子)の場合{
  8. p.advance(私の値);
  9. mPaint.setColor(新しいColor(p.color));
  10. //この設定では、透明色は黒として表示されます。
  11. mPaint.setAlpha(( int ) (p.alpha));
  12. キャンバスに円を描画します。
  13. }
  14. }
  15. mContainer.invalidate();
  16. }

最後に、アニメーション描画処理全体の実装方法をまとめます。まず、`ExplosionField` 内で `ExplosionAnimator` の `start()` メソッドが呼び出され、アニメーションが開始されます。`start()` メソッドは `invalidate()` メソッドを呼び出し、`ExplosionField` を再描画します(`onDraw` メソッドを呼び出すことで)。

`onDraw` メソッドは `draw` メソッドを呼び出し、`draw` メソッドは `invalidate` を使用して `ExplosionField` を強制的に再描画します(`onDraw` メソッドを呼び出すことで)。各ループで 1 回の再描画が完了します。これらの 2 つのメソッドは継続的に呼び出し、すべてのパーティクルが描画されるまで描画を更新し、描画が完了すると更新を停止します。アニメーション描画プロセスを図 5 に示します。


図5 アニメーションの描画プロセス

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHarmonyOSテクノロジーコミュニティ。

https://harmonyos..com