我已经移植了一些 Android 代码,用于将 ImageView 缩放为 Android 的单声道,但我在缩放检测器焦点方面遇到了问题。我需要以编程方式绘制对象,因此我要重写 ondraw 方法。
问题是,当我的缩放比例不是 1 时,如果我捏住绘制对象的一侧,绘制的对象会跳离捏合焦点,最终得到的焦点不是您开始时(如果缩放比例大于 1)。如果缩放比例小于1,则绘制的对象会跳向捏合焦点。
我已经尝试了几乎所有的方法,但我一定是太老太累了,因为我就是想不通。
在ondraw中,我先缩放然后平移,然后在固定点绘制对象。
我是否以正确的方式处理这件事?我在搜索中找不到任何涉及在 Canvas 上的某个点绘制对象同时实现捏缩放的内容。
如果有人能提供帮助,我们将不胜感激。
代码如下...
class clsTarget : ImageView, ImageView.IOnTouchListener
{
private ScaleGestureDetector mScaleDetector;
private ScaleListener sListener;
private static float mScaleFactor = 0.6F;
private static float scalePointX;
private static float scalePointY;
private static int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private static float mPosX, mPosY, mLastTouchX, mLastTouchY;
public clsTarget(Context context)
: base(context)
{
this.SetOnTouchListener(this);
sListener = new ScaleListener();
mScaleDetector = new ScaleGestureDetector(context, sListener);
mScaleFactor = 800F / (float)Math.Min(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels);
}
protected override void OnDraw(Android.Graphics.Canvas canvas)
{
canvas.Save();
canvas.Scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY);
canvas.Translate(mPosX, mPosY);
Paint p = new Paint(PaintFlags.AntiAlias);
p.Color = Color.Orange;
p.SetStyle(Paint.Style.Fill);
p.StrokeWidth = 1F;
canvas.DrawCircle(400, 400, 200, p);
canvas.Restore();
}
public bool OnTouch(View v, MotionEvent e)
{
mScaleDetector.OnTouchEvent(e);
switch (e.Action & MotionEventActions.Mask)
{
case MotionEventActions.Down:
float x = (e.GetX() - scalePointX) / mScaleFactor;
float y = (e.GetY() - scalePointY) / mScaleFactor;
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = e.GetPointerId(0);
break;
case MotionEventActions.Move:
int pointerIndex = e.FindPointerIndex(mActivePointerId);
float x2 = (e.GetX(pointerIndex) - scalePointX) / mScaleFactor;
float y2 = (e.GetY(pointerIndex) - scalePointY) / mScaleFactor;
float dx = (x2 - mLastTouchX);
float dy = (y2 - mLastTouchY);
if (!mScaleDetector.IsInProgress)
{
mPosX += dx;
mPosY += dy;
mLastTouchX = x2;
mLastTouchY = y2;
}
this.Invalidate();
break;
case MotionEventActions.Up:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEventActions.Cancel:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEventActions.PointerUp:
int pointerIndex2 = (int)(e.Action & MotionEventActions.PointerIndexMask) >> (int)MotionEventActions.PointerIndexShift;
int pointerID = e.GetPointerId(pointerIndex2);
if (pointerID == mActivePointerId)
{
int newPointerIndex = pointerIndex2 == 0 ? 1 : 0;
mLastTouchX = (e.GetX(newPointerIndex) - scalePointX) / mScaleFactor;
mLastTouchY = (e.GetY(newPointerIndex) - scalePointY) / mScaleFactor;
mActivePointerId = e.GetPointerId(newPointerIndex);
}
break;
}
return true;
}
private class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener
{
public override bool OnScale(ScaleGestureDetector detector)
{
scalePointX = detector.FocusX;
scalePointY = detector.FocusY;
mScaleFactor *= detector.ScaleFactor;
mScaleFactor = Math.Max(0.5f, Math.Min(mScaleFactor, 7.0f));
return true;
}
}
}
最佳答案
抱歉,英语不好。
首先,Case MotionEventActions.Move,当ScaleDetector.IsInProgress为true时,设置mLastGestureX和mLastGesturey。
在OnDraw中,当ScaleDetector.IsInProgress为false时, canvas.Scale(mScaleFactor, mScaleFactor,mLastGestureX,mLastGestureY)
代码如下...
class ImageViewExt : ImageView
{
private static int INVALID_POINTER_ID = -1;
private float mPosX;
private float mPosY;
private float mLastTouchX;
private float mLastTouchY;
private float mLastGestureX;
private float mLastGestureY;
private int mActivePointerId = INVALID_POINTER_ID;
private ScaleGestureDetector mScaleDetector;
private static float mScaleFactor = 1.0f;
public ImageViewExt(Context context):base(context)
{
mScaleDetector = new ScaleGestureDetector(Context,new ScaleListener());
}
public override bool OnTouchEvent (MotionEvent e)
{
mScaleDetector.OnTouchEvent (e);
//int action = e.Action;
switch (e.Action & MotionEventActions.Mask) {
case MotionEventActions.Down:
if (!mScaleDetector.IsInProgress) {
float x = e.GetX ();
float y = e.GetY ();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = e.GetPointerId (0);
}
break;
case MotionEventActions.Pointer1Down:
if (mScaleDetector.IsInProgress) {
float gx = mScaleDetector.FocusX;
float gy = mScaleDetector.FocusY;
mLastGestureX = gx;
mLastGestureY = gy;
}
break;
case MotionEventActions.Move:
if (!mScaleDetector.IsInProgress) {
int pointerIdx = e.FindPointerIndex (mActivePointerId);
float x = e.GetX (pointerIdx);
float y = e.GetY (pointerIdx);
float dx = x - mLastTouchX;
float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
Invalidate ();
mLastTouchX = x;
mLastTouchY = y;
} else {
float gx = mScaleDetector.FocusX;
float gy = mScaleDetector.FocusY;
float gdx = gx - mLastGestureX;
float gdy = gy - mLastGestureY;
mPosX += gdx;
mPosY += gdy;
Invalidate ();
mLastGestureX = gx;
mLastGestureY = gy;
}
break;
case MotionEventActions.Up:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEventActions.Cancel:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEventActions.PointerUp:
int pointerIdx2 = (int)(e.Action & MotionEventActions.PointerIndexMask) >> (int)MotionEventActions.PointerIndexShift;
int pointerId = e.GetPointerId (pointerIdx2);
if (pointerId == mActivePointerId) {
int NewPointerIndex = pointerIdx2 == 0 ? 1 : 0;
mLastTouchX = e.GetX (NewPointerIndex);
mLastTouchY = e.GetY (NewPointerIndex);
mActivePointerId = e.GetPointerId (NewPointerIndex);
}
else{
int TempPointerIdx = e.FindPointerIndex(mActivePointerId);
mLastTouchX = e.GetX(TempPointerIdx);
mLastTouchY = e.GetY(TempPointerIdx);
}
break;
}
return true;
}
protected override void OnDraw (Canvas canvas)
{
canvas.Save ();
canvas.Translate (mPosX, mPosY);
if (mScaleDetector.IsInProgress) {
canvas.Scale (mScaleFactor, mScaleFactor, mScaleDetector.FocusX, mScaleDetector.FocusY);
} else {
canvas.Scale (mScaleFactor, mScaleFactor,mLastGestureX,mLastGestureY);
}
base.OnDraw (canvas);
canvas.Restore();
}
private class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener
{
public override bool OnScale (ScaleGestureDetector detector)
{
mScaleFactor *= detector.ScaleFactor;
//小さすぎず大きすぎず処理
mScaleFactor = Math.Max(0.1f, Math.Min(mScaleFactor, 10.0f));
return true;
}
}
}
关于android - Mono Android 双指缩放同时覆盖 ondraw,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12594918/