Android:缩放 canvas 上的圆圈
Android: Scaling circles on a canvas with pinch
我目前可以在 canvas 上放置和拖动圆圈,但我无法理解如何允许用户使用捏合手势缩放圆圈。
圆是用'canvas.drawCircle(x,y,radius,paint)'画的。我最初的想法是使用自定义 'SimpleOnScaleGestureListener' 监听捏合手势,然后将所选圆的半径乘以比例因子。这产生了一些非常不可预测的结果,用两根手指快速点击,圆圈被缩放到微小或史诗般的比例。
这是我的自定义侦听器:
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector){
mScaleFactor *= detector.getScaleFactor()
if (isCircleToolSelected) {
// Checks if gesture was made inside of an existing circle
// CircleDrawing is a private class that holds x,y,radius,paint values
CircleDrawing circle = getCircle(detector.getFocusX(),
detector.getFocusY());
if (circle != null) {
touchedCircle.radius *= mScaleFactor;
}
}
return true;
}
}
这会检测手势并知道捏合是否在我 canvas 的圆圈内,但应用的缩放完全失控且无法使用。
我只尝试在当前和之前的比例因子之间的差异超过某个阈值时进行缩放,但这只会让缩放更难预测且更不稳定。
如果有人实现了类似的东西,我会喜欢一些方向。
当你select圈
时你必须得到比例因子
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (isCircleToolSelected) {
mScaleFactor *= detector.getScaleFactor()
// Checks if gesture was made inside of an existing circle
// CircleDrawing is a private class that holds x,y,radius,paintvalues
CircleDrawing circle = getCircle(detector.getFocusX(),
detector.getFocusY());
if (circle != null) {
touchedCircle.radius *= mScaleFactor;
}
}
return true;
}
}
回答我自己的问题,以防其他人确信您必须使用 ScaleFactor 来缩放所有内容。对于圆的基本缩放,您只需要找到 getCurrentSpan() 的当前值和先前值之间的差异。
这是我最后使用的代码:
//Used elsewhere to detect if we've touched an existing circle
CircleDrawing touchedCircle;
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private float lastSpan;
private float lastRadius;
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
//If the user has not already selected a circle
if (null == touchedCircle) {
// Check if we started scale gesture within existing circle
touchedCircle = getCircle(detector.getFocusX(), detector.getFocusY());
}
//If a circle has been selected, save radius and span
if (touchedCircle != null) {
lastRadius = touchedCircle.radius;
lastSpan = detector.getCurrentSpan();
}
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector){
//If the user has the shapes tool selected - handled elsewhere
if (isShapesSelected) {
//If the user is touching a circle
if (touchedCircle != null) {
//Value used to calculate new radius
float currentSpan = detector.getCurrentSpan();
float diameterDiff = currentSpan - lastSpan;
//Keep track of scaling direction for min and max sizes
boolean scalingUp = diameterDiff > 0;
//Only scale within radius sizes between 150 and 500
//Likely will change these values to relate to size of canvas
if ((!scalingUp && (lastRadius >= 150)) || (scalingUp && (lastRadius < 500))) {
//Calculate and set new radius
touchedCircle.radius += (diameterDiff)/2;
//Save radius and span for next frame
lastRadius = touchedCircle.radius;
lastSpan = detector.getCurrentSpan();
}
}
}
return true;
}
}
我目前可以在 canvas 上放置和拖动圆圈,但我无法理解如何允许用户使用捏合手势缩放圆圈。
圆是用'canvas.drawCircle(x,y,radius,paint)'画的。我最初的想法是使用自定义 'SimpleOnScaleGestureListener' 监听捏合手势,然后将所选圆的半径乘以比例因子。这产生了一些非常不可预测的结果,用两根手指快速点击,圆圈被缩放到微小或史诗般的比例。
这是我的自定义侦听器:
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector){
mScaleFactor *= detector.getScaleFactor()
if (isCircleToolSelected) {
// Checks if gesture was made inside of an existing circle
// CircleDrawing is a private class that holds x,y,radius,paint values
CircleDrawing circle = getCircle(detector.getFocusX(),
detector.getFocusY());
if (circle != null) {
touchedCircle.radius *= mScaleFactor;
}
}
return true;
}
}
这会检测手势并知道捏合是否在我 canvas 的圆圈内,但应用的缩放完全失控且无法使用。
我只尝试在当前和之前的比例因子之间的差异超过某个阈值时进行缩放,但这只会让缩放更难预测且更不稳定。
如果有人实现了类似的东西,我会喜欢一些方向。
当你select圈
时你必须得到比例因子 private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if (isCircleToolSelected) {
mScaleFactor *= detector.getScaleFactor()
// Checks if gesture was made inside of an existing circle
// CircleDrawing is a private class that holds x,y,radius,paintvalues
CircleDrawing circle = getCircle(detector.getFocusX(),
detector.getFocusY());
if (circle != null) {
touchedCircle.radius *= mScaleFactor;
}
}
return true;
}
}
回答我自己的问题,以防其他人确信您必须使用 ScaleFactor 来缩放所有内容。对于圆的基本缩放,您只需要找到 getCurrentSpan() 的当前值和先前值之间的差异。
这是我最后使用的代码:
//Used elsewhere to detect if we've touched an existing circle
CircleDrawing touchedCircle;
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private float lastSpan;
private float lastRadius;
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
//If the user has not already selected a circle
if (null == touchedCircle) {
// Check if we started scale gesture within existing circle
touchedCircle = getCircle(detector.getFocusX(), detector.getFocusY());
}
//If a circle has been selected, save radius and span
if (touchedCircle != null) {
lastRadius = touchedCircle.radius;
lastSpan = detector.getCurrentSpan();
}
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector){
//If the user has the shapes tool selected - handled elsewhere
if (isShapesSelected) {
//If the user is touching a circle
if (touchedCircle != null) {
//Value used to calculate new radius
float currentSpan = detector.getCurrentSpan();
float diameterDiff = currentSpan - lastSpan;
//Keep track of scaling direction for min and max sizes
boolean scalingUp = diameterDiff > 0;
//Only scale within radius sizes between 150 and 500
//Likely will change these values to relate to size of canvas
if ((!scalingUp && (lastRadius >= 150)) || (scalingUp && (lastRadius < 500))) {
//Calculate and set new radius
touchedCircle.radius += (diameterDiff)/2;
//Save radius and span for next frame
lastRadius = touchedCircle.radius;
lastSpan = detector.getCurrentSpan();
}
}
}
return true;
}
}