2015-12-11 14 views
21

Próbuję utworzyć SurfaceView, który można powiększyć i przeciągnąć. Implementuje strumień obrazów HTTP, który bezpośrednio rysuje na kanwie. Próbowałem tego kodu i to trochę działa ... ale daje mi problemy w granicach. Nie mam pojęcia dlaczego. Jakaś pomoc?Funkcja powiększania i przeciągania w SurfaceView

Pełny strumień:

full stream image

powiększonego obrazu:

zoomed image

W drugim obrazie można zobaczyć wiele zielone linie, które nie musi tam być.

Jest to klasa, która obsługuje ten strumień:

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

Kod do dodawania ramek do powierzchni jest następujący:

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

Odpowiedz

1

Kod zostanie zaksięgowana jest niekompletny, więc jej trudno powiedz, czym jest problem. Zrzuciłem kod do szybkiego projektu demonstracyjnego i nie widziałem żadnych problemów z granicami.

Wystarczy spojrzeć na zrzuty ekranu: czy istnieje szansa, że ​​twoje dane obrazu będą w jakiś sposób zawijane? Drugi zrzut ekranu wygląda tak, jakby dolna ramka była rysowana u góry obrazu. Ponownie trudno powiedzieć bez powtarzalnego kodu.

może próbować malowanie tła przed przerysowywania bitmapę

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

Dodałem kod do dodawania obrazów. Właściwie byłoby o wiele lepiej, gdybyśmy korzystali z strumienia wskazującego na zasoby obrazu HTTP. Ale teraz za każdym razem dowładkuję mapę bitową (nie mam pojęcia, jak to zmienić). – Filnik

+0

Czy oczyszczasz tło za każdym razem, gdy rysujesz? (Zaktualizowana odpowiedź) – ayvazj

+0

czyszczenie tła działa! Jedyny problem polega na tym, że kiedy używam dotyku, aby przesunąć zoom, nie jest on ograniczony do granic obrazu. Pracuję nad tym. Chociaż efekt powiększenia działa teraz :) dzięki. Wkrótce opublikuję pełne rozwiązanie – Filnik

Powiązane problemy