我正在尝试相对于另一个视图缩放一堆视图。所以,假设我有ImageView
,其地图为ImageDrawable
。
该地图上有一些POI(在位图中),我想在POI之上绘制我的视图,因为我希望它们可以被触摸。
我对如何实现这一点有一些想法:
1 - 我只是简单地拖动/缩放该图像并关于它的位置和比例我也可以使用MotionEvent
getX和getY获得POI位置。
这是最丑陋但最快的解决方案。
2 - 使用GoogleMaps
我的图片有地图图片叠加(我可以使用Mapbox
或Android
Ground Overlays
来实现此目的。我会将地图移到“无处”位置,绘制我的自定义标记和完成的工作。 GoogleMaps
会处理我的缩放,拖动,POI触摸等...
3 - 我正在使用的解决方案和我最喜欢的解决方案:拥有一个 ViewContainer 及其所有子视图,这些视图将遭受一些矩阵转换。
让我们看一些代码:
public class ZoomableContainer extends FrameLayout implements View.OnTouchListener {
private static final float THRESHOLD = 50;
private List<ImageView> mChildViews;
private final GestureDetector mGestureDetector;
private Matrix mMatrix = new Matrix();
private Matrix mSavedMatrix = new Matrix();
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mMode = NONE;
private PointF mStart = new PointF();
private PointF mMid = new PointF();
private float mOldDist = 1f;
private float[] mLastEvent = null;
public ZoomableContainer(ZoomInActivity context, List<ImageView> child) {
super(context);
mChildViews = new ArrayList<>(child);
mGestureDetector = new GestureDetector(getContext(), new SingleTapConfirm());
setClipChildren(false);
setClipToPadding(false);
for (ImageView view : mChildViews) {
view.setScaleType(ImageView.ScaleType.MATRIX);
addView(view);
}
setOnTouchListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
if (mGestureDetector.onTouchEvent(event)) {
getViewInBounds(event);
} else {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mSavedMatrix.set(mMatrix);
mStart.set(event.getX(), event.getY());
mMode = DRAG;
mLastEvent = null;
break;
case MotionEvent.ACTION_POINTER_DOWN:
mOldDist = spacingBetweenTouch(event);
if (mOldDist > 10f) {
mSavedMatrix.set(mMatrix);
midPointBetweenTouch(mMid, event);
mMode = ZOOM;
}
mLastEvent = new float[4];
mLastEvent[0] = event.getX(0);
mLastEvent[1] = event.getX(1);
mLastEvent[2] = event.getY(0);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mMode = NONE;
mLastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
if (mMode == DRAG) {
mMatrix.set(mSavedMatrix);
float dx = event.getX() - mStart.x;
float dy = event.getY() - mStart.y;
mMatrix.postTranslate(dx, dy);
} else if (mMode == ZOOM) {
float newDist = spacingBetweenTouch(event);
if (newDist > 10f) {
mMatrix.set(mSavedMatrix);
float scale = (newDist / mOldDist);
mMatrix.postScale(scale, scale, mMid.x, mMid.y);
}
}
break;
}
if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE) {
for (ImageView view : mChildViews) {
view.setImageMatrix(mMatrix);
}
}
}
return true;
}
private float spacingBetweenTouch(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
private void midPointBetweenTouch(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 getViewInBounds(MotionEvent event) {
// handle POI onClick() logic...
}
private class SingleTapConfirm extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent event) {
return true;
}
}
}
因此,使用此View
我可以 DRAG 和 ZOOM ,这让人感到寒心。 List<ImageView> child
包含我的所有POI和MAP(子[0])。现在它变得棘手:
setX(100)
和setY(100)
,则该比例可以正常工作,但相对于de MAP视图,其位置不会改变。我有一些问题:
1 - 为什么在应用矩阵变换后getX()
,getY()
,getScale()
...将不会更新?
2 - 我如何实现我想要的,postScale
所有视图都会受到相对于MAP视图的比例(工作)和正确的翻译(不工作)(就像它们位于相同的原点时一样) scale = 1)
我已经尝试过{在if
view.setImageMatrix(mMatrix);
之后的onTouch
内部)以使用视图新矩阵并参考Matrix.MTRANS_X
或Matrix.MSCALE_X
in为了将视图转换回(在比例之后)到相对于地图的所需位置但没有运气。
我想我离解决方案的距离不远,或者我可能,但你能指出我吗? 谢谢你的帮助,希望我一直很清楚。