6

独自のカスタム SurfaceView を作成しましたが、それ自体は正常に動作しますが、TabWidgetの別々のタブに 2 つを配置しようとすると、選択されているタブに関係なく 1 つだけが表示され、常に最初に描画されるのは SurfaceView です。アプリが起動します。

問題を説明するために、問題を表示するためにコンパイルできるサンプル コードを作成しました。

以下の SurfaceViewCircle と呼ばれる SurfaceView は、単純にビットマップを作成し、デフォルトで青い円を描画してから表示します。ビットマップの円の色を変更するパブリック メソッド changeColour() があります。

次に、SurfaceViewCircle のインスタンスを 1 つだけ含む XML レイアウトを作成します。

Activity クラスで、TabWidget とホストなどを作成します。次に、上記の XML を 2 回インフレートしますが、1 つのインスタンスで 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>

また、他の誰かがここで同様の問題を抱えていることにも気付きました。

書式設定が不十分で申し訳ありませんが、コード エディターを使用して大きなコードを引用することはほぼ不可能です。

追加情報

setVisibility()'inを使用してみましたonvisibilityChanged()が、最終的に例外が発生します。

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()たびに表面が破壊されるようです。

4

2 に答える 2

4

私はあなたのコードに基づいてテスト プロジェクトを作成しましたが、驚くべきことに、それをいじるのにほぼ 2 時間かかりました。袋に入れなければならないので、今すぐ調査結果をぼんやりさせます!

まず第一に、2 つのタブを作成していることは間違いありません。各タブには独自の custom のインスタンスがありますSurfaceView。それはいいです。

Activity最初のタブが起動して最初のタブが表示されると、最初のタブのみSurfaceViewが初期化されてsurfaceCreated()呼び出され、その時点で実行されますThread

2 番目のタブが選択されるSurfaceViewと、createTabContent()コールバックが提供する 2 番目のタブが最初のタブと同じように初期化されます。この時点から、 が分解されるまでActivity両方 SurfaceViewの が有効な表面状態のままです。タブ間の切り替えはsurfaceDestroyed()、どちらでも呼び出されないSurfaceViewため、SurfaceCreated()再度呼び出されることもありません。最初の作成後に「onMeasure()」が再び呼び出されることもありません。したがって、これは両方の が階層SurfaceView全体に残っていることを示しています。View両方SurfaceViewsThreadが実行されておりwait()、そこに がなければ、両方とも継続的にビデオ メモリにレンダリングしようとします。

ご存知のように、aは、階層SurfaceView内でどのように配置されているか (というか、配置されていないか) という点で非常にユニークです。Viewここで起こっているように見えるのは、最初SurfaceViewに作成されるのは、タブの選択に関係なく、出力がビデオ メモリに表示されるものです。

私が最初に試みたことの 1 つは、2 番目SurfaceViewの円を 1 番目の円よりも大幅に小さくし、それに比例して内側の円を小さくすることでした。SurfaceView最初のタブ (大きい赤い円で大きく) から 2 番目のタブ (SurfaceView小さい青い円で小さい) に切り替えると、2 番目のタブが表示されているように、表示されているサイズがSurfaceView正しく縮小されていることがわかりましたSurfaceViewが、小さい青ではなく円が表示されているため、最初SurfaceViewの大きな赤い円の大部分が突き抜けていましたが、2 番目の小さいサイズでトリミングされていましたSurfaceView

私が遊んだのは、次の2つのメソッド呼び出しでした。

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

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

後者はbringToFront()、何も達成していないようです。しかし、2 番目のタブが選択されたときに最初の呼び出しを使用すると赤いsetVisibility(View.GONE)円から青い円にうまく切り替わりました。 SurfaceView SurfaceView

したがって、あなたが試してみる必要があると思うのは、タブが選択されたときTabHostに呼び出される適切な API コールバック メソッドを探してevery(おそらく を使用して)、それをすべてのsで適切にTabHost.OnTabChangeListener呼び出す場所として使用して制御することです。 1 つが上に表示されます。setVisibility()SurfaceView

于 2012-05-09T00:11:57.930 に答える
1

SurfaceView でやりたいことは推奨されていないようです:リンク

于 2012-05-13T15:24:15.970 に答える