2010-11-19 100 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); 
    } 

}