在Android上的动态壁纸中使用布局资源

时间:2010-11-13 21:13:21

标签: android canvas android-layout android-linearlayout

当您在Android 2.2+中创建LiveWallpaper时,您将获得一个画布(或任何3D等效物)来绘制。我想使用内置的Android UI工具绘制一些元素,而不是使用canvas命令从头开始构建所有元素或加载预渲染的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可以作为toast或常规视图(即一切都很好地显示),在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);

有没有人知道你是否需要做一些特别的事情来让孩子们正确地渲染到我的位图?即,我是否需要以某种方式做一些特别的事情来使布局渲染其余的孩子?我应该写一个函数来递归地对所有孩子做些什么吗?

我可以自己合成所有内容但是,因为显示是相当静态的(即我画了一次并保留了位图的副本以在背景上绘制)这对我来说似乎更容易并且仍然非常有效。

修改 在挖掘布局状态的同时,看起来好像布局没有沿着视图树向下移动(即,当我调用layout()时,LinearLayout得到它的布局,但子窗口的大小为null(0x0))。根据Romain Guy在2008年的帖子android developer post。您必须等待布局传递或自己强制布局。问题是我如何等待壁纸引擎的布局传递给没有连接到根视图组的LinearLayout?如果布局要求您在我不知道这些应该是什么时设置左,上,右,下,我怎样才能手动布局每个子元素。

我尝试过对孩子们调用forceLayout,但似乎也没有帮助。我不确定布局框架如何在幕后工作(除了它做了两遍布局)。有没有办法手动让它做布局通过,即现在?由于它不是一个活动,我不认为很多正常的背景材料正在发生我想要的方式。

2 个答案:

答案 0 :(得分:9)

动态壁纸是专为不使用标准UI小部件而设计的。但无论如何都可以使用它们。您必须首先在View上调用measure(),然后在layout()上强制执行布局传递。您可以在我的presentation

中找到更多信息

答案 1 :(得分:3)

这是一个在动态壁纸中布局和显示的视图组,按钮和图像视图的示例。如果将Window类型设置为0,您还可以解决空窗口令牌错误并直接通过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 )
                    {
                    }

            }

    }