android imageView:设置拖动和捏缩放参数
我目前正在为 Android(我的第一个应用程序)开发一个应用程序,它可以让用户查看地铁地图并能够进行缩放和拖动。
我目前正在修改 Hello Android,第 3 版中的代码,并让捏缩放和拖动功能正常工作。我使用 Matrix 作为布局比例。
然而我现在有 3 个问题:
我尝试了很多方法来限制拖动参数,但我似乎无法阻止它被拖离父视图(并且实际上可以从视图中消失)。我已经尝试在 XML 文件中设置布局参数,但它不起作用。
我可以很好地捏缩放,但我再次遇到限制缩放量的问题。我正在尝试设置 max_zoom 和 min_zoom 来限制缩放值(我将在之后发布我的代码)
我在尝试在图像上映射坐标以便人们可以单击某些部分时也遇到了麻烦(这样做的全部目的是让用户单击地图上的一个站点并查看有关它的信息)
我感觉我遇到了麻烦,因为我正在使用矩阵比例。
这是我当前的代码:
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>
I am currently developing for Android (my first app) an application which lets users see the subway map and be able to pinch zoom and drag around.
I am currently modifying the code found in Hello Android, 3rd Edition and got the pinch zooming and dragging to work. I'm using Matrix as my layout scale.
However I now have 3 problems:
I tried many things to limit the drag parameters but I can't seem to stop it being dragged off the parent view (and can actually disappear from view). I've tried setting layout parameters in the XML file and it just doesn't work.
I can pinch zoom fine but I have trouble, again, limiting the amount of zoom. I'm trying to play around with setting a max_zoom and min_zoom to limit the scaling value (i will post my code after)
I also have trouble trying to map a coordinate on my image so that people can click on certain parts (the whole point of this is to let users click a station on the map and view information about it)
I have a feeling i'm having trouble because I'm using the matrix scale.
Here is my current code:
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 (rather simple nothing really complicated):
<?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 (only added the theme so there is no title bar and is full screen)
<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>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我刚刚创建了这个:
https://github.com/jasonpolites/gesture-imageview
可能有用对于某人...
I just created this:
https://github.com/jasonpolites/gesture-imageview
Might be useful for someone...
另一个可能对某些人有用的选择是使用
WebView
,它内置了缩放控件。Another option that might work for some is to use a
WebView
, which has built in zoom controls.我知道这已经很旧了,但我正在考虑这样做,并找到了一个效果很好的解决方案。在 switch 语句之后和设置矩阵之前,您可以像这样限制缩放:
我仍在研究如何限制平移,但这应该适用于缩放限制。
编辑:这是限制翻译的解决方案。请注意,我这样做是为了全屏图像视图,这就是为什么我在限制因素中使用显示宽度和高度,但您也可以轻松地使用视图的宽度和高度。
再次强调,这将在 switch 语句之后、在视图中设置图像矩阵之前进行。我也将缩放限制分解为一个函数,它反映在上面。
I know this is old but I was looking into doing this and have a solution that works pretty well. Right after your switch statement and before you set the matrix, you can limit the zoom like so:
I'm still working out how to limit the translation but this should work for the zoom limiting.
EDIT: Here's a solution for limiting the translation. Just as a note, I'm doing this for a full screen image view which is why I use the display width and height in my limiting factors but you could just as easily use the width and height of your view instead.
Once again, this would go right after your switch statement and right before you set the matrix for the image in the view. I broke out the zoom limiting into a function as well and it is reflected above.
下载源代码。
因此,您还可以获得 a) 点击、b) 拖动和 c) 捏缩放。
http://pragprog.com/titles/eband3/source_code
Download the source code.
So you can also get this a) tap, b) drag, and c) pinch zoom.
http://pragprog.com/titles/eband3/source_code
这是捏拉缩放和平移的完整代码(Touch.java,做了一些修改,可以实际使用)
Here is the complete code for pinch zoom and pan (Touch.java with some modifications that can be used practically)
使用以下链接中 Phyxdevel 评论中的代码
ZDNET 缩放示例。
他有限制平移和缩放级别的代码。
Use the code in the comment by Phyxdevel in the below link
ZDNET Pinch Zoom Example.
He has the code to restrict the pan and zoom level.
您可以使用以下代码来限制底部和右侧
you can use following code to limit bottom and right