2012-02-17 23 views
5

Tengo un SurfaceView personalizado que es administrado por un subproceso de trabajador. Estoy utilizando un código muy similar al código de la siguiente entrada del blog para gestionar el SurfaceView:Cómo sobrescribir una vista personalizada (vista de superficie)

http://android-coding.blogspot.com/2011/05/drawing-on-surfaceview.html

Mi SurfaceView costumbre es desplazable en el sentido de que escucho de eventos de toque, enviarlos a un detector gesto, e implementar onScroll. Realizo un seguimiento de las distancias de desplazamiento en algunas variables miembro (tanto el eje x como el eje y) y traduzco las coordenadas por las cantidades apropiadas al dibujar en el lienzo. También aseguro las distancias de desplazamiento y puedo calcular y almacenar fácilmente cualquier cantidad de sobredesarrollo al sujetar.

Todo esto funciona bien.

El problema es que quiero mostrar los efectos de sobredesarrollo estándar de Android en mi SurfaceView personalizado. Traté de llamar a OvercrollBy manualmente, pero no funcionó y mi mejor estimación es porque estoy dibujando la vista desde un hilo de trabajo, lo que significa que nunca se llama a la vista onDraw.

me encontré con el siguiente post StackOverflow sobre la personalización de los efectos Permitir desplazamiento:

How can I change the OverScroll color in Android 2.3.1?

Ese artículo no está destinado a SurfaceViews pero probablemente podría adaptar el código. Dicho eso, ¿hay una mejor manera? Quiero mostrar exactamente los mismos efectos de sobrescritura que se muestran en otros lugares. Hacer copias de los sobrescroll drawables y tratar de duplicar la lógica de sobrescritura parece ... feo.

Respuesta

0

Bueno, tengo exactamente el mismo problema.

Miré la implementación de la vista de Android, y dentro de 'onOverScrolled' solo está el comentario "Intencionalmente vacío".

Al observar la implementación de ListView, puedo ver que lo han implementado manualmente al obtener los comwandibles 'com.android.internal.R.styleable.ListView_overScrollHeader' y 'com.android.internal.R.styleable.ListView_overScrollFooter 'que no se puede usar desde afuera. Lamentablemente, no pude encontrar esos recursos en las fuentes.

ya que parece que tendremos que hacer de forma manual Permitir desplazamiento ...

4

Bueno, me las arreglé para armar un ejemplo sencillo de Permitir desplazamiento en vista simple mediante el uso de OverScroller:

package net.project.experimental; 

import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.PointF; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.VelocityTracker; 
import android.view.View; 
import android.view.ViewConfiguration; 
import android.widget.OverScroller; 

public class WorksheetView extends View 
{ 
    protected static final int OVERSCROLL_DISTANCE = 10; 
    protected static final int INVALID_POINTER_ID = -1; 

    private int     fWorksheetWidth  = 2000; 
    private int     fWorksheetHeight = 2000; 

    private OverScroller  fScroller; 
    private VelocityTracker  fVelocityTracker = null; 
    private int     fMinimumVelocity; 

    // The ‘active pointer’ is the one currently moving our object. 
    private int     fTranslatePointerId = INVALID_POINTER_ID; 
    private PointF    fTranslateLastTouch = new PointF(); 

    private boolean    fInteracting  = false; 

    public WorksheetView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
     this.initView(context, attrs); 
    } 

    public WorksheetView(Context context, AttributeSet attrs, int defStyle) 
    { 
     super(context, attrs, defStyle); 
     this.initView(context, attrs); 
    } 

    protected void initView(Context context, AttributeSet attrs) 
    { 
     fScroller = new OverScroller(this.getContext()); 

     this.setOverScrollMode(OVER_SCROLL_ALWAYS); 

     final ViewConfiguration configuration = ViewConfiguration.get(getContext()); 
     //fTouchSlop = configuration.getScaledTouchSlop(); 
     fMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) 
    { 
     if (fVelocityTracker == null) 
     { 
      fVelocityTracker = VelocityTracker.obtain(); 
     } 
     fVelocityTracker.addMovement(event); 

     final int action = event.getAction(); 
     switch (action & MotionEvent.ACTION_MASK) 
     { 
      case MotionEvent.ACTION_DOWN: 
      { 
       if (!fScroller.isFinished()) 
        fScroller.abortAnimation(); 

       final float x = event.getX(); 
       final float y = event.getY(); 

       fTranslateLastTouch.set(x, y); 
       fTranslatePointerId = event.getPointerId(0); 
       this.startInteracting(); 
       break; 
      } 

      case MotionEvent.ACTION_MOVE: 
      { 
       final int pointerIndexTranslate = event.findPointerIndex(fTranslatePointerId); 
       if (pointerIndexTranslate >= 0) 
       { 
        float translateX = event.getX(pointerIndexTranslate); 
        float translateY = event.getY(pointerIndexTranslate); 

        this.overScrollBy(
          (int) (fTranslateLastTouch.x - translateX), 
          (int) (fTranslateLastTouch.y - translateY), 
          this.getScrollX(), 
          this.getScrollY(), 
          fWorksheetWidth - this.getWidth(), 
          fWorksheetHeight - this.getHeight(), 
          OVERSCROLL_DISTANCE, 
          OVERSCROLL_DISTANCE, 
          true); 

        fTranslateLastTouch.set(translateX, translateY); 

        this.invalidate(); 
       } 

       break; 
      } 

      case MotionEvent.ACTION_UP: 
      { 
       final VelocityTracker velocityTracker = fVelocityTracker; 
       velocityTracker.computeCurrentVelocity(1000); 
       //velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); 
       int initialXVelocity = (int) velocityTracker.getXVelocity(); 
       int initialYVelocity = (int) velocityTracker.getYVelocity(); 

       if ((Math.abs(initialXVelocity) + Math.abs(initialYVelocity) > fMinimumVelocity)) 
       { 
        this.fling(-initialXVelocity, -initialYVelocity); 
       } 
       else 
       { 
        if (fScroller.springBack(this.getScrollX(), this.getScrollY(), 0, fWorksheetWidth - this.getWidth(), 0, fWorksheetHeight - this.getHeight())) 
         this.invalidate(); 

        this.stopInteracting(); 
       } 

       if (fVelocityTracker != null) 
       { 
        fVelocityTracker.recycle(); 
        fVelocityTracker = null; 
       } 


       fTranslatePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_POINTER_DOWN: 
      { 
       break; 
      } 

      case MotionEvent.ACTION_POINTER_UP: 
      { 
       final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
       final int pointerId = event.getPointerId(pointerIndex); 
       if (pointerId == fTranslatePointerId) 
       { 
        // This was our active pointer going up. Choose a new 
        // active pointer and adjust accordingly. 
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
        fTranslateLastTouch.set(event.getX(newPointerIndex), event.getY(newPointerIndex)); 
        fTranslatePointerId = event.getPointerId(newPointerIndex); 
       } 

       break; 
      } 

      case MotionEvent.ACTION_CANCEL: 
      { 
       if (fScroller.springBack(this.getScrollX(), this.getScrollY(), 0, fWorksheetWidth - this.getWidth(), 0, fWorksheetHeight - this.getHeight())) 
        this.invalidate(); 

       fTranslatePointerId = INVALID_POINTER_ID; 
       break; 
      } 
     } 

     return true; 
    } 

    private void fling(int velocityX, int velocityY) 
    { 
     int x = this.getScrollX(); 
     int y = this.getScrollY(); 

     this.startInteracting(); 
     //fScroller.setFriction(ViewConfiguration.getScrollFriction()); 
     fScroller.fling(x, y, velocityX, velocityY, 0, fWorksheetWidth - this.getWidth(), 0, fWorksheetHeight - this.getHeight()); 

     this.invalidate(); 
    } 

    private void startInteracting() 
    { 
     fInteracting = true; 
    } 

    private void stopInteracting() 
    { 
     fInteracting = false; 
    } 

    @Override 
    public void computeScroll() 
    { 
     if (fScroller != null && fScroller.computeScrollOffset()) 
     { 
      int oldX = this.getScrollX(); 
      int oldY = this.getScrollY(); 
      int x = fScroller.getCurrX(); 
      int y = fScroller.getCurrY(); 

      if (oldX != x || oldY != y) 
      { 
       this.overScrollBy(
         x - oldX, 
         y - oldY, 
         oldX, 
         oldY, 
         fWorksheetWidth - this.getWidth(), 
         fWorksheetHeight - this.getHeight(), 
         OVERSCROLL_DISTANCE, 
         OVERSCROLL_DISTANCE, 
         false); 
      } 

      if (fScroller.isFinished()) 
       this.stopInteracting(); 

      this.postInvalidate(); 
     } 
    } 

    @Override 
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) 
    { 
     // Treat animating scrolls differently; see #computeScroll() for why. 
     if (!fScroller.isFinished()) 
     { 
      super.scrollTo(scrollX, scrollY); 

      if (clampedX || clampedY) 
      { 
       fScroller.springBack(this.getScrollX(), this.getScrollY(), 0, fWorksheetWidth - this.getWidth(), 0, fWorksheetHeight - this.getHeight()); 
      } 
     } 
     else 
     { 
      super.scrollTo(scrollX, scrollY); 
     } 
     awakenScrollBars(); 
    } 

    @Override 
    protected int computeHorizontalScrollExtent() 
    { 
     return this.getWidth(); 
    } 

    @Override 
    protected int computeHorizontalScrollRange() 
    { 
     return fWorksheetWidth; 
    } 

    @Override 
    protected int computeHorizontalScrollOffset() 
    { 
     return this.getScrollX(); 
    } 

    @Override 
    protected int computeVerticalScrollExtent() 
    { 
     return this.getHeight(); 
    } 

    @Override 
    protected int computeVerticalScrollRange() 
    { 
     return fWorksheetHeight; 
    } 

    @Override 
    protected int computeVerticalScrollOffset() 
    { 
     return this.getScrollY(); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) 
    { 
     canvas.drawColor(Color.BLACK); 

     Paint paint = new Paint(); 

     if (fInteracting) 
      ; 

     paint.setColor(Color.WHITE); 
     canvas.drawRect(0, 0, fWorksheetWidth, fWorksheetHeight, paint); 

     paint.setColor(Color.RED); 
     for (int i = 0; i < 1500; i += 10) 
     { 
      canvas.drawLine(i, 0, i + 100, 500, paint); 
     } 

     canvas.drawRect(fWorksheetWidth - 50, 0, fWorksheetWidth, fWorksheetHeight, paint); 
     canvas.drawRect(0, fWorksheetHeight - 50, fWorksheetWidth, fWorksheetHeight, paint); 
    } 
} 
0

Ok, para responder realmente a la pregunta del sobrecritura del estilo de Android. Puede ir un paso más allá de mi última respuesta (el código) Después de usar OverScroller para implementar el sobrerrevolucionado a través del dibujo, puede restringir el movimiento de la página, por lo que la página no se desbordará. En su lugar, puede dibujar un recurso para el sobrecritura estilo Android, y eso es lo que llama 'manual'.

Vea el ejemplo a continuación, que es adicional al código que publiqué ayer. Ahora, el 'onDraw' no permitirá que la página se sobrescriba visualmente. Luego 'displatchDraw' dibujará un recurso dibujable para representar el sobrecritura estilo Android.

Nota, soy un fanático de la memoria, así que utilizo el mismo recurso para las cuatro esquinas y lo giro manualmente a través de matrices cuando se renderiza en el lienzo.

private void compensateForOverscroll(Canvas canvas) 
    { 
     int x = this.getScrollX(); 
     int y = this.getScrollY(); 

     Matrix matrix = canvas.getMatrix(); 

     int maxX = fWorksheetWidth - this.getWidth(); 
     int maxY = fWorksheetHeight - this.getHeight(); 

     if (x < 0 || x > maxX || y < 0 || y > maxY) 
     { 
      if (x < 0) 
       matrix.postTranslate(x, 0); 
      else if (x > maxX) 
       matrix.postTranslate((x - maxX), 0); 

      if (y < 0) 
       matrix.postTranslate(0, y); 
      else if (y > maxY) 
       matrix.postTranslate(0, (y - maxY)); 

      canvas.setMatrix(matrix); 
     } 
    } 

    @Override 
    protected void dispatchDraw(Canvas canvas) 
    { 
     int width = this.getWidth(); 
     int height = this.getHeight(); 
     int maxX = fWorksheetWidth - width; 
     int maxY = fWorksheetHeight - height; 

     int x = this.getScrollX(); 
     int y = this.getScrollY(); 


     if (x < 0 || x > maxX) 
     { 
      canvas.save(); 
      Matrix canvasMatrix = canvas.getMatrix(); 

      if (x < 0) 
      { 
       fOverScrollDrawable.setBounds(0, x, height, x - x); 
       canvasMatrix.preRotate(-90); 
       canvasMatrix.preTranslate(- y - height, 0); 
      } 
      else if (x > maxX) 
      { 
       fOverScrollDrawable.setBounds(0, maxX, height, x); 
       canvasMatrix.preRotate(90); 
       canvasMatrix.preTranslate(y, - x - fWorksheetWidth); 
      } 

      canvas.setMatrix(canvasMatrix); 
      fOverScrollDrawable.draw(canvas); 

      canvas.restore(); 
     } 

     if (y < 0 || y > maxY) 
     { 
      canvas.save(); 
      Matrix canvasMatrix = canvas.getMatrix(); 

      if (y < 0) 
      { 
       fOverScrollDrawable.setBounds(x, y, x + width, y - y); 
      } 
      else if (y > maxY) 
      { 
       fOverScrollDrawable.setBounds(0, maxY, width, y); 
       canvasMatrix.preRotate(180); 
       canvasMatrix.preTranslate(- x - width, - y - fWorksheetHeight); 
      } 

      canvas.setMatrix(canvasMatrix); 
      fOverScrollDrawable.draw(canvas); 

      canvas.restore(); 
     } 
    } 

    @Override 
    protected void onDraw(Canvas canvas) 
    { 
     canvas.save(); 

     this.compensateForOverscroll(canvas); 

     canvas.drawColor(Color.BLACK);   

     Paint paint = new Paint(); 

     if (fInteracting) 
      ; 

     paint.setColor(Color.WHITE); 
     canvas.drawRect(0, 0, fWorksheetWidth, fWorksheetHeight, paint); 

     paint.setColor(Color.RED); 
     for (int i = 0; i < 1500; i += 10) 
     { 
      canvas.drawLine(i, 0, i + 100, 500, paint); 
     } 

     canvas.drawRect(fWorksheetWidth - 50, 0, fWorksheetWidth, fWorksheetHeight, paint); 
     canvas.drawRect(0, fWorksheetHeight - 50, fWorksheetWidth, fWorksheetHeight, paint); 

     canvas.restore(); 
    } 

El dibujable se inicia así:

Drawable fOverScrollDrawable; 

... 

Resources rsr = context.getResources(); 
fOverScrollDrawable = rsr.getDrawable(R.drawable.overscroll_glow); 

El recurso de imagen para el resplandor Permitir desplazamiento, he tomado dos imágenes en el SDK y se combinan en un único recurso dibujable:

  • \ \ plataformas Android-SDK \ android-11 \ data \ res \ dibujable-IPAP \ overscroll_edge.png
  • \ \ plataformas Android-SDK \ android-11 \ data \ res \ dibujable -hdpi \ overscroll_glow.png
Cuestiones relacionadas