问题
I have image zooming and dragging in my application my requirement is the image sets maximum and minimum zooming levels. I have used the below code.
public class Touch extends Activity implements OnTouchListener {
private static final String TAG = "Touch";
// 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;
static final float MAX_ZOOM = 5.0f;
static final float MIN_ZOOM = 1.0f;
// 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.findstation);
ImageView view = (ImageView) findViewById(R.id.imageView);
view.setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
// 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());
Log.d(TAG, "mode=DRAG");
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "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);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
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("]");
Log.d(TAG, sb.toString());
}
/** 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);
}
}
Can you please tell me how to set the max and min levels for zooming?
回答1:
Hi you need to define maximum zooming level
private static final float MIN_ZOOM = 1.0f;
private static final float MAX_ZOOM = //set Maximum zooming level
float scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
回答2:
That solution does not work, cause scale is relative value, but MIN_ZOOM and MAX_ZOOM are absolute. I've solved this problem like this:
public class GestureImageView extends ImageView {
private static final float MIN_DISTANCE_FOR_ZOOM = 5f;
private static final float MAX_SCALE_RATIO = 5f;
private static final int SCALE_X_INDEX = 0;
private static final int MATRIX_SIZE = 9;
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private GestureDetector gestureDetector;
private Matrix fitScreenMatrix = new Matrix();
private Matrix defaultMatrix = new Matrix();
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private PointF start = new PointF(0, 0);
private PointF mid = new PointF(0, 0);
private float oldDist = 1f;
private float minScale;
private float maxScale;
public GestureImageView(Context context) {
super(context);
gestureDetector = new GestureDetector(context, new DoubleTapListener());
setOnTouchListener(new ZoomDragListener());
setScaleType(AsyncGestureImageView.ScaleType.MATRIX);
}
private void calculateDefaultValues(Drawable drawable) {
float imgWidth = drawable.getIntrinsicWidth();
float imgHeight = drawable.getIntrinsicHeight();
float width = getWidth();
float height = getHeight();
float widthRatio = width / imgWidth;
float heightRatio = height / imgHeight;
float values[] = new float[MATRIX_SIZE];
float ratio;
PointF fitScreenPosition;
PointF defaultPosition = new PointF((width - imgWidth)/2f, (height - imgHeight)/2f);
if ( widthRatio < heightRatio ) {
ratio = widthRatio;
fitScreenPosition = new PointF(0f, (height/ratio-imgHeight)/2f);
} else {
ratio = heightRatio;
fitScreenPosition = new PointF((width/ratio - imgWidth)/2f, 0f);
}
fitScreenMatrix.postTranslate(fitScreenPosition.x, fitScreenPosition.y);
fitScreenMatrix.postScale(ratio, ratio, 0, 0);
fitScreenMatrix.getValues(values);
defaultMatrix.postTranslate(defaultPosition.x, defaultPosition.y);
maxScale = values[SCALE_X_INDEX] * MAX_SCALE_RATIO;
minScale = values[SCALE_X_INDEX];
}
private void fitScreen() {
matrix.set(fitScreenMatrix);
setImageMatrix(matrix);
}
private void defaultScreen() {
matrix.set(defaultMatrix);
setImageMatrix(matrix);
}
private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDoubleTap(MotionEvent e) {
if ( isFitScreen() ) {
defaultScreen();
return true;
}
fitScreen();
return true;
}
}
public boolean isFitScreen() {
return matrix.equals(fitScreenMatrix);
}
private class ZoomDragListener implements OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetector.onTouchEvent(event);
AsyncGestureImageView i = (AsyncGestureImageView) v;
dragAndZoom(i, event);
return true;
}
private void dragAndZoom(View v, MotionEvent event) {
AsyncGestureImageView view = (AsyncGestureImageView) v;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.x = event.getX();
start.y = event.getY();
if (isFitScreen()) {
return;
}
mode = DRAG;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = gestureDistance(event);
if (oldDist > MIN_DISTANCE_FOR_ZOOM) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
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 = gestureDistance(event);
if (newDist > MIN_DISTANCE_FOR_ZOOM) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
float values[] = new float[MATRIX_SIZE];
matrix.getValues(values);
float currentScale = values[SCALE_X_INDEX];
float newScale = currentScale * scale;
if ( newScale > maxScale ) {
scale = maxScale / currentScale;
}
if ( newScale < minScale ) {
scale = minScale / currentScale;
}
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix);
}
private float gestureDistance(MotionEvent event) {
if ( event.getPointerCount() != 2 ) {
return 0;
}
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) {
point.x = event.getX(0) / 2 + event.getX(1) / 2;
point.y = event.getY(0) / 2 + event.getY(1) / 2;
}
}
@Override
public void setImageDrawable(Drawable drawable) {
if ( drawable != null ) {
calculateDefaultValues(drawable);
fitScreen();
}
super.setImageDrawable(drawable);
}
来源:https://stackoverflow.com/questions/8656739/how-can-i-set-maximum-and-minimum-zooming-levels-for-image-in-android