2010-11-13 90 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