5

Android 2.2 以降で LiveWallpaper を作成すると、描画するキャンバス (または 3D に相当するもの) が得られます。キャンバス コマンドを使用してゼロからすべてを構築したり、事前にレンダリングされた UI ビットマップを読み込んだりするのではなく、組み込みの Android UI ツールを使用していくつかの要素を描画したいと考えています。

単一のビューをビットマップに変換するとうまくいきます。つまり、これはうまく機能します:

// For example this works:
TextView view = new TextView(ctx);
view.layout(0, 0, 200, 100);
view.setText("test");
Bitmap b = Bitmap.createBitmap( 200, 100, Bitmap.Config.ARGB_8888);                
Canvas tempC = new Canvas(b);
view.draw(tempC);
c.drawBitmap(b, 200, 100, mPaint);

ただし、子を持つ LinearLayout を変換すると問題が発生します。LinearLayout自体のみを取得し、その子は取得しません。たとえば、LinearLayout を白い背景に設定すると、きれいにレンダリングされた白いボックスが表示されますが、Bitmap には TextView の子はありません。同様の結果で DrawingCache も使用してみました。

私が使用しているコードは、追加の描画コマンドだけが変更された立方体の例です。LinearLayout は、トーストまたは通常のビュー (つまり、すべてがうまく表示される) として正常に動作します。LiveWallpaper では、LinearLayout の背景がレンダリングされるだけです。

inflater = (LayoutInflater)getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layout = (LinearLayout) inflater.inflate(com.example.android.livecubes.R.layout.testLinearLayout, null);
layout.layout(0, 0, 400, 200);

Bitmap b = Bitmap.createBitmap( 400, 200, Bitmap.Config.ARGB_8888);
Canvas tempC = new Canvas(b);
layout.draw(tempC);
c.drawBitmap(b, 10, 200, mPaint);

子をビットマップに適切にレンダリングするために何か特別なことをする必要があるかどうか、誰か知っていますか? つまり、レイアウトが残りの子をレンダリングするために何か特別なことをする必要がありますか? すべての子に対して再帰的に何かを行う関数を作成する必要がありますか?

私は自分ですべてを合成することができましたが、表示がかなり静的であるため (つまり、これを一度描画し、ビットマップのコピーを保持して背景に描画します)、これは私にとってより簡単で、それでもかなり効率的です。

編集: レイアウトの状態をもう少し掘り下げると、レイアウトがビュー ツリーを下って進んでいないように見えます (つまり、 LinearLayout は、layout() を呼び出すと計算されたレイアウトを取得しますが、子のサイズは null (0x0) です。 )。2008 android developer postの Romain Guy の投稿によると。レイアウト パスを待つか、自分でレイアウトを強制する必要があります。問題は、ルート ビュー グループにアタッチされていない LinearLayout の壁紙エンジンからのレイアウト パスをどのように待つことができるかということです。また、レイアウトで左、上、右、下を設定する必要がある場合、これらがどうあるべきかわからない場合、各子要素を手動でレイアウトするにはどうすればよいですか。

子で forceLayout を呼び出してみましたが、どちらも役に立たないようです。レイアウト フレームワークが舞台裏でどのように機能するかはわかりません (2 パス レイアウトを実行する以外に)。手動でレイアウト パスを実行させる方法はありますか? これはアクティビティではないため、通常のバックグラウンド処理の多くが思いどおりに行われていないと思います。

4

2 に答える 2

10

ライブ壁紙は、標準の UI ウィジェットを使用しないように特別に設計されています。ただし、とにかくそれらを使用することは可能です。最初に View で measure() を呼び出し、次に layout() を呼び出して、自分でレイアウト パスを強制する必要があります。詳細については、私のプレゼンテーションを参照してください。

于 2011-02-15T07:53:21.817 に答える
3

これは、ビュー グループ、ボタン、およびイメージビューをレイアウトしてライブ壁紙に表示した例です。Window タイプを 0 に設定すると、null ウィンドウ トークンのバグを回避し、WindowManager を介して直接ビューを追加することもできます。スローされる例外をキャッチする必要があり、結果は多少不安定になりますが、ほとんどの場合は機能します。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class UIWidgetWallpaper extends WallpaperService
    {

        private final String    TAG         = getClass().getSimpleName();
        final static int        pixFormat   = PixelFormat.RGBA_8888;
        protected ImageView     imageView;
        protected WindowManager windowManager;
        protected LayoutParams  layoutParams;
        protected WidgetGroup   widgetGroup;
        protected SurfaceHolder surfaceHolder;
        protected Button        button;

        @Override
        public Engine onCreateEngine()
            {
                Log.i( TAG, "onCreateEngine" );
                return new UIWidgetWallpaperEngine();
            }

        public class WidgetGroup extends ViewGroup
            {

                private final String    TAG = getClass().getSimpleName();

                public WidgetGroup( Context context )
                    {
                        super( context );
                        Log.i( TAG, "WidgetGroup" );
                        setWillNotDraw( true );
                    }

                @Override
                protected void onLayout( boolean changed, int l, int t, int r, int b )
                    {
                        layout( l, t, r, b );
                    }

            }

        public class UIWidgetWallpaperEngine extends Engine implements Callback
            {

                private final String    TAG = getClass().getSimpleName();

                @Override
                public void onCreate( SurfaceHolder holder )
                    {
                        Log.i( TAG, "onCreate" );
                        super.onCreate( holder );
                        surfaceHolder = holder;
                        surfaceHolder.addCallback( this );
                        imageView = new ImageView( getApplicationContext() );
                        imageView.setClickable( false );
                        imageView.setImageResource( R.drawable.icon );
                        widgetGroup = new WidgetGroup( getApplicationContext() );
                        widgetGroup.setBackgroundDrawable( getWallpaper() );
                        widgetGroup.setLayoutParams( new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT ) );
                        widgetGroup.setAddStatesFromChildren( true );
                        holder.setFormat( pixFormat );
                        LinearLayout.LayoutParams imageParams = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT );
                        imageParams.weight = 1.0f;
                        imageParams.gravity = Gravity.CENTER;
                        widgetGroup.addView( imageView, imageParams );
                        button = new Button( getApplicationContext() );
                        button.setText( "Test Button" );
                        LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT );
                        buttonParams.weight = 1.0f;
                        buttonParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
                        widgetGroup.addView( button, buttonParams );
                    }

                @Override
                public void surfaceChanged( SurfaceHolder holder, int format, int width, int height )
                    {
                        Log.i( TAG, "surfaceChanged: " );
                        synchronized( surfaceHolder )
                            {
                                Canvas canvas = surfaceHolder.lockCanvas();
                                widgetGroup.layout( 0, 0, width, height );
                                imageView.layout( 0, 0, width / 2, height );
                                button.layout( width / 2, height - 100, width, height );
                                widgetGroup.draw( canvas );
                                surfaceHolder.unlockCanvasAndPost( canvas );
                            }
                    }

                @Override
                public void surfaceCreated( SurfaceHolder holder )
                    {
                    }

                @Override
                public void surfaceDestroyed( SurfaceHolder holder )
                    {
                    }

            }

    }
于 2012-11-15T20:17:07.837 に答える