2015-08-27 15 views
11

Sto lavorando ad una semplice app di lettura di libri per Android. Ho usato il listview per questo.Come ingrandire l'elemento della lista dal centro del pizzico

Quello che sto facendo è caricare le immagini remote dal server nel mio Listview (utilizzando la libreria Picasso) e sta funzionando bene.

Volevo anche zoomare la funzionalità nel mio Reader, beh, ho usato la classe ZoomListView per raggiungere questo obiettivo.

public class ZoomListView extends ListView { 
private static final int INVALID_POINTER_ID = -1; 
private int mActivePointerId = INVALID_POINTER_ID; 
private ScaleGestureDetector mScaleDetector; 

private float mScaleFactor = 1.f; 
private float maxWidth = 0.0f; 
private float maxHeight = 0.0f; 
private float mLastTouchX; 
private float mLastTouchY; 
private float mPosX; 
private float mPosY; 
private float width; 
private float height; 

public ZoomListView(Context context) { 
    super(context); 
    mScaleDetector = new ScaleGestureDetector(getContext(), 
      new ScaleListener()); 
} 

public ZoomListView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    mScaleDetector = new ScaleGestureDetector(getContext(), 
      new ScaleListener()); 
} 

public ZoomListView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    mScaleDetector = new ScaleGestureDetector(getContext(), 
      new ScaleListener()); 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    width = MeasureSpec.getSize(widthMeasureSpec); 
    height = MeasureSpec.getSize(heightMeasureSpec); 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
} 

@Override 
public boolean onTouchEvent(@NonNull MotionEvent ev) { 
    super.onTouchEvent(ev); 
    final int action = ev.getAction(); 
    mScaleDetector.onTouchEvent(ev); 
    switch (action & MotionEvent.ACTION_MASK) { 
    case MotionEvent.ACTION_DOWN: { 
     final float x = ev.getX(); 
     final float y = ev.getY(); 

     mLastTouchX = x; 
     mLastTouchY = y; 

     mActivePointerId = ev.getPointerId(0); 
     break; 
    } 

    case MotionEvent.ACTION_MOVE: { 
     final int pointerIndex = ev.findPointerIndex(mActivePointerId); 
     final float x = ev.getX(pointerIndex); 
     final float y = ev.getY(pointerIndex); 
     final float dx = x - mLastTouchX; 
     final float dy = y - mLastTouchY; 

     mPosX += dx; 
     mPosY += dy; 

     if (mPosX > 0.0f) 
      mPosX = 0.0f; 
     else if (mPosX < maxWidth) 
      mPosX = maxWidth; 

     if (mPosY > 0.0f) 
      mPosY = 0.0f; 
     else if (mPosY < maxHeight) 
      mPosY = maxHeight; 

     mLastTouchX = x; 
     mLastTouchY = y; 

     invalidate(); 
     break; 
    } 

    case MotionEvent.ACTION_UP: { 
     mActivePointerId = INVALID_POINTER_ID; 
     break; 
    } 

    case MotionEvent.ACTION_CANCEL: { 
     mActivePointerId = INVALID_POINTER_ID; 
     break; 
    } 

    case MotionEvent.ACTION_POINTER_UP: { 
     final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
     final int pointerId = ev.getPointerId(pointerIndex); 
     if (pointerId == mActivePointerId) { 
      final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
      mLastTouchX = ev.getX(newPointerIndex); 
      mLastTouchY = ev.getY(newPointerIndex); 
      mActivePointerId = ev.getPointerId(newPointerIndex); 
     } 
     break; 
    } 
    } 

    return true; 
} 

@Override 
public void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    canvas.save(Canvas.MATRIX_SAVE_FLAG); 
    canvas.translate(mPosX, mPosY); 
    canvas.scale(mScaleFactor, mScaleFactor); 
    canvas.restore(); 
} 

@Override 
protected void dispatchDraw(@NonNull Canvas canvas) { 
    canvas.save(Canvas.MATRIX_SAVE_FLAG); 
    if (mScaleFactor == 1.0f) { 
     mPosX = 0.0f; 
     mPosY = 0.0f; 
    } 
    canvas.translate(mPosX, mPosY); 
    canvas.scale(mScaleFactor, mScaleFactor); 
    super.dispatchDraw(canvas); 
    canvas.restore(); 
    invalidate(); 
} 

private class ScaleListener extends 
     ScaleGestureDetector.SimpleOnScaleGestureListener { 
    @Override 
    public boolean onScale(ScaleGestureDetector detector) { 
     mScaleFactor *= detector.getScaleFactor(); 
     mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 4.0f)); 
     maxWidth = width - (width * mScaleFactor); 
     maxHeight = height - (height * mScaleFactor); 
     invalidate(); 
     return true; 
    } 
} 

} 

Ecco il mio layout XML (ho mostrato solo lo ZoomListView):

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" > 

<RelativeLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="#ffffff" 
    android:gravity="top" 
    android:visibility="visible" > 

    <libraries.ZoomListView 
     android:id="@+id/lstv_book_reader" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_marginTop="0dp" 
     android:paddingTop="0dp" > 
    </libraries.ZoomListView> 
</RelativeLayout> 
</RelativeLayout> 

Questo mi ha permesso di ingrandire il mio lettore di libri. Il mio book reader sembra

enter image description here

Problema: sto ottenendo problema nel mio pinch zoom. Quando pizzico lo zoom inizia dalla parte superiore sinistra della listview.

Lasciatemi descrivere con le immagini

1 pizzico

enter image description here

2 Corrente di uscita

Nota: Questo ingrandimento di ListView dall'angolo topleft

enter image description here

3 Uscita consigliata

enter image description here

+0

Segui questo tutorial http://android-er.blogspot.com/2011/11/implement-pinch-zoom-in-ontouchlistener.html –

+0

Puoi giustificare queste affermazioni: 'if (mPosX> 0.0f) mPosX = 0.0f; altrimenti se (mPosX maxWidth) mPosX = maxWidth; '. Ho preoccupazioni simili riguardo alle condizioni per il controllo dei confini di 'mPosY'. – Vikram

+0

@Vikram Ho cambiato come suggerito sopra, ma il mio problema è ancora lì. –

risposta

1

significa che si desidera modificare la proprietà di default che è zoom (ridimensionamento) parte sempre da (0,0) che è:

_____________ 
|0,0 x  | 
|y   | 
|   | Suppose this the device screen 
|   | 
|   | 
______________ 

E si desidera ridimensionarlo da:

_____________ 
|   | 
|   | 
|   | Suppose this the device screen 
|   y | 
|  X 0,0| 
______________ 

Quindi, per raggiungere questo obiettivo: cambiamento che il codice da questa:

canvas.scale(mScaleFactor, mScaleFactor); 

a questo:

canvas.scale(mScaleFactor, -mScaleFactor); 

vedi anche la questione che riguarda la tua domanda: Android: Drawing to canvas, way to make bottom left correspond to (0,0)? ho ti ho hai ottenuto la tua soluzione da questo esempio e dallo snippet di codice.

+0

per favore leggi di nuovo il quiz. Non voglio questo come suggerito la tua risposta, piuttosto ho bisogno di ingrandire l'elemento della lista dal centro di pizzico ma è sempre lo zoom in alto a sinistra dell'articolo –

+0

@ All: come punto di zoom lo tocco – abcd1234

1

tenta di utilizzare getPivotX() e getPivotY(). Per def sono 0, 0 è per questo che inizia il ridimensionamento dall'angolo in alto a sinistra.
Cercare di ottenere perni da dove è toccato e cambiare il tuo
canvas.scale(...) a
canvas.scale(mScaleFactor, mScaleFactor, pivotx, pivoty);

+0

@All: come punto di zoom lo tocco – abcd1234

2

Approccio uno:

Per ingrandire dal centro di lista, ottenere il centro di zoom chiamando detector.getFocusX(); e detector.getFocusY(); .Ora uso questo centro nella tua logica di ridimensionamento.

Cambia la tua onScale() implementazione-qualcosa come di seguito:

mPosX = detector.getFocusX(); 
    mPosY = detector.getFocusY(); 

approccio in due (che sono attualmente in uso):

  • Metti la tua vista in vista di scorrimento.
  • Ridimensiona la visualizzazione.
  • calcolare quanto il centro si è spostato. (Prendere il diff di detector.getFocusX() e detector.getFocusY() prima e dopo il ridimensionamento)
  • uso parent.scrollBy (dx, dy) per centrare la vista.

Se aiuta, questa è una parte del mio codice di centratura.

if (isZoomOnGoing && mPreviousWidth != 0 && Math.abs(mCenterDiff) > 0) { 
     float ratioBeforeAdjustment = mCurrentZoomFocus/(float) (mTotalWidth - mCurrentZoomFocus);// 
     float ratioDiff = reducePrecision(mStartZoomRatio) - reducePrecision(ratioBeforeAdjustment); 
     float x1 = mStartZoomRatio * mTotalWidth/(1.0f + mStartZoomRatio); 
     float y1 = mTotalWidth - x1; 
     float currentRatio = x1/y1;// 
     int currentScrollBy = (int) (x1 - mCurrentZoomFocus); 
     int scrollDiff = 0; 
     if (mPreviousScrollBy != 0 && Math.abs(ratioDiff) > 1) { 
      scrollDiff = currentScrollBy - mPreviousScrollBy; 
     } 
     // if (scrollDiff>5) {//To avoid flickering//TODO do we need this 
     parent.scrollBy(currentScrollBy, 0); 

//} else {// Log.d (TAG, "drawActualGraph salto di scorrimento perché scrollDiff < 5"); //} mPreviousScrollBy = currentScrollBy;

+0

@ All: come punto di zoom lo tocco – abcd1234