2015-08-27 9 views
11

Ich arbeite an einer einfachen Buch-Reader-App für Android. Ich habe die Listenansicht dafür verwendet.Wie zoomen Listenelement von der Mitte der Prise

Was ich mache ist das Laden der Remote-Bilder vom Server in meine Listview (mit der Picasso-Bibliothek) und funktioniert gut.

Ich wollte auch Funktionalität in meinem Reader Zoom, gut ich ZoomListView Klasse verwendet, um dies zu erreichen.

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

} 

Hier ist meine XML-Layout (Ich habe nur die ZoomListView zeigte):

<?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> 

So konnte ich mein Buch Leser vergrößern. Mein Buch Leser sieht aus wie

enter image description here

Problem: Ich erhalte Thema in meinem Prise Zoom. Wenn ich kneife, beginnt der Zoom von oben links in der Listenansicht.

Lassen Sie mich mit Bildern beschreiben

1 Pinch

enter image description here

2 Stromausgang

Hinweis: Dies ist die Listenansicht von der oberen linken Ecke Vergrößerte

enter image description here

3 Empfohlene Ausgabe

enter image description here

+0

Folgen Sie diesem Tutorial http://android-er.blogspot.com/2011/11/implement-pinch-zoom-in-ontouchlistener.html –

+0

Können Sie diese Anweisungen rechtfertigen: 'if (mPosX> 0.0f) mPosX = 0.0f; sonst if (mPosX maxWidth) mPosX = maxWidth; '. Ich habe ähnliche Bedenken hinsichtlich Ihrer Grenzkontrollbedingungen für 'mPosY'. – Vikram

+0

@Vikram Ich habe mich geändert, wie Sie oben vorgeschlagen haben, aber mein Problem ist immer noch da. –

Antwort

1

es bedeutet, dass Sie die Standardeigenschaft ändern möchten, das Zoom (Skalierung) immer von (0,0) beginnt, das ist:

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

Und Sie möchten es skalieren von:

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

So dies zu erreichen: Sie Code aus dieser Änderung:

canvas.scale(mScaleFactor, mScaleFactor); 

dazu:

canvas.scale(mScaleFactor, -mScaleFactor); 

auch diese Frage sehen, die mit Ihrer Frage betrifft: Android: Drawing to canvas, way to make bottom left correspond to (0,0)? Ich habe ich Ihnen habe deine Lösung aus diesem Beispiel und Code-Snippet.

+0

Bitte lesen Sie das Quiz erneut. Ich möchte nicht wie vorgeschlagen Ihre Antwort eher ich muss das Listenelement von der Mitte der Prise zu zoomen, aber es immer Zoom von oben links von dem Artikel –

+0

@All: wie zoomen Punkt ich berühre es – abcd1234

1

Versuchen Sie zu verwenden getPivotX() und getPivotY(). Per def sind sie 0, 0, deshalb beginnt sie von oben links zu skalieren.
Versuchen schwenkt zu bekommen, von wo sie berührt hat und Ihr
canvas.scale(...) zu
canvas.scale(mScaleFactor, mScaleFactor, pivotx, pivoty);

+0

@All: wie zu Zoom-Punkt Ich berühre es – abcd1234

2

Ansatz ein ändern:

Um von der Mitte der Liste zu vergrößern, die Zoom-Center erhalten, indem Aufruf detector.getFocusX(); und detector.getFocusY(); .Jetzt Einsatz Dieses Zentrum in Ihrer Skalierungslogik.

Ihre onScale() umsetzungs etwas ändern wie unten:

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

Ansatz zwei (die ich zur Zeit bin mit):

  • in Scroll-Ansicht Legen Sie Ihre Ansicht.
  • Ändern Sie die Größe Ihrer Ansicht.
  • berechnet, wie viel das Zentrum bewegt hat. (Nehmen Sie die diff von detector.getFocusX() und detector.getFocusY() vor und nach dem Ändern der Größe)
  • Verwendung parent.scrollBy (dx, dy), um die Ansicht neu zu zentrieren.

Wenn es hilft - das ist ein Teil von meinem Zentrierungscode.

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 Überspringen scroll weil scrollDiff < 5"); //} mPreviousScrollBy = currentScrollBy;

+0

@All: wie Zoom-Punkt Ich berühre es – abcd1234