Android Surface更改了不正确的宽度/高度值

Android Surface更改了不正确的宽度/高度值,android,rotation,Android,Rotation,我有一个在表面上绘制的位图,每次旋转设备时都需要调整其大小。由于使用了软按钮,我使用此代码获取当前尺寸,它似乎工作正常: public void getCanvasXY(){ int currentapiVersion = android.os.Build.VERSION.SDK_INT; if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2){ // HoneyComb

我有一个在表面上绘制的位图,每次旋转设备时都需要调整其大小。由于使用了软按钮,我使用此代码获取当前尺寸,它似乎工作正常:

public void getCanvasXY(){
    int currentapiVersion = android.os.Build.VERSION.SDK_INT;
    if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2){
         // HoneyComb 3.2 and up
         DisplayMetrics metrics = new DisplayMetrics();
         ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
         Global.CanvasX = metrics.widthPixels;
         Global.CanvasY = metrics.heightPixels;
    } else{
         // before HoneyComb
         Global.CanvasX = getWidth();
         Global.CanvasY = getHeight();
    }
}
我认为重新计算尺寸和创建位图的最佳位置是surfaceChanged

@Override
    public void surfaceChanged(SurfaceHolder holder1, int format, int width, int height) {
                getCanvasXY();
                LoadBMP();
    }
我看到这被调用了不止一次,当设备旋转时,我得到了CanvasX和CanvasY的不同值。上一次叫做works ok,但我看到onDraw是如何绘制位图和精灵的,它的大小调整得不好,最后是ok。这是一个丑陋的效果。 如何解决这个问题?
谢谢

这里我假设您指的是SurfaceView,您正在使用背景线程绘制曲面,并且正在使用SurfaceHolder.CallBack。这不是一个完整的答案,然而,这个问题也困扰了我一段时间。在我深夜的故障排除中,我设法找到了一个可能比你的更优雅的解决方法。结果是,在surfacechanged设置为其最后状态之前,不会绘制任何内容,因此用户不知道发生了什么

在“曲面更改”中,您会注意到高度或宽度没有更改为正确的值,换句话说,绘制到的结果曲面的格式不正确。您需要的是一个高度和宽度的参考值,您可以在主要活动中设置ContentView之前放置以下代码:

WindowManager w = getWindowManager();
   Display d = w.getDefaultDisplay();
   int Meausredwidth = d.getWidth();
   int Measuredheight = d.getHeight(); 
现在,根据测量的高度和宽度,计算出分配给surfaceView的值,并将这些值作为全局变量传递给surfaceView。并确保在主活动的OnConfiguration Changed中调用上述代码,以便每次重新计算这些值。现在,在您的SurfaceView上,它应该以某种方式实现SurfaceHolder.Callback,将您的surfacechanged更改为如下所示:

@Override
public void surfaceChanged(SurfaceHolder mholder, int format, int width,
        int height) {

    if (width != mWidth) {
        MalFormed = true;
        thread.setRunning(false);
        count++;

    } else if (width == mWidth) {

        if (MalFormed) {
            MalFormed = false;

            Log.d("ROTATE", "ReDraw");

            thread = new DrawingThread(this, holder, mHandler);
            thread.setRunning(true);
            thread.start();

        }

    }

}
其中mWidth是所需的宽度。在此,您可能需要根据具体问题更改if语句。在你的surfaceview中,MalFormed是一个全局布尔值

现在重要的是要记住,如果发生更改,则在创建SurfaceChanged之前调用SurfaceChanged,这意味着我们可以轻松修改尝试与线程交互的任何代码,以适应上述更改

因此,无论您在任何其他地方尝试加入或启动背景绘制线程,都必须首先检查曲面是否存在格式错误。例如

if (thread.getState() == State.TERMINATED){

            if(!MalFormed){
               holder.removeCallback(this);
               holder = getHolder();
               holder.addCallback(this);


               thread = new DrawingThread(this, holder,mHandler);
               thread.setRunning(true);

               thread.start();
            }



        }else{
            if(!MalFormed){
                thread.setRunning(true);

                try {
                    thread.join();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }


        }

希望我在某个大概的地方。祝您一切顺利。

这里我假设您指的是SurfaceView,在这里您使用背景线程绘制曲面,而您使用的是SurfaceHolder.CallBack。这不是一个完整的答案,然而,这个问题也困扰了我一段时间。在我深夜的故障排除中,我设法找到了一个可能比你的更优雅的解决方法。结果是,在surfacechanged设置为其最后状态之前,不会绘制任何内容,因此用户不知道发生了什么

在“曲面更改”中,您会注意到高度或宽度没有更改为正确的值,换句话说,绘制到的结果曲面的格式不正确。您需要的是一个高度和宽度的参考值,您可以在主要活动中设置ContentView之前放置以下代码:

WindowManager w = getWindowManager();
   Display d = w.getDefaultDisplay();
   int Meausredwidth = d.getWidth();
   int Measuredheight = d.getHeight(); 
现在,根据测量的高度和宽度,计算出分配给surfaceView的值,并将这些值作为全局变量传递给surfaceView。并确保在主活动的OnConfiguration Changed中调用上述代码,以便每次重新计算这些值。现在,在您的SurfaceView上,它应该以某种方式实现SurfaceHolder.Callback,将您的surfacechanged更改为如下所示:

@Override
public void surfaceChanged(SurfaceHolder mholder, int format, int width,
        int height) {

    if (width != mWidth) {
        MalFormed = true;
        thread.setRunning(false);
        count++;

    } else if (width == mWidth) {

        if (MalFormed) {
            MalFormed = false;

            Log.d("ROTATE", "ReDraw");

            thread = new DrawingThread(this, holder, mHandler);
            thread.setRunning(true);
            thread.start();

        }

    }

}
其中mWidth是所需的宽度。在此,您可能需要根据具体问题更改if语句。在你的surfaceview中,MalFormed是一个全局布尔值

现在重要的是要记住,如果发生更改,则在创建SurfaceChanged之前调用SurfaceChanged,这意味着我们可以轻松修改尝试与线程交互的任何代码,以适应上述更改

因此,无论您在任何其他地方尝试加入或启动背景绘制线程,都必须首先检查曲面是否存在格式错误。例如

if (thread.getState() == State.TERMINATED){

            if(!MalFormed){
               holder.removeCallback(this);
               holder = getHolder();
               holder.addCallback(this);


               thread = new DrawingThread(this, holder,mHandler);
               thread.setRunning(true);

               thread.start();
            }



        }else{
            if(!MalFormed){
                thread.setRunning(true);

                try {
                    thread.join();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }


        }

希望我在某个大概的地方。祝您一切顺利。

请将heigth拼写为height,以便此问题能够正确索引。请将heigth拼写为height,以便此问题能够正确索引。谢谢@digipd。我尝试在开始时检查尺寸,但我的800x480像素平板电脑有软按钮,当我从活动中获取尺寸时,它返回800x480。但问题是760x480真的很有用。我使用DisplayMetrics获得的值。临时解决方案:等待一秒钟,直到旋转完成,以确定正确的尺寸。足以确保​​不要波动太大。对于我的应用程序来说已经足够了,艾尔
虽然我知道这不是最优雅的解决方案。是的,这与我的解决方法相似。我只是等到尺寸匹配。希望这个帖子也能帮助其他人:谢谢@digipd。我尝试在开始时检查尺寸,但我的800x480像素平板电脑有软按钮,当我从活动中获取尺寸时,它返回800x480。但问题是760x480真的很有用。我使用DisplayMetrics获得的值。临时解决方案:等待一秒钟,直到旋转完成,以确定正确的尺寸。足以确保​​不要波动太大。对于我的应用来说已经足够了,尽管我知道这不是最优雅的解决方案。是的,这与我的解决方案类似。我只是等到尺寸匹配。希望此帖子也能帮助其他人: