2015-12-11 74 views
21

我在創建一個可以縮放和拖動的SurfaceView。它實現了一個HTTP圖像流,直接繪製到畫布上在SurfaceView中縮放和拖動功能

我試過下面的代碼,它有點工作......但它給我在邊界的問題。不知道爲什麼。任何幫助?

全碼流:

full stream image

縮放圖像:

zoomed image

在第二圖像,你可以看到多個綠線並不需要在那裏。

這是處理此流的類:

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.Rect; 
import android.graphics.RectF; 
import android.graphics.drawable.BitmapDrawable; 
import android.graphics.drawable.Drawable; 
import android.util.AttributeSet; 
import android.view.Display; 
import android.view.MotionEvent; 
import android.view.ScaleGestureDetector; 
import android.view.SurfaceView; 
import android.view.WindowManager; 

/** 
* Created by fil on 07/12/15. 
*/ 
public class ZoomSurfaceView extends SurfaceView { 
    //These two constants specify the minimum and maximum zoom 
    private static float MIN_ZOOM = 1f; 
    private static float MAX_ZOOM = 5f; 

    private float scaleFactor = 1.f; 
    private ScaleGestureDetector detector; 

    //These constants specify the mode that we're in 
    private static int NONE = 0; 
    private static int DRAG = 1; 
    private static int ZOOM = 2; 

    private boolean dragged = false; 
    private float displayWidth; 
    private float displayHeight; 

    private int mode; 

    //These two variables keep track of the X and Y coordinate of the finger when it first 
    //touches the screen 
    private float startX = 0f; 
    private float startY = 0f; 

    //These two variables keep track of the amount we need to translate the canvas along the X 
    //and the Y coordinate 
    private float translateX = 0f; 
    private float translateY = 0f; 

    //These two variables keep track of the amount we translated the X and Y coordinates, the last time we 
    //panned. 
    private float previousTranslateX = 0f; 
    private float previousTranslateY = 0f; 

    private final Paint p = new Paint(); 

    private void init(Context context){ 
     detector = new ScaleGestureDetector(getContext(), new ScaleListener()); 
     WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 
     Display display = wm.getDefaultDisplay(); 

     displayWidth = display.getWidth(); 
     displayHeight = display.getHeight(); 
    } 

    public ZoomSurfaceView(Context context) { 
     super(context); 
     init(context); 
    } 

    public ZoomSurfaceView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(context); 
    } 

    public ZoomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     init(context); 
    } 

    public ZoomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 
     init(context); 
    } 

    public void resetZoom() { 

    } 

    public void drawBitmap(Canvas canvas, Bitmap b, Rect rect){ 

     canvas.save(); 

     //If translateX times -1 is lesser than zero, letfs set it to zero. This takes care of the left bound 
     if((translateX * -1) > (scaleFactor - 1) * displayWidth) 
     { 
      translateX = (1 - scaleFactor) * displayWidth; 
     } 

     if(translateY * -1 > (scaleFactor - 1) * displayHeight) 
     { 
      translateY = (1 - scaleFactor) * displayHeight; 
     } 

     //We need to divide by the scale factor here, otherwise we end up with excessive panning based on our zoom level 
     //because the translation amount also gets scaled according to how much we've zoomed into the canvas. 
     canvas.translate(translateX/scaleFactor, translateY/scaleFactor); 

     //We're going to scale the X and Y coordinates by the same amount 
     canvas.scale(scaleFactor, scaleFactor); 

     canvas.drawBitmap(b, null, rect, p); 

     /* The rest of your canvas-drawing code */ 
     canvas.restore(); 
    } 

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener 
    { 
     @Override 
     public boolean onScale(ScaleGestureDetector detector) 
     { 
      scaleFactor *= detector.getScaleFactor(); 
      scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM)); 
      return true; 
     } 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) 
    { 
     switch (event.getAction() & MotionEvent.ACTION_MASK) 
     { 
      case MotionEvent.ACTION_DOWN: 
       mode = DRAG; 

       //We assign the current X and Y coordinate of the finger to startX and startY minus the previously translated 
       //amount for each coordinates This works even when we are translating the first time because the initial 
       //values for these two variables is zero. 
       startX = event.getX() - previousTranslateX; 
       startY = event.getY() - previousTranslateY; 
       break; 

      case MotionEvent.ACTION_MOVE: 
       translateX = event.getX() - startX; 
       translateY = event.getY() - startY; 

       //We cannot use startX and startY directly because we have adjusted their values using the previous translation values. 
       //This is why we need to add those values to startX and startY so that we can get the actual coordinates of the finger. 
       double distance = Math.sqrt(Math.pow(event.getX() - (startX + previousTranslateX), 2) + 
         Math.pow(event.getY() - (startY + previousTranslateY), 2)); 

       if(distance > 0) 
       { 
        dragged = true; 
        distance *= scaleFactor; 
       } 
       break; 

      case MotionEvent.ACTION_POINTER_DOWN: 
       break; 

      case MotionEvent.ACTION_UP: 
       mode = NONE; 
       dragged = false; 

       //All fingers went up, so letfs save the value of translateX and translateY into previousTranslateX and 
       //previousTranslate 
       previousTranslateX = translateX; 
       previousTranslateY = translateY; 
       break; 

      case MotionEvent.ACTION_POINTER_UP: 
       mode = DRAG; 

       //This is not strictly necessary; we save the value of translateX and translateY into previousTranslateX 
       //and previousTranslateY when the second finger goes up 
       previousTranslateX = translateX; 
       previousTranslateY = translateY; 
       break; 
     } 

     detector.onTouchEvent(event); 

     //We redraw the canvas only in the following cases: 
     // 
     // o The mode is ZOOM 
     // OR 
     // o The mode is DRAG and the scale factor is not equal to 1 (meaning we have zoomed) and dragged is 
     // set to true (meaning the finger has actually moved) 
     if ((mode == DRAG && scaleFactor != 1f && dragged) || mode == ZOOM) 
     { 
      invalidate(); 
     } 

     return true; 
    } 
} 

添加幀到表面的代碼如下:

if (!b.isRecycled()){ 
    try { 
     Rect rect = new Rect(0, 0, frame.getWidth(), frame.getHeight()); 
     Canvas canvas = frame.getHolder().lockCanvas(); 
     synchronized (frame.getHolder()) { 
      if (!b.isRecycled()) { 
       frame.drawBitmap(canvas, b, rect); 
       b.recycle(); 
      } 
     } 
     frame.getHolder().unlockCanvasAndPost(canvas); 
    } catch (java.lang.RuntimeException exc){ 
     Dbg.d("ERROR", exc); 
    } 
    lastBitmap = b; 
} 

回答

1

您發佈的代碼是完全,因此其難度說出什麼問題。我沒有將代碼放入快速演示項目中,但沒有看到任何邊界問題。

只是看截圖:你的圖像數據以某種方式包裝的任何機會?第二張截圖看起來像是在圖像頂部繪製底部邊框。如果沒有可重複的代碼,再說一遍也很難。

可以嘗試重繪我添加的代碼添加圖像的位圖

canvas.drawRect(rect, backgroundPaint); 
frame.drawBitmap(canvas, b, rect); 
+0

之前重繪背景。實際上,使用指向HTTP圖像資源的流會好很多..但是現在我只是每次都下載位圖(不知道如何改變它) – Filnik

+0

您是否每次繪製都清除背景? (更新回答) – ayvazj

+0

清除背景確實有用!唯一的問題是,當我使用觸摸移動縮放時,不僅限於圖像的邊界。在它上面工作。雖然縮放效果正在工作:)謝謝。我會很快發佈完整的解決方案 – Filnik