2010-11-19 96 views
28

我目前正在爲Android(我的第一個應用)開發一個應用程序,它可以讓用戶看到地鐵地圖,並能夠縮放和拖動。android imageView:設置拖放縮放縮放參數

我目前正在修改在Hello Android第3版中找到的代碼,並得到了縮放和拖動工作。我使用矩陣作爲我的佈局規模。

但是我現在有3個問題:

  1. 我試過很多事情要限制阻力參數,但我似乎無法阻止它被拖離父視圖(和實際上可以從視野中消失) 。我試過在XML文件中設置佈局參數,它不起作用。

  2. 我可以縮放很好,但我又遇到了麻煩,再次限制了縮放量。我試圖通過設置max_zoom和min_zoom來限制縮放值(我將在後面發佈我的代碼)

  3. 我也無法嘗試映射圖像上的座標,以便人們可以點擊確定部分(這整點是讓用戶在地圖上點擊一個站,並查看關於它的信息)

我有我我,因爲我使用的是矩陣的規模有麻煩的感覺。

這裏是我當前的代碼:

Touch.java

package org.example.touch; 
import android.app.Activity; 
import android.graphics.Bitmap; 
import android.graphics.Matrix; 
import android.graphics.PointF; 
import android.os.Bundle; 
import android.util.FloatMath; 
import android.util.Log; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.View.OnTouchListener; 
import android.widget.GridView; 
import android.widget.ImageView; 

public class Touch extends Activity implements OnTouchListener { 
private static final String TAG = "Touch"; 

private static final float MIN_ZOOM = 1.0f; 
private static final float MAX_ZOOM = 5.0f; 

// These matrices will be used to move and zoom image 
Matrix matrix = new Matrix(); 
Matrix savedMatrix = new Matrix(); 

// We can be in one of these 3 states 
static final int NONE = 0; 
static final int DRAG = 1; 
static final int ZOOM = 2; 
int mode = NONE; 

// Remember some things for zooming 
PointF start = new PointF(); 
PointF mid = new PointF(); 
float oldDist = 1f; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    ImageView view = (ImageView) findViewById(R.id.imageView); 
    //view.setLayoutParams(new GridView.LayoutParams(85, 85)); 
    view.setScaleType(ImageView.ScaleType.FIT_CENTER); 
    view.setOnTouchListener(this); 
} 

public boolean onTouch(View v, MotionEvent event) { 
    ImageView view = (ImageView) v; 
    view.setScaleType(ImageView.ScaleType.MATRIX); 
    float scale; 

    // Dump touch event to log 
    dumpEvent(event); 

    // Handle touch events here... 
    switch (event.getAction() & MotionEvent.ACTION_MASK) { 

    case MotionEvent.ACTION_DOWN: //first finger down only 
     savedMatrix.set(matrix); 
     start.set(event.getX(), event.getY()); 
     Log.d(TAG, "mode=DRAG"); 
     mode = DRAG; 
     break; 
    case MotionEvent.ACTION_UP: //first finger lifted 
    case MotionEvent.ACTION_POINTER_UP: //second finger lifted 
     mode = NONE; 
     Log.d(TAG, "mode=NONE"); 
     break; 
    case MotionEvent.ACTION_POINTER_DOWN: //second finger down 
     oldDist = spacing(event); 
     Log.d(TAG, "oldDist=" + oldDist); 
     if (oldDist > 5f) { 
     savedMatrix.set(matrix); 
     midPoint(mid, event); 
     mode = ZOOM; 
     Log.d(TAG, "mode=ZOOM"); 
     } 
     break; 

    case MotionEvent.ACTION_MOVE: 
     if (mode == DRAG) { //movement of first finger 
     matrix.set(savedMatrix); 
     if (view.getLeft() >= -392){ 
      matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); 
     } 
     } 
     else if (mode == ZOOM) { //pinch zooming 
     float newDist = spacing(event); 
     Log.d(TAG, "newDist=" + newDist); 
     if (newDist > 5f) { 
      matrix.set(savedMatrix); 
      scale = newDist/oldDist; **//thinking i need to play around with this value to limit it** 
      matrix.postScale(scale, scale, mid.x, mid.y); 
     } 
     } 
     break; 
    } 

    // Perform the transformation 
    view.setImageMatrix(matrix); 

    return true; // indicate event was handled 
} 

private float spacing(MotionEvent event) { 
    float x = event.getX(0) - event.getX(1); 
    float y = event.getY(0) - event.getY(1); 
    return FloatMath.sqrt(x * x + y * y); 
} 

private void midPoint(PointF point, MotionEvent event) { 
    float x = event.getX(0) + event.getX(1); 
    float y = event.getY(0) + event.getY(1); 
    point.set(x/2, y/2); 
} 

/** Show an event in the LogCat view, for debugging */ 
private void dumpEvent(MotionEvent event) { 
    String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" , 
     "POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" }; 
    StringBuilder sb = new StringBuilder(); 
    int action = event.getAction(); 
    int actionCode = action & MotionEvent.ACTION_MASK; 
    sb.append("event ACTION_").append(names[actionCode]); 
    if (actionCode == MotionEvent.ACTION_POINTER_DOWN 
     || actionCode == MotionEvent.ACTION_POINTER_UP) { 
     sb.append("(pid ").append(
     action >> MotionEvent.ACTION_POINTER_ID_SHIFT); 
     sb.append(")"); 
    } 
    sb.append("["); 
    for (int i = 0; i < event.getPointerCount(); i++) { 
     sb.append("#").append(i); 
     sb.append("(pid ").append(event.getPointerId(i)); 
     sb.append(")=").append((int) event.getX(i)); 
     sb.append(",").append((int) event.getY(i)); 
     if (i + 1 < event.getPointerCount()) 
     sb.append(";"); 
    } 
    sb.append("]"); 
    Log.d(TAG, sb.toString()); 
} 
} 

main.xml中(而不是簡單的沒有什麼複雜的):

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" > 
<ImageView android:id="@+id/imageView" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:src="@drawable/map" 
    android:scaleType="matrix" > 
</ImageView> 
</FrameLayout> 

的AndroidManifest.xml (只添加了主題,因此沒有標題欄並且是全屏幕)

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="org.example.touch" 
    android:versionCode="7" 
    android:versionName="1.0" > 
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > 
    <activity android:name=".Touch" 
     android:label="@string/app_name" > 
    <intent-filter> 
     <action android:name="android.intent.action.MAIN" /> 
     <category android:name="android.intent.category.LAUNCHER" /> 
    </intent-filter> 
    </activity> 
</application> 
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="7" /> 
</manifest> 

回答

18

我只是創造了這個:

https://github.com/jasonpolites/gesture-imageview

可能是有用的人......

+0

我喜歡這個,但是我不能隨便fill_parent ... – explodes 2012-03-08 00:12:20

+0

fill_parent的寬度和高度是沒有意義的,因爲這會(在大多數情況下)扭曲圖像。該框架對一個軸使用fill_parent屬性,並根據圖像的高寬比計算另一個軸。它根據設備的方向選擇哪個軸。橫向意味着寬度是fill_parent,高度是計算的,反之亦然。 – 2012-03-19 21:22:42

+0

@Jason,這將是圖像容器的大小,並且圖像本身可以在容器邊界內獨立設置大小。 – explodes 2012-04-11 17:19:38

7

我知道這是舊的,但我一直在尋找到這樣做的,有一個可行的解決方案很不錯。您的switch語句之後,你設置的矩陣前,可以限制變焦像這樣:

private void limitZoom(Matrix m) { 

    float[] values = new float[9]; 
    m.getValues(values); 
    float scaleX = values[Matrix.MSCALE_X]; 
    float scaleY = values[Matrix.MSCALE_Y]; 
    if(scaleX > MAX_ZOOM) { 
     scaleX = MAX_ZOOM; 
    } else if(scaleX < MIN_ZOOM) { 
     scaleX = MIN_ZOOM; 
    } 

    if(scaleY > MAX_ZOOM) { 
     scaleY = MAX_ZOOM; 
    } else if(scaleY < MIN_ZOOM) { 
     scaleY = MIN_ZOOM; 
    } 

    values[Matrix.MSCALE_X] = scaleX; 
    values[Matrix.MSCALE_Y] = scaleY; 
    m.setValues(values); 
} 

我還在工作如何限制的翻譯,但這應該縮放限制工作。

編輯:這是限制翻譯的解決方案。就像一個筆記,我這樣做的全屏圖像視圖,這就是爲什麼我在我的限制因素中使用顯示寬度和高度,但您可以輕鬆地使用視圖的寬度和高度。

private void limitDrag(Matrix m) { 
    float[] values = new float[9]; 
    m.getValues(values); 
    float transX = values[Matrix.MTRANS_X]; 
    float transY = values[Matrix.MTRANS_Y]; 
    float scaleX = values[Matrix.MSCALE_X]; 
    float scaleY = values[Matrix.MSCALE_Y]; 

    ImageView iv = (ImageView)findViewById(R.id.photo_view); 
    Rect bounds = iv.getDrawable().getBounds(); 
    int viewWidth = getResources().getDisplayMetrics().widthPixels; 
    int viewHeight = getResources().getDisplayMetrics().heightPixels; 

    int width = bounds.right - bounds.left; 
    int height = bounds.bottom - bounds.top; 

    float minX = (-width + 20) * scaleX; 
    float minY = (-height + 20) * scaleY; 

    if(transX > (viewWidth - 20)) { 
     transX = viewWidth - 20; 
    } else if(transX < minX) { 
     transX = minX; 
    } 

    if(transY > (viewHeight - 80)) { 
     transY = viewHeight - 80; 
    } else if(transY < minY) { 
     transY = minY; 
    } 

    values[Matrix.MTRANS_X] = transX; 
    values[Matrix.MTRANS_Y] = transY; 
    m.setValues(values); 
} 

再次,你設置的矩陣視圖圖像在此之前會去你的switch語句,右後右。我也將變焦限制分解爲一個函數,並在上面反映出來。

+0

限制向上和向左的拖動。但是朝右和向下的方向仍然是圖像。任何想法解決? – playmaker420 2012-11-23 19:15:54

+1

@ playmaker420請在下方檢查我的答案以限制右下角。 – Ankit 2013-03-06 13:53:08

+0

@ Ankit ..我解決了它。任何方式感謝分享代碼 – playmaker420 2013-03-06 15:29:06

11

另一種可能適用於某些功能的選項是使用WebView,它內置了縮放控件。

WebView webView = new WebView(this); 
webView.setBackgroundColor(0xff000000); 
webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY); 
webView.getSettings().setBuiltInZoomControls(true); 
webView.getSettings().setSupportZoom(true); 
//webView.getSettings().setDisplayZoomControls(false); // API 11 
webView.loadDataWithBaseURL(null, getHtml(), "text/html", "UTF-8", null); 
mainView.addView(webView, -1, -2); 
+0

毫無疑問,我可以說,這是我發現管理縮放位圖的最佳方式。我希望你不介意我發佈一個鏈接到另一個SO問題,可能會幫助別人,但這個答案與http://stackoverflow.com/questions/10849200/android-how-to-display-a-bitmap- in-a-webview做了將動態創建的位圖加載到WebView進行縮放的技巧。再次感謝,很好的回答! – zgc7009 2014-11-24 21:25:54

0

你可以用下面的代碼來限制底部和右側

float maxX = minX+viewWidth; 
int offsetY = 80; 
     float maxY = minY+viewHeight-offsetY; 
     if(x>maxX){ 
      mPosX = maxX; 
     } 
     if(x<minX){ 
      mPosX = minX; 
     } 
     if(y>maxY){ 
      mPosY = maxY; 
     } 
     if(y<minY){ 
      mPosY = minY; 
     } 
6

這裏是指縮放和平移的完整代碼(Touch.java有一些修改,可實際使用)

public class Touch implements OnTouchListener { 

// These matrices will be used to move and zoom image 
public static Matrix matrix = new Matrix(); 
public static Matrix savedMatrix = new Matrix(); 

// We can be in one of these 3 states 
static final int NONE = 0; 
static final int DRAG = 1; 
static final int ZOOM = 2; 
private static final float MAX_ZOOM = (float) 3; 
private static final float MIN_ZOOM = 1; 
int mode = NONE; 

// Remember some things for zooming 
PointF start = new PointF(); 
PointF mid = new PointF(); 
float oldDist = 1f; 

int width,height; 

@Override 
public boolean onTouch(View v, MotionEvent event) { 


    ImageView view = (ImageView) v; 
    Rect bounds = view.getDrawable().getBounds(); 

    width = bounds.right - bounds.left; 
    height = bounds.bottom - bounds.top; 
    // Dump touch event to log 
    dumpEvent(event); 

    // Handle touch events here... 
    switch (event.getAction() & MotionEvent.ACTION_MASK) { 
    case MotionEvent.ACTION_DOWN: 
    savedMatrix.set(matrix); 
    start.set(event.getX(), event.getY()); 
    mode = DRAG; 
    break; 
    case MotionEvent.ACTION_POINTER_DOWN: 
    oldDist = spacing(event); 
    if (oldDist > 10f) { 
    savedMatrix.set(matrix); 
    midPoint(mid, event); 
    mode = ZOOM; 
    } 
    break; 
    case MotionEvent.ACTION_UP: 
    case MotionEvent.ACTION_POINTER_UP: 
    mode = NONE; 
    break; 
    case MotionEvent.ACTION_MOVE: 
    if (mode == DRAG) { 
    // ...  
    matrix.set(savedMatrix); 
    matrix.postTranslate(event.getX() - start.x, event.getY() - start.y);  
    } else if (mode == ZOOM) { 
    float newDist = spacing(event); 
    if (newDist > 10f) { 
    matrix.set(savedMatrix); 
    float scale = newDist/oldDist; 
    matrix.postScale(scale, scale, mid.x, mid.y); 
    } 
    } 
    break; 
    } 
//---------------------------------------------------- 
    limitZoom(matrix); 
    limitDrag(matrix); 
//---------------------------------------------------- 
    view.setImageMatrix(matrix); 
    return true; // indicate event was handled 
} 

/** Show an event in the LogCat view, for debugging */ 
private void dumpEvent(MotionEvent event) { 
    String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", 
    "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" }; 
    StringBuilder sb = new StringBuilder(); 
    int action = event.getAction(); 
    int actionCode = action & MotionEvent.ACTION_MASK; 
    sb.append("event ACTION_").append(names[actionCode]); 
    if (actionCode == MotionEvent.ACTION_POINTER_DOWN 
    || actionCode == MotionEvent.ACTION_POINTER_UP) { 
    sb.append("(pid ").append( 
    action >> MotionEvent.ACTION_POINTER_ID_SHIFT); 
    sb.append(")"); 
    } 
    sb.append("["); 
    for (int i = 0; i < event.getPointerCount(); i++) { 
    sb.append("#").append(i); 
    sb.append("(pid ").append(event.getPointerId(i)); 
    sb.append(")=").append((int) event.getX(i)); 
    sb.append(",").append((int) event.getY(i)); 
    if (i + 1 < event.getPointerCount()) 
    sb.append(";"); 
    } 
    sb.append("]"); 
} 

/** Determine the space between the first two fingers */ 
private float spacing(MotionEvent event) { 
    float x = event.getX(0) - event.getX(1); 
    float y = event.getY(0) - event.getY(1); 
    return FloatMath.sqrt(x * x + y * y); 
} 

/** Calculate the mid point of the first two fingers */ 
private void midPoint(PointF point, MotionEvent event) { 
    float x = event.getX(0) + event.getX(1); 
    float y = event.getY(0) + event.getY(1); 
    point.set(x/2, y/2); 
} 

private void limitZoom(Matrix m) { 

     float[] values = new float[9]; 
     m.getValues(values); 
     float scaleX = values[Matrix.MSCALE_X]; 
     float scaleY = values[Matrix.MSCALE_Y]; 
     if(scaleX > MAX_ZOOM) { 
      scaleX = MAX_ZOOM; 
     } else if(scaleX < MIN_ZOOM) { 
      scaleX = MIN_ZOOM; 
     } 

     if(scaleY > MAX_ZOOM) { 
      scaleY = MAX_ZOOM; 
     } else if(scaleY < MIN_ZOOM) { 
      scaleY = MIN_ZOOM; 
     } 

     values[Matrix.MSCALE_X] = scaleX; 
     values[Matrix.MSCALE_Y] = scaleY; 
     m.setValues(values); 
    } 


private void limitDrag(Matrix m) { 

     float[] values = new float[9]; 
     m.getValues(values); 
     float transX = values[Matrix.MTRANS_X]; 
     float transY = values[Matrix.MTRANS_Y]; 
     float scaleX = values[Matrix.MSCALE_X]; 
     float scaleY = values[Matrix.MSCALE_Y]; 
//--- limit moving to left --- 
     float minX = (-width + 0) * (scaleX-1); 
     float minY = (-height + 0) * (scaleY-1); 
//--- limit moving to right ---  
     float maxX=minX+width*(scaleX-1); 
     float maxY=minY+height*(scaleY-1); 
     if(transX>maxX){transX = maxX;} 
     if(transX<minX){transX = minX;} 
     if(transY>maxY){transY = maxY;} 
     if(transY<minY){transY = minY;} 
     values[Matrix.MTRANS_X] = transX; 
     values[Matrix.MTRANS_Y] = transY; 
     m.setValues(values); 
    } 

}