gpt4 book ai didi

android - 使用水平和垂直平移/拖动和捏缩放查看

转载 作者:IT老高 更新时间:2023-10-28 23:37:12 26 4
gpt4 key购买 nike

是否可以有一个支持水平和垂直平移/拖动的 View 。最重要的是,我希望能够捏缩放和双击缩放。这个 View 是否存在于 Android 上,或者有人知道有一个项目吗?

为了让它变得更加困难,需要将另一个 View (Button、TextView、VideoView、...)添加到 View 中。当第一个/父 View 放大或移动时, subview (按钮)需要随着父 View 移动。

我尝试了多种解决方案,但没有一个具有我正在寻找的所有选项。

最佳答案

我认为有可能实现您想要的,但据我所知,有内置解决方案。从你问题的第二部分,我猜你不想要一个可缩放的 View 而是一个 ViewGroup ,它是所有可以包含其他 View 的 View 的父类(super class)(例如布局)。以下是一些您可以从构建自己的 ViewGroup 开始的代码,其中大部分来自 this博文:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.*;

public class ZoomableViewGroup extends ViewGroup {

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 中布局子元素有疑问,我找到了 video非常有帮助,或者如果您对单一方法的工作原理或其他任何问题有任何疑问,请随时在评论中提问。

关于android - 使用水平和垂直平移/拖动和捏缩放查看,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12479859/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com