问题描述
时有可能有谁支持水平和垂直平移/拖期。最重要的是,我希望能够捏缩放和双击放大。请问这种观点存在于Android或不会有人知道的一个项目谁做的?
Is it possible to have a view who supports horizontal and vertical pan/drag. On top of that, I want to be able to pinch to zoom and double tap to zoom.Does this view exists on Android or does somebody knows a project who does?
要使它变得更加困难,在其他视图(按钮,TextView的,VideoView,...)需要被添加到视图。当第一/父视图被放大或四处移动,子视图(按钮),需要与父母四处移动。
To make it even more difficult, an other view (Button, TextView, VideoView, ...) needs to be added to the view. When the first/parent view is zoomed in or moved around, the subview (Button) needs to move around with the parent.
我尝试过多种解决方案,但他们都没有人我正在寻找的选项。
I've tried multiple solutions, but none of them have al the options I'm looking for.
- https://github.com/MikeOrtiz/TouchImageView/tree/master/src/com/example/touch
- http://vivin.net/2011/12/04/implementing-pinch-zoom-and-pandrag-in-an-android-view-on-the-canvas/
- https://github.com/MikeOrtiz/TouchImageView/tree/master/src/com/example/touch
- http://vivin.net/2011/12/04/implementing-pinch-zoom-and-pandrag-in-an-android-view-on-the-canvas/
推荐答案
我认为这是可能实现你想要什么,但,据我所知构建解决方案吧。从你问题的第二部分,我猜你不想要一个可缩放查看
但的ViewGroup
这是超类中的所有可以包含其他视图查看(如布局)。下面是一些code,你可以从建立自己的ViewGroup大部分开始来自的的博客文章:
I think it's possible to achieve what you want, but there is, as far as I know build in solution for it. From the second part of your question I guess that you don't want a zoomable View
but a ViewGroup
which is the super class of all Views that can contain other view (e.g. Layouts). Here is some code you could start from building your own ViewGroup most of it comes from this blog post:
public class ZoomableViewGroup {
private static final int INVALID_POINTER_ID = 1;
private int mActivePointerId = INVALID_POINTER_ID;
private float mScaleFactor = 1;
private ScaleGestureDetector mScaleDetector;
private Matrix mScaleMatrix = new Matrix();
private Matrix mScaleMatrixInverse = new Matrix();
private float mPosX;
private float mPosY;
private Matrix mTranslateMatrix = new Matrix();
private Matrix mTranslateMatrixInverse = new Matrix();
private float mLastTouchX;
private float mLastTouchY;
private float mFocusY;
private float mFocusX;
private float[] mInvalidateWorkingArray = new float[6];
private float[] mDispatchTouchEventWorkingArray = new float[2];
private float[] mOnTouchEventWorkingArray = new float[2];
public ZoomableViewGroup(Context context) {
super(context);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
mTranslateMatrix.setTranslate(0, 0);
mScaleMatrix.setScale(1, 1);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
child.layout(l, t, l+child.getMeasuredWidth(), t + child.getMeasuredHeight());
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor, mFocusX, mFocusY);
super.dispatchDraw(canvas);
canvas.restore();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mDispatchTouchEventWorkingArray[0] = ev.getX();
mDispatchTouchEventWorkingArray[1] = ev.getY();
mDispatchTouchEventWorkingArray = screenPointsToScaledPoints(mDispatchTouchEventWorkingArray);
ev.setLocation(mDispatchTouchEventWorkingArray[0],
mDispatchTouchEventWorkingArray[1]);
return super.dispatchTouchEvent(ev);
}
/**
* Although the docs say that you shouldn't override this, I decided to do
* so because it offers me an easy way to change the invalidated area to my
* likening.
*/
@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
mInvalidateWorkingArray[0] = dirty.left;
mInvalidateWorkingArray[1] = dirty.top;
mInvalidateWorkingArray[2] = dirty.right;
mInvalidateWorkingArray[3] = dirty.bottom;
mInvalidateWorkingArray = scaledPointsToScreenPoints(mInvalidateWorkingArray);
dirty.set(Math.round(mInvalidateWorkingArray[0]), Math.round(mInvalidateWorkingArray[1]),
Math.round(mInvalidateWorkingArray[2]), Math.round(mInvalidateWorkingArray[3]));
location[0] *= mScaleFactor;
location[1] *= mScaleFactor;
return super.invalidateChildInParent(location, dirty);
}
private float[] scaledPointsToScreenPoints(float[] a) {
mScaleMatrix.mapPoints(a);
mTranslateMatrix.mapPoints(a);
return a;
}
private float[] screenPointsToScaledPoints(float[] a){
mTranslateMatrixInverse.mapPoints(a);
mScaleMatrixInverse.mapPoints(a);
return a;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
mOnTouchEventWorkingArray[0] = ev.getX();
mOnTouchEventWorkingArray[1] = ev.getY();
mOnTouchEventWorkingArray = scaledPointsToScreenPoints(mOnTouchEventWorkingArray);
ev.setLocation(mOnTouchEventWorkingArray[0], mOnTouchEventWorkingArray[1]);
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
mTranslateMatrix.preTranslate(dx, dy);
mTranslateMatrix.invert(mTranslateMatrixInverse);
mLastTouchX = x;
mLastTouchY = y;
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
if (detector.isInProgress()) {
mFocusX = detector.getFocusX();
mFocusY = detector.getFocusY();
}
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
mScaleMatrix.setScale(mScaleFactor, mScaleFactor,
mFocusX, mFocusY);
mScaleMatrix.invert(mScaleMatrixInverse);
invalidate();
requestLayout();
return true;
}
这是什么类的应该是能够做到的,是周围拖动内容,并允许捏放大,双击放大是不可能的现在,但它应该很容易在的onTouchEvent实施
方法。
如果您有任何疑问如何布置孩子的在你的ViewGroup我发现这视频一>非常有帮助,或者如果您有任何进一步的问题是如何单独的工作方法或其他任何随意问了意见。
If you have questions how to layout the childs in your ViewGroup I found this video very helpfull or if you have any further questions how single methods work or anything else feel free to ask in the comments.
这篇关于查看水平和垂直平移/阻力和捏缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!