Использование ресурсов Layout в LiveWallpaper на Android

Когда вы создаете LiveWallpaper в Android 2.2+, вы получаете холст (или любой другой 3D-эквивалент) для рисования. Я хотел бы нарисовать некоторые элементы, используя встроенные инструменты пользовательского интерфейса Android, а не создавать все с нуля, используя команды canvas или загрузку предварительно визуализированного растрового изображения пользовательского интерфейса.

Преобразование одного представления в растровое изображение работает нормально. т.е. это прекрасно работает:

// 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 белый фон, я получаю хорошо визуализированный белый прямоугольник, но ни один из дочерних объектов 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(), но дочерние элементы имеют нулевой (0x0) размер)). По сообщению Ромена Гая в 2008 году, пост разработчика Android. Вы должны дождаться прохождения макета или принудительно выполнить макет самостоятельно. Проблема заключается в том, как я могу ждать проход макета из механизма обоев для LinearLayout, который не присоединен к корневой группе представлений? И как я могу вручную разметить каждый дочерний элемент, если разметка требует, чтобы вы установили левый, верхний, правый, нижний, когда я не знаю, что это должно быть.

Я пытался вызвать forceLayout для детей, но, похоже, это тоже не помогло. Я не уверен, как фреймворк работает за кулисами (кроме того, что он делает двухпроходный макет). Есть ли способ сделать это вручную, то есть прямо сейчас? Поскольку это не деятельность, я не думаю, что многие обычные фоновые вещи происходят так, как мне бы хотелось.

2 ответа

Живые обои были специально разработаны, чтобы НЕ использовать стандартные виджеты интерфейса. Однако их можно использовать в любом случае. Вам нужно будет принудительно передать макет, сначала вызвав measure() в представлении, а затем layout(). Вы можете найти больше информации в моей презентации.

Вот пример группы представлений, кнопок и изображений, разложенных и отображенных на живых обоях. Вы также можете обойти ошибку маркера нулевого окна и добавить представления непосредственно через WindowManager, если вы установили тип окна на 0. Вы должны отловить исключение, которое оно выдает, и результаты несколько ошибочны, но это работает по большей части.

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 )
                    {
                    }

            }

    }
Другие вопросы по тегам