gpt4 book ai didi

android - 无法显示我的自定义 SurfaceView 的 2 个实例

转载 作者:塔克拉玛干 更新时间:2023-11-02 21:01:32 26 4
gpt4 key购买 nike

我已经创建了自己的自定义 SurfaceView,它自己可以正常工作,但是当我尝试将两个放在 TabWidget 中的单独选项卡上时无论选择哪个选项卡,都只会显示一个,并且始终是应用程序启动时最先绘制的 SurfaceView。

为了说明问题,我创建了可以编译以显示问题的示例代码。

下面的 SurfaceView,称为 SurfaceViewCircle,只是创建一个位图,默认绘制一个蓝色圆圈,然后显示它。有一个公共(public)方法 changeColour(),它会改变位图中圆圈的颜色。

其次,我创建了一个 XML 布局,它只包含一个 SurfaceViewCircle 实例。

在 Activity 类中,我创建了一个 TabWidget 和主机等。然后我将上面的 XML 膨胀两次,但在一个实例中我将 SurfaceViewCircle 的颜色更改为红色。应用程序运行后,无论我选择哪个选项卡,都会始终显示红色圆圈,除非在应用程序退出时短暂显示蓝色圆圈。

谁能指出我在使用 SurfaceView 时是否遗漏了一个步骤?

这是 Activity 代码:

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() 都会破坏表面。

最佳答案

我根据您的代码构建了一个测试项目,令人惊讶的是花了将近几个小时来摆弄它。我现在会迅速脱口而出我的发现,因为我应该被解雇了!

首先,您肯定会创建两个选项卡,每个选项卡都有一个单独的自定义 SurfaceView 实例。没关系。

现在,当 Activity 首次启动并显示第一个选项卡时,只有第一个 SurfaceView 被初始化并调用了 surfaceCreated() ,此时它的 Thread 运行。

选择第二个选项卡时,第二个 surfaceView createTabContent()回调供应,然后像第一个一样初始化。从那时起,直到 Activity 被拆除,两者 SurfaceView 都保持在有效的表面状态。在选项卡之间切换永远不会调用 SurfaceView 上的 surfaceDestroyed(),因此也永远不会再次调用 SurfaceCreated()。首次创建后也不会再次调用“onMeasure()”。因此,这告诉我两个 SurfaceView 都保留在整个 View 层次结构中。 SurfaceViews' Thread 都在运行,如果你没有 wait() ,两者都会不断尝试渲染到显存。

如您所知,SurfaceViewView 层次结构中的位置(或者更确切地说,不位于)的方式非常独特。此处似乎发生的情况是,第一个要创建的 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(),似乎没有取得任何成就。但是使用 setVisibility(View.GONE) 调用 first SurfaceView 就像 second SurfaceView 的选项卡已被选中,然后它很好地从红色圆圈切换到蓝色圆圈。

因此,我认为您需要尝试做的是寻找一个合适的 TabHost API 回调方法来重写,每次 选择选项卡时都会调用该回调方法(可能使用TabHost.OnTabChangeListener) 并将其用作在所有 SurfaceView 上适当调用 setVisibility() 的地方,以控制哪个出现在最佳。

关于android - 无法显示我的自定义 SurfaceView 的 2 个实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10506832/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com