2015-03-30 5 views
2

Я использую поверхностный вид, чтобы показать графику, проблема в том, что есть мерцающий эффект, когда я перемещаю фигуру на экране, я понимаю, что это связано с двойной проблемой буферизации, хотя Я прошел через много сообщений, я не могу решить проблему, пожалуйста, взгляните на мой код и помогите мне исправить это.Мерцание при использовании поверхностного вида

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 
     } 
} 

ответ

2

Если вы звоните lockCanvas(), вы должны опираться на каждый пиксель в грязном прямоугольнике. Поскольку вы вызываете его без грязного прямоугольника, это означает обновление каждого пикселя на холсте.

Я считаю, что проблема с вашим кодом в том, что когда mTouched является false, вы вообще ничего не рисуете. Поскольку Surface является двойным или тройным буфером, вы повторно показываете содержимое предыдущего кадра, что вызовет эффект вибрации.

Я думаю, что все, что вам нужно сделать, это переместить тест на mTouched перед вызовом lockCanvas(), поэтому вы не переворачиваете буферы, если не собираетесь ничего рисовать.

Возможно, вы захотите просмотреть SurfaceView lifecycle appendix в документе графической архитектуры, если вы его раньше не видели, поскольку управление потоками иногда вызывает неожиданности.

+0

Спасибо за внимание, я исправился, все, что мне нужно было сделать, это написать еще что-нибудь для if (mTouched) { } и всех чертежей. –

+0

Не могли бы вы также взглянуть на этот вопрос: - http://stackoverflow.com/questions/29297931/custom-views-inside-canvas-android –

-1

мерцание, как правило, странная проблема, так что это мое лучшее предположение о том, как решить в вашем конкретном случае.

Я могу видеть из вашего кода, вы объявляете серию различных команд, которые должны быть применены к холсту, которые рисуются по одному за раз на холсте, в порядке кода, в тот момент, когда ваш код lockCanvas и сочетание тех элементов, которые, я считаю, являются причиной вашего мерцания.

Потому что:

  • те черпает не выполняются во время системы ВСИНХ (потому что SurfaceViews)
  • это делается по одному в последовательности (которая занимает много времени и делает мерцание заметно).

Я могу думать о двух решений для этого:

  1. Я вижу, вы только позвонив drawColor и drawRect на ваш взгляд. Кроме того, вы не выполняете много времени на нем. Поэтому я действительно не вижу причины для использования SurfaceView. Рефакторинг класса к нормальному extends View и выполнять их утягивающим onDraw и вызвать invalidate() всякий раз, когда необходимо заново рисовать (я считаю, что это будет внутри сенсорными события)

  2. Если есть некоторый код, который вы опускаете для краткости, что на самом деле делает SurfaceView действительно необходимо, вы можете выделить временный холст с растровым изображением, используя тот же размер холста экрана. Сделайте весь рисунок на этом временном холсте и используйте только вызов drawBitmap на экранном экране. Ниже приведен небольшой пример кода.

.

// init your objects inside the `surfaceCreated` callback 
Bitmap tempBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
Canvas tempCanvas = new Canvas(tempBitmap); 


// then on your thread. 
while(mRunning){ 
    tempCanvas. // ... do all your drawing operations here 
    Canvas canvas = mSurfaceHolder.lockCanvas(); 
    canvas.drawBitmap(tempBitmap, 0, 0, null); 
    mSurfaceHolder.unlockCanvasAndPost(canvas); 
} 

помнить, что это только пример кода, а не полное решение, вы должны сделать все нормальные проверки на холст действует и т.д.

+1

SurfaceViews являются двойными или тройными буферами. Рисунок, который происходит между 'lockCanvas()' и 'unlockCanvas()', происходит на экране и не помещается до разблокировки, поэтому рисование на временном холсте просто добавляет дополнительный уровень буферизации без эффекта. – fadden

+0

не стесняйтесь дать правильный ответ. – Budius

Смежные вопросы