android - 使用表面 View 时闪烁

标签 android android-canvas surfaceview doublebuffered

我正在使用表面 View 来显示一些图形,问题是当我在屏幕中移动图形时会出现闪烁效果,我知道这是由于双缓冲问题,尽管我浏览了很多帖子,我无法解决该问题,请查看我的代码并帮助我解决此问题。

public class CustomSurfaceView  extends SurfaceView implements Runnable{

      Thread mThread             =  null;
      SurfaceHolder mSurfaceHolder;
      volatile boolean mRunning  =  false;
      Bitmap mBitmap;
      boolean mTouched;
      float mTouched_x,mTouched_y;
      Context mContext;
      float mCurrentPosOfRect1x1,mCurrentPosOfRect1y1,mCurrentPosOfRect1x2,mCurrentPosOfRect1y2;
      float mCurrentPosOfRect2x1,mCurrentPosOfRect2y1,mCurrentPosOfRect2x2,mCurrentPosOfRect2y2;

      private Paint mPaint   =  new Paint(Paint.ANTI_ALIAS_FLAG);
      boolean isInitialized  =  false;

      /**
       * Constructor..
       */
      public CustomSurfaceView(Context context) {
          super(context);
          mSurfaceHolder = getHolder();
          mBitmap   =   BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
          mContext  =   context;

          mCurrentPosOfRect1x1  =   100;
          mCurrentPosOfRect1y1  =   100;
          mCurrentPosOfRect1x2  =   300;
          mCurrentPosOfRect1y2  =   300;

          mCurrentPosOfRect2x1  =   300;
          mCurrentPosOfRect2y1  =   300;
          mCurrentPosOfRect2x2  =   500;
          mCurrentPosOfRect2y2  =   500;
      }

      public void onResumeMySurfaceView(){
          mRunning  =   true;
          mThread       =   new Thread(this);
          mThread.start();
      }

      public void onPauseMySurfaceView(){
          boolean retry = true;
          mRunning = false;
          while(retry){
              try {
                  mThread.join();
                  retry = false;
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      }

      @Override
      public void run() {
       while(mRunning){
           if(mSurfaceHolder.getSurface().isValid()){
               Canvas canvas = mSurfaceHolder.lockCanvas();
               //... actual drawing on canvas

               mPaint.setStyle(Paint.Style.STROKE);

               if(mTouched){
                      canvas.drawColor(Color.BLACK); 

                      mPaint.setColor(Color.BLACK);
                      mPaint.setStrokeWidth(3);
                      mPaint.setStrokeWidth(0);
                      mPaint.setColor(Color.CYAN);
                      //Left,top 
                      //Right bottom.
                      if(!isInitialized){
                          canvas.drawRect(mCurrentPosOfRect1x1, mCurrentPosOfRect1y1,mCurrentPosOfRect1x2, mCurrentPosOfRect1y2,mPaint);
                          isInitialized =   true;

                      }

                      mPaint.setColor(Color.BLACK);
                      mPaint.setStrokeWidth(3);
                      mPaint.setStrokeWidth(0);
                      mPaint.setColor(Color.BLUE);
                      //Left,top 
                      //Right bottom.
                      if(!isInitialized){
                          canvas.drawRect(mCurrentPosOfRect2x1, mCurrentPosOfRect2y1,mCurrentPosOfRect2x2, mCurrentPosOfRect2y2,mPaint);
                          isInitialized = true;

                      }

                      if(isInitialized){
                          //Check whether the touch points are inside the rectangle & then move...
                          if((mTouched_x>mCurrentPosOfRect1x1) && (mTouched_x<mCurrentPosOfRect1x2) && (mTouched_y>mCurrentPosOfRect1y1) && (mTouched_y<mCurrentPosOfRect1y2)){
                              mCurrentPosOfRect1x1  =   mTouched_x-100;
                              mCurrentPosOfRect1x2  =   mTouched_x+100;
                              mCurrentPosOfRect1y1  =   mTouched_y-100;
                              mCurrentPosOfRect1y2  =   mTouched_y+100;
                          }else if((mTouched_x>mCurrentPosOfRect2x1) && (mTouched_x<mCurrentPosOfRect2x2) && (mTouched_y>mCurrentPosOfRect2y1) && (mTouched_y<mCurrentPosOfRect2y2)){
                              mCurrentPosOfRect2x1  =   mTouched_x-100;
                              mCurrentPosOfRect2x2  =   mTouched_x+100;
                              mCurrentPosOfRect2y1  =   mTouched_y-100;
                              mCurrentPosOfRect2y2  =   mTouched_y+100;

                          }
                      }

                      canvas.drawRect(mCurrentPosOfRect1x1, mCurrentPosOfRect1y1,mCurrentPosOfRect1x2, mCurrentPosOfRect1y2, mPaint);
                      mPaint.setColor(Color.RED);
                      canvas.drawRect(mCurrentPosOfRect2x1,  mCurrentPosOfRect2y1,mCurrentPosOfRect2x2, mCurrentPosOfRect2y2, mPaint);
                      mPaint.setColor(Color.BLUE);


                      Paint paint = new Paint() {
                            {
                                setStyle(Paint.Style.STROKE);
                                setStrokeCap(Paint.Cap.ROUND);
                                setStrokeWidth(3.0f);
                                setAntiAlias(true);
                            }
                        };

                        paint.setColor(Color.YELLOW);

                        final Path path = new Path();
                        final float x1 = mCurrentPosOfRect1x1+ 100;
                        final float y1 = mCurrentPosOfRect1y1 + 100;



                        final float x3 = (mCurrentPosOfRect2x1+ 100) ;
                        final float y3 = (mCurrentPosOfRect2y1 + 100);

                        final float x2 = (x1 +200);
                        final float y2 = (y1 -100);

                        final float x4  = (x3-100);
                        final float y4  = (y3+200);

                        path.moveTo(x1, y1);

                        path.cubicTo(x2,y2,x4,y4,x3,y3);
                        canvas.drawPath(path, paint);

                }

               mSurfaceHolder.unlockCanvasAndPost(canvas);
        }

      }

    }
      @Override
       public boolean onTouchEvent(MotionEvent event){

          mTouched_x = event.getX();
           mTouched_y = event.getY();
          int action = event.getAction();
           switch(action){
           case MotionEvent.ACTION_DOWN:
            mTouched = true;
            break;
           case MotionEvent.ACTION_MOVE:
            mTouched = true;
            break;
           case MotionEvent.ACTION_UP:
            mTouched = false;
            break;
           case MotionEvent.ACTION_CANCEL:
            mTouched = false;
            break;
           case MotionEvent.ACTION_OUTSIDE:
            mTouched = false;
            break;
           default:
           }
           return true; //processed
       }
}

最佳答案

如果调用lockCanvas(),则需要在脏矩形中的每个像素上进行绘制。由于您在没有脏矩形的情况下调用它,这意味着更新 Canvas 上的每个像素。

我认为您的代码的问题在于,当 mTouchedfalse 时,您根本没有绘制任何内容。由于 Surface 是双缓冲或三缓冲的,因此您将重新显示前一帧的内容,这将导致振动效果。

我认为您需要做的就是在 lockCanvas() 调用之前移动 mTouched 的测试,这样如果您不这样做,就不会翻转缓冲区会画任何东西。

您可能想查看 SurfaceView lifecycle appendix如果您以前没有见过的话,请参阅图形架构文档,因为线程管理有时会带来惊喜。

关于android - 使用表面 View 时闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29348022/

相关文章:

android - android canvas 上的 Fling 实现

java - 如何在重绘时保存先前绘制到 Canvas 上的对象?

android - Activity 恢复时不会调用 onSurfaceCreated()

android - RUBYMOTION_ANDROID_SDK 不正确

android - 使用 Canvas 将圆圈转换为环形?

android - 从 ndk 写入 Android 显示器

android - 屏幕尺寸计算错误

java - 即使我声明了 Android 权限也不起作用

android - 在 Android 中的导航堆栈顶部启动 Activity

java - Android - setText() 方法正在更改小部件的文本,即使它从未被调用