2012-02-17 31 views
5

Tôi có một SurfaceView tùy chỉnh được quản lý bởi một chuỗi công nhân. Tôi đang sử dụng mã rất giống với mã trong bài viết trên blog sau để quản lý các SurfaceView:Cách ghi đè chế độ xem tùy chỉnh (xem lướt sóng)

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

SurfaceView tùy chỉnh của tôi là cuộn theo nghĩa là tôi nghe cho các sự kiện liên lạc, gửi chúng vào một máy dò cử chỉ, và triển khai onScroll. Tôi theo dõi khoảng cách di chuyển trong một số biến thành viên (cả trục x và trục y) và dịch bất kỳ tọa độ nào bằng số lượng thích hợp khi vẽ lên canvas. Tôi cũng kẹp khoảng cách di chuyển và có thể dễ dàng tính toán và lưu trữ bất kỳ số tiền overscroll khi kẹp.

Tất cả đều hoạt động tốt.

Vấn đề là tôi muốn hiển thị các hiệu ứng overscroll tiêu chuẩn của Android trên SurfaceView tùy chỉnh của mình. Tôi đã cố gắng gọi overScrollBy bằng tay nhưng nó đã không làm việc và đoán tốt nhất của tôi là bởi vì tôi vẽ xem từ một sợi công nhân có nghĩa là onDraw của view không bao giờ được gọi.

Tôi tìm thấy bài stackoverflow sau về tùy chỉnh hiệu ứng thanh cuộn:

How can I change the OverScroll color in Android 2.3.1?

Đó bài không dành cho SurfaceViews nhưng tôi có thể có thể thích ứng với mã. Điều đó nói rằng, có cách nào tốt hơn không? Tôi muốn hiển thị chính xác hiệu ứng ghi đè được hiển thị ở nơi khác. Làm bản sao của các bản vẽ overscroll và cố gắng để lặp lại logic overscroll có vẻ ... xấu xí.

Trả lời

0

Vâng, tôi có cùng một vấn đề chính xác.

Tôi đã xem triển khai chế độ xem android và bên trong 'onOverScrolled' chỉ có nhận xét "Cố ý trống".

Nhìn vào triển khai ListView, tôi có thể thấy rằng họ đã triển khai thực hiện theo cách thủ công bằng cách tải các trình rút gọn 'com.android.internal.R.styleable.ListView_overScrollHeader' và 'com.android.internal.R.styleable.ListView_overScrollFooter 'không thể được sử dụng từ bên ngoài. Thật không may, tôi không thể tìm thấy những tài nguyên đó trong các nguồn.

như có vẻ như chúng tôi sẽ phải làm thanh cuộn bằng tay ...

4

Vâng, tôi quản lý để đặt lại với nhau một ví dụ đơn giản của thanh cuộn trong đơn giản bằng cách sử dụng Xem 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, để thực sự trả lời câu hỏi về ghi đè kiểu Android. Bạn có thể đi xa hơn một bước so với câu trả lời cuối cùng của tôi (mã) Sau khi sử dụng OverScroller để thực hiện ghi đè thông qua bản vẽ, bạn có thể hạn chế chuyển động trang, vì vậy trang sẽ không ghi đè lên. Thay vào đó, bạn có thể vẽ một tài nguyên để ghi đè kiểu Android - và đó là những gì bạn gọi là 'thủ công'.

Xem mẫu bên dưới, ngoài mã tôi đã đăng hôm qua. Bây giờ, 'onDraw' sẽ không cho phép trang overscroll trực quan. Sau đó, 'displatchDraw' sẽ vẽ một tài nguyên có thể vẽ để đại diện cho việc ghi đè kiểu Android.

Lưu ý, tôi là một bộ nhớ quái dị, vì vậy tôi sử dụng cùng một tài nguyên cho tất cả bốn góc và xoay nó theo cách thủ công thông qua ma trận khi hiển thị trên canvas.

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

Các drawable được khởi tạo như thế:

Drawable fOverScrollDrawable; 

... 

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

Nguồn hình ảnh cho ánh sáng thanh cuộn, tôi đã lấy hai hình ảnh trong sdk và kết hợp chúng thành một nguồn tài nguyên có thể vẽ được duy nhất:

  • \ android-sdk \ platforms \ android-11 \ data \ res \ drawable-hdpi \ overscroll_edge.png
  • \ android-sdk \ platforms \ android-11 \ data \ res \ drawable -hdpi \ overscroll_glow.png
Các vấn đề liên quan