2012-02-17 21 views
5

Ho un SurfaceView personalizzato che è gestito da un thread di lavoro. Sto usando il codice molto simile al codice nel seguente post sul blog per gestire il SurfaceView:Come sovrascrivere una vista personalizzata (vista surreale)

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

mio SurfaceView personalizzato è scorrevole nel senso che ascolto per gli eventi di tocco, li invia ad un rilevatore di gesto, e implementare onScroll. Tengo traccia delle distanze di scorrimento in alcune variabili membro (sia l'asse x che l'asse y) e traduco tutte le coordinate con gli importi appropriati quando disegno sulla tela. Ho anche bloccato le distanze di scorrimento e posso facilmente calcolare e memorizzare eventuali quantità di overscroll durante il serraggio.

Tutto funziona correttamente.

Il problema è che voglio mostrare gli effetti di overscroll Android standard sul mio SurfaceView personalizzato. Ho provato a chiamare overScrollBy manualmente ma non ha funzionato e la mia ipotesi migliore è perché sto disegnando la vista da un thread di lavoro, il che significa che la vista suDraw non viene mai chiamata.

ho trovato il seguente post StackOverflow sulla personalizzazione degli effetti Overscroll:

How can I change the OverScroll color in Android 2.3.1?

Questo post non è destinato per SurfaceViews ma probabilmente ho potuto adattare il codice. Detto questo, c'è un modo migliore? Voglio mostrare esattamente gli stessi effetti overscroll mostrati altrove. Fare copie dei drawables overscroll e tentare di duplicare la logica del overscroll sembra ... brutto.

risposta

0

Bene, ho esattamente lo stesso problema.

Ho esaminato l'implementazione della vista Android e all'interno di "onOverScrolled" è presente solo il commento "Intenzionalmente vuoto".

Guardando all'implementazione di ListView, posso vedere che l'hanno implementato manualmente ottenendo i drawable 'com.android.internal.R.styleable.ListView_overScrollHeader' e 'com.android.internal.R.styleable.ListView_overScrollFooter 'che non può essere utilizzato dall'esterno. Sfortunatamente, non sono riuscito a trovare quelle risorse nelle fonti.

come sembra che dovremo fare Overscroll manualmente ...

4

Beh, sono riuscito a mettere insieme un semplice esempio di Overscroll in vista semplice utilizzando 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, per rispondere davvero alla domanda di overscroll in stile Android. Puoi fare un passo oltre la mia ultima risposta (il codice) Dopo aver usato OverScroller per implementare il overscrolling attraverso il disegno, puoi limitare il movimento della pagina, quindi la pagina non sovrascriverà. Invece, puoi disegnare una risorsa per lo overscroll in stile Android, e questo è ciò che chiami "manuale".

Vedere l'esempio di seguito, che si aggiunge al codice che ho postato ieri. Ora, "onDraw" non consente alla pagina di sovrascrivere visivamente. Quindi 'displatchDraw' disegna una risorsa estraibile per rappresentare lo overscroll di stile Android.

Nota, sono un maniaco della memoria, quindi utilizzo la stessa risorsa per tutti e quattro gli angoli e lo faccio ruotare manualmente attraverso le matrici durante il rendering sulla tela.

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

Il drawable viene inizializzato così:

Drawable fOverScrollDrawable; 

... 

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

La risorsa immagine per il bagliore Overscroll, ho preso due immagini nel SDK e combinati loro in una singola risorsa drawable:

  • \ android-sdk \ piattaforme \ android-11 \ data \ res \ drawable-hdpi \ overscroll_edge.png
  • \ android-sdk \ piattaforme \ android-11 \ data \ res \ drawable -hdpi \ overscroll_glow.png
Problemi correlati