2012-05-08 29 views
6

我創建自己的自定義SurfaceView其工作對自己很好,但是當我嘗試把兩個在分開的選項卡中TabWidget只有一個是有史以來無論哪個選項卡顯示已被選中,它總是在應用程序啓動時首先繪製的SurfaceView。無法顯示2個實例我自定義的SurfaceView

爲了說明我已經創建了可被編譯以顯示給問題樣本代碼的問題。

下SurfaceView,稱爲SurfaceViewCircle只需創建一個位圖,繪製一個藍色圓圈爲默認值,然後顯示它。有一個公共方法changeColour(),它將更改位圖中的圓形顏色。

其次,我創造出只包含SurfaceViewCircle的單一實例的XML佈局。

在活動類,創建一個TabWidget和主機等,然後我膨脹上述XML兩次,但在一個實例中我改變SurfaceViewCircle的顏色爲紅色。一旦應用程序運行,無論我選擇哪個標籤,當應用程序退出並顯示藍色圓圈時,紅色圓圈總是顯示爲一個簡短實例。

任何人都可以指出,如果我錯過了一個步驟時使用SurfaceView?

這是活動代碼:

public class TestActivity extends Activity { 
/** Called when the activity is first created. */ 

private TabHost mTabHost; 
private Context mTabHostContext; 
private View surfaceView1, surfaceView2; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    /* 
    * Setup tabs 
    */ 
    setContentView(R.layout.maintabs); 
     setupTabHost(); //Prepares the TabHost from code rather than XML; 
    mTabHost.getTabWidget().setDividerDrawable(R.drawable.tab_divider); //Sets a thin dividing line 
    mTabHostContext = mTabHost.getContext(); 
    surfaceView1 = LayoutInflater.from(mTabHostContext).inflate(R.layout.surfaceviewindependent, null); 
    SurfaceViewCircle s = (SurfaceViewCircle)surfaceView1.findViewById(R.id.circle1); 
    /* 
    * Change the colour to red 
    */ 
    s.changeColour(getResources().getColor(R.color.red_square)); 

    /* 
    * Create a second layout containing SurfaceViewCircle but leave circle as default blue. 
    */ 
    surfaceView2 = LayoutInflater.from(mTabHostContext).inflate(R.layout.surfaceviewindependent, null); 
    setupTab(surfaceView1,"SurfaceView1"); 
    setupTab(surfaceView2,"SurfaceView2"); 


} 

private void setupTabHost() { 
    mTabHost = (TabHost) findViewById(android.R.id.tabhost); 
    mTabHost.setup(); 
} 

private void setupTab(final View view, final String tag) { 
    View tabview = createTabView(mTabHost.getContext(), tag); // This creates a view to be used in the TAB only 

    /* this creates the tab content AND applies the TAB created in the previous step in one go */ 
    TabSpec setContent = mTabHost.newTabSpec(tag).setIndicator(tabview).setContent(new TabContentFactory() { 
     public View createTabContent(String tag) {return view;} 
    }); 
    mTabHost.addTab(setContent); 

} 

private static View createTabView(final Context context, final String text) { 
    View view = LayoutInflater.from(context).inflate(R.layout.tabs_bg, null); 
    TextView tv = (TextView) view.findViewById(R.id.tabsText); 
    tv.setText(text); 

    return view; 
} 
} 

這是我的自定義SurfaceView:

public class SurfaceViewCircle extends SurfaceView implements SurfaceHolder.Callback{ 

private Paint paint, circlePaint; 
private Bitmap bitmap = null; 
private int w; 
private int h; 
private int colour = 0; 
private Resources r = null; 
private _Thread t = null; 
private boolean surfaceIsCreated; 

public SurfaceViewCircle(Context context) { 
    super(context); 
    initialise(); 
} 

public SurfaceViewCircle(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    initialise(); 
} 

public SurfaceViewCircle(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    initialise(); 
} 

private void initialise(){ 
    r = getResources(); 
    getHolder().addCallback(this); 
    paint = new Paint(Paint.ANTI_ALIAS_FLAG); 
    paint.setFilterBitmap(true); 
    colour = R.color.blue_square; 
    circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
    circlePaint.setColor(r.getColor(colour)); 
    circlePaint.setStyle(Style.FILL); 
    circlePaint.setStrokeWidth(0.02f); 
    t = new _Thread(getHolder()); 


} 

public void changeColour(int colour){ 
    circlePaint.setColor(colour); 
    if (surfaceIsCreated){ 
     createBitmap(); 
    } 
    synchronized (t){ 
     t.notify(); 
    } 
} 

private Bitmap createBitmap(){ 
    Bitmap b = null; 
    b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
    Canvas c = new Canvas(b); 
    c.scale((float)w, (float)w);  //Scales the background for whatever pixel size 
    c.drawCircle(0.5f, 0.5f, 0.5f, circlePaint); 
    //c.drawColor(r.getColor(colour)); 
    return b; 
} 

public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ 
    int width = measure(widthMeasureSpec); 
    int height = measure(heightMeasureSpec); 

    int d = Math.min(width, height); 
    setMeasuredDimension(d,d); 
} 

private int measure(int measureSpec) { 
    int result = 0; 
    // Decode the measurement specifications 
    int specMode = MeasureSpec.getMode(measureSpec); 
    int specSize = MeasureSpec.getSize(measureSpec); 

    return specSize; 
} 

@Override 
protected void onSizeChanged(int w, int h, int oldW, int oldH){ 
    super.onSizeChanged(w, h, oldW, oldH); 
    //synchronized (this){ 
     this.w = Math.min(w, h); 
     this.h = w; 
    //} 
    Bitmap b = createBitmap(); 

     bitmap = b; 

    Log.i("Square", "onSizeChanged() called."); 


} 
@Override 
public void surfaceChanged(SurfaceHolder holder, int format, int width, 
     int height) { 
    // TODO Auto-generated method stub 

} 

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    Log.i("Panel", "surfaceCreated() called."); 
    t.setRunning(true); 
    t.start(); 
    surfaceIsCreated = true; 

} 

@Override 
public void surfaceDestroyed(SurfaceHolder holder) { 
    Log.i("Square", "surfaceDestroyed() called."); 

    surfaceIsCreated = false; 
    boolean retry = true; 
    synchronized (t){ 
     t.setRunning(false); 
     t.notify(); 
    } 
    while (retry) { 
     try { 
      t.join(); 
      retry = false; 
     } catch (InterruptedException e) { 
      // we will try it again and again... 
     } 
    } 

} 

private class _Thread extends Thread { 
    private SurfaceHolder _surfaceHolder; 
    private boolean _run = false; 

    public _Thread(SurfaceHolder surfaceHolder) { 
     _surfaceHolder = surfaceHolder; 
    } 

    public void setRunning(boolean run) { 
     _run = run; 
    } 

    @Override 
    public void run() { 
     Canvas c = null; 
     while (_run){ 
      try { 
       c = _surfaceHolder.lockCanvas(null); 
       synchronized (_surfaceHolder) { 
        synchronized(bitmap){ 
         c.drawBitmap(bitmap, 0, 0, paint); 
        } 
       } 
      } finally { 
       // do this in a finally so that if an exception is thrown 
       // during the above, we don't leave the Surface in an 
       // inconsistent state 
       if (c != null) { 
        _surfaceHolder.unlockCanvasAndPost(c); 
       } 
      } 
      synchronized(this){ 
       try { 
        wait(); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 

       } 
      } 
     } 
    } 
} 
} 

的maintabs.xml文件:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="vertical" android:layout_width="fill_parent" 
android:layout_height="fill_parent"> 
<TabHost xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/tabhost" android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
    <LinearLayout android:orientation="vertical" 
     android:layout_width="fill_parent" android:layout_height="fill_parent"> 
     <TabWidget android:id="@android:id/tabs" 
      android:layout_width="fill_parent" android:layout_height="wrap_content" 
      android:layout_marginLeft="0dip" android:layout_marginRight="0dip" /> 
      <FrameLayout android:id="@android:id/tabcontent" 
      android:layout_width="fill_parent" android:layout_height="fill_parent" /> 
    </LinearLayout> 
    </TabHost> 
</LinearLayout> 

而且surfaceviewindependent.xml:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
<uk.co.androidcontrols.gauges.SurfaceViewCircle 
android:id="@+id/circle1" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_weight="0.5" 
    android:layout_margin="1dip"> 
</uk.co.androidcontrols.gauges.SurfaceViewCircle> 
</LinearLayout> 

我還注意到,其他人遇到過類似的問題here.

道歉窮人格式,但代碼編輯器是無法使用在附近的大碼報價!

附加信息

我試着用在onvisibilityChanged()setVisibility()',但它最終會導致異常:每次

protected void onVisibilityChanged(View changedView, int visibility){ 
    super.onVisibilityChanged(changedView, visibility); 
    changedView.setVisibility(visibility); 
    Log.i("SurfaceViewCircle", "onVisibilityChanged() called."); 
} 

java.lang.IllegalThreadStateException: Thread already started. 

看來調用changedView.setvisibility()破壞表面。

+0

您setupTab你只創建一個在我看來,嘗試檢查這一點:http://stackoverflow.com/a/5034063/ 1084764 – Raykud

+0

謝謝Raykud。將檢查出來並稍後再報告。 – Kerry

回答

1

看起來像什麼,我想SurfaceView做不建議:link

4

我建立了一個基於你的代碼的測試項目,並且出乎意料地花了幾個小時擺弄它。我現在應該快速脫口而出,因爲我應該解決這個問題!

首先,你最肯定創建兩個標籤,其中有您的自定義SurfaceView的一個單獨的實例每個選項卡。沒關係。

現在,當顯示了Activity第一次啓動和第一個選項卡中,只有第一SurfaceView被初始化並具有surfaceCreated()調用,此時它的Thread運行。

當第二個選項卡被選中時,createTabContent()回撥爲其提供的第二個SurfaceView被初始化,就像第一個那樣。從此,從這個角度,直到Activity的拆卸,SurfaceView S保持存儲在其有效的表面狀態。在選項卡之間切換不會在SurfaceView上調用surfaceDestroyed(),所以SurfaceCreated()也不會再次被調用。 'onMeasure()'在第一次創建後都不會被再次調用。因此,這告訴我這兩個SurfaceView都保留在總體View層次結構中。無論SurfaceViewsThread s的運行,如果你沒有在那裏wait(),雙方將繼續努力使顯存。

正如你所知道的,SurfaceView在它的座標(或者說,不坐)中是非常獨特的,它在View層次中。這裏似乎發生的是,要創建的第一個SurfaceView是其輸出在視頻內存中顯示的那個,無論選項卡選擇如何。

有一件事我第一次嘗試是有第二SurfaceView比第一顯著較小,內部的比例小了一圈。當從第一選項卡(具有大的紅色圓圈較大SurfaceView)到第二選項卡(較小SurfaceView具有較小的藍色圓圈)交換,我可以看到的是,可見SurfaceView正確地減小的尺寸,如同第二SurfaceView變得可見的,而是比其較小的藍色圓圈可見,我只有大部分第一個SurfaceView的大紅色圓圈穿透,但由第二個SurfaceView的較小尺寸裁剪。

我最終什麼樣的主意打了以下​​兩種方法調用:

((SurfaceView)surfaceView1.findViewById(R.id.circle1)).setVisibility(View.GONE); 

((SurfaceView)view.findViewById(R.id.circle1)).bringToFront(); 

後者,bringToFront(),似乎沒有取得任何成就。但使用調用第一個SurfaceView就像第二個SurfaceView的選項卡已被選中,然後很好地從紅色圓圈切換到藍色圓圈。

我現在想什麼,因此你需要嘗試做的是尋找合適的TabHost API回調方法來覆蓋,這將被稱爲選項卡中選擇(可能使用TabHost.OnTabChangeListenerevery時間和使用,作爲一個地方打電話setVisibility()適當在所有SurfaceView s上控制哪一個出現在頂部。

+0

謝謝Trevor!發佈我的問題後,我還得睡一覺,現在我必須開始工作了!稍後我會仔細研究你的答案。 – Kerry

+0

Trevor:有幾件事要注意。如果你重寫onVisibilityChanged()方法,你會發現當選項卡選擇被改變時,它會被調用。然而,當我寫這篇文章時,我意識到,在我的實際'生產'代碼中(這裏沒有顯示),我不通過超級方法調用...雖然在上面的例子中我沒有覆蓋這種方法。另外,如果您向包含標準Android按鈕的上述示例中添加第三個選項卡,則在Button和SurfaceView之間切換即可,但同樣不能在曲面視圖之間切換。我可能會查看View類的源代碼。 – Kerry

+0

另外我也嘗試調用setVisibility()方法,但遇到了一些問題,但我可能再次重新調查ethis方法。 – Kerry