2010-11-13 22 views
5

当您在Android 2.2或更高版本中创建LiveWallpaper时,您将得到一个画布(或任何3D等价物)来绘制。我想使用内置的Android UI工具来绘制一些元素,而不是使用canvas命令从头开始构建所有内容,或者加载预渲染的UI位图。在Android上的LiveWallpaper中使用布局资源

转换单一视图为位图工作正常。即这工作很好:

// 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子项位于Bitmap中。我也尝试使用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中得到它的布局时,我打电话布局(计算机),但孩子们有一个空(0x0)大小)。根据2008年的罗曼盖伊的职位android developer post。您必须等待布局通过或自己强制布局。问题是如何等待来自墙纸引擎的布局传递给未连接到根视图组的LinearLayout?如果布局要求您设置左侧,顶部,右侧和底部,我不知道这些应该是什么,那么如何手动布局每个子元素。

我已经打过电话forceLayout的孩子,但它似乎并没有帮助的。我不确定布局框架是如何在幕后工作的(除此之外它还实现了两遍布局)。有没有办法手动让它做布局传递,即现在?由于这不是一个活动,我不认为很多正常的背景资料都是按照我喜欢的方式进行的。

+0

您是否实施了建议的解决方案?我正在评估相同的方法,但希望从您的经验中学习 – dparnas 2012-01-12 14:40:24

回答

8

动态壁纸是非常特别设计,不使用标准的UI部件。不过,无论如何都可以使用它们。您必须首先在视图上调用measure(),然后在layout()上调用布局。您可以在我的presentation中找到更多信息。

+13

@JustinBuser我是在Android团队中设计和实现动态壁纸的工程师之一。您提到的类与我们正在讨论的标准UI小部件无关。重点是你不能直接添加视图到动态壁纸(使用setContentView(),addView()等)。例如,一个ListView。我链接到的演示文稿是关于如何自己测量和布置视图。 – 2012-11-02 00:42:01

+1

演示文稿解释了如何在视图上调用measure()和layout()。一旦视图已经被测量和布置,它可以被绘制到画布上,例如在动态壁纸上。 – 2012-11-16 17:57:44

3

这里的一个视图组,按钮和ImageView的布局,并在动态壁纸显示的一个例子。如果将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) 
        { 
        } 

      } 

    } 
+0

这就是为什么我们不能拥有好东西的原因......“你必须捕捉它引发的异常,结果有些不稳定,但它在很大程度上起作用。”真??? – Dan 2012-12-01 21:35:57

+3

我的回答主要是对那种说“活壁纸非常专门设计为不使用标准UI小部件”的回应。这是一个荒谬和误导性的答案。这就好像说飞机是“专门设计成不能潜入水中的”。我的观点基本上是因为你没有做出防水的事情并不意味着它不能完成。我写了这个示例代码的15分钟证明它实际上可以完成,但是我没有真正感到倾向于在证明了我的观点之后彻底调试它,因此发现了一个错误的警告。 – 2012-12-31 21:49:02

+0

这个解决方案实际上工作! :D代码有点搞砸了,它缺少一些代码,但它确实有效。但我有个问题。我有一个扩展GLSurfaceView的子类,它有一个3D对象被渲染,我怎么能让它们显示的3D对象在背景上的ImageView在上面?谢谢! – 2016-02-17 13:02:39