Использование ресурсов 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 )
{
}
}
}