我目前正在使用Canvas Circles开发一个树形结构,我几乎使用Canvas实现了布局,但在Canvas中实现Drag and Drop时遇到了问题。代码如下以便更好地理解:
private HashSet<CircleArea> mCircles = new HashSet<CircleArea>(CIRCLES_LIMIT);
private SparseArray<CircleArea> mCirclePointer = new SparseArray<CircleArea>(CIRCLES_LIMIT);
private static class CircleArea {
int radius;
int centerX;
int centerY;
CircleArea(int centerX, int centerY, int radius) {
this.radius = radius;
this.centerX = centerX;
this.centerY = centerY;
}
public int getCenterX()
{
return centerX;
}
public int getCenterY()
{
return centerY;
}
public int getRadius()
{
return radius;
}
@Override
public String toString() {
return "Circle[" + centerX + ", " + centerY + ", " + radius + "]";
}
}
private void init(final Context ct) {
Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
System.out.println("Width is " + width + "Height is " + height);
scrWidth = width;
scrHeight = height;
}
@Override
public void onDraw(final Canvas canv) {
// setWillNotDraw(false);
for (int i = 0; i < name.length; i++) {
if (i == 0) {
for (int j = 0; j < latitude_0.length; j++) {
x = (int) ((scrWidth / 360.0) * (90 + longitude_0[j]));
y = (int) ((scrHeight / 180.0) * (90 - latitude_0[j]));
mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));
}
} else if (i == 1) {
for (int k = 0; k < latitude_1.length; k++) {
x = (int) ((scrWidth / 360.0) * (90 + longitude_1[k]));
y = (int) ((scrHeight / 180.0) * (90 - latitude_1[k]));
mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));
}
} else if (i == 2) {
for (int l = 0; l < latitude_2.length; l++) {
x = (int) ((scrWidth / 360.0) * (90 + longitude_2[l]));
y = (int) ((scrHeight / 180.0) * (90 - latitude_2[l]));
mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));
}
} else if (i == 3) {
for (int l = 0; l < latitude_3.length; l++) {
x = (int) ((scrWidth / 360.0) * (90 + longitude_3[l]));
y = (int) ((scrHeight / 180.0) * (90 - latitude_3[l]));
mCircles.add(new CircleArea(x, y, RADIUS_LIMIT));
}
} else if (i == 4) {
for (int l = 0; l < latitude_4.length; l++) {
x = (int) ((scrWidth / 360.0) * (90 + longitude_4[l]));
y = (int) ((scrHeight / 180.0) * (90 - latitude_4[l]));
mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));
}
}else if (i == 5) {
for (int l = 0; l < latitude_5.length; l++) {
x = (int) ((scrWidth / 360.0) * (90 + longitude_5[l]));
y = (int) ((scrHeight / 180.0) * (90 - latitude_5[l]));
mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));
}
}else if (i == 6) {
for (int l = 0; l < latitude_6.length; l++) {
x = (int) ((scrWidth / 360.0) * (90 + longitude_6[l]));
y = (int) ((scrHeight / 180.0) * (90 - latitude_6[l]));
mCircles.add(new CircleArea(x,y,RADIUS_LIMIT));
}
}
}
for (CircleArea circle : mCircles) {
canv.drawCircle(circle.getCenterX(),circle.getCenterY(),RADIUS_LIMIT, mCirclePaint);
}
// invalidate();;
}
@Override
public boolean onTouchEvent(final MotionEvent event) {
boolean handled = false;
CircleArea touchedCircle;
int xTouch;
int yTouch;
int pointerId;
int actionIndex = event.getActionIndex();
// get touch event coordinates and make transparent circle from it
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
xTouch = (int) event.getX(0);
yTouch = (int) event.getY(0);
touchedCircle = obtainTouchedCircle(xTouch, yTouch);
touchedCircle.centerX = xTouch;
touchedCircle.centerY = yTouch;
mCirclePointer.put(event.getPointerId(0), touchedCircle);
invalidate();
handled = true;
break;
case MotionEvent.ACTION_POINTER_DOWN:
Log.w(TAG, "Pointer down");
// It secondary pointers, so obtain their ids and check circles
pointerId = event.getPointerId(actionIndex);
xTouch = (int) event.getX(actionIndex);
yTouch = (int) event.getY(actionIndex);
// check if we've touched inside some circle
for(CircleArea circle: mCircles)
{
touchedCircle = obtainTouchedCircle(circle.getCenterX(), circle.getCenterY());
mCirclePointer.put(pointerId, touchedCircle);
touchedCircle.centerX = circle.getCenterX();
touchedCircle.centerY = circle.getCenterY();
}
invalidate();
handled = true;
break;
case MotionEvent.ACTION_MOVE:
final int pointerCount = event.getPointerCount();
Log.w(TAG, "Move");
for (actionIndex = 0; actionIndex < pointerCount; actionIndex++) {
// Some pointer has moved, search it by pointer id
pointerId = event.getPointerId(actionIndex);
for(CircleArea circle: mCircles)
{
xTouch = (int) event.getX(actionIndex);
yTouch = (int) event.getY(actionIndex);
float dx = xTouch - circle.getCenterX();
float dy = yTouch - circle.getCenterY();
float r = FloatMath.sqrt((dx * dx) + (dy * dy));
touchedCircle = mCirclePointer.get(pointerId);
if (null != touchedCircle) {
touchedCircle.centerX = xTouch;
touchedCircle.centerY = yTouch;
}
}
}
invalidate();
handled = true;
break;
case MotionEvent.ACTION_UP:
//clearCirclePointer();
invalidate();
handled = true;
break;
case MotionEvent.ACTION_POINTER_UP:
// not general pointer was up
pointerId = event.getPointerId(actionIndex);
mCirclePointer.remove(pointerId);
// invalidate();
handled = true;
break;
case MotionEvent.ACTION_CANCEL:
handled = true;
break;
default:
// do nothing
break;
}
return super.onTouchEvent(event) || handled;
}
private CircleArea obtainTouchedCircle(final int xTouch, final int yTouch) {
CircleArea touchedCircle = getTouchedCircle(xTouch, yTouch);
if (null == touchedCircle) {
touchedCircle = new CircleArea(xTouch, yTouch, RADIUS_LIMIT);
}
return touchedCircle;
}
private CircleArea getTouchedCircle(final int xTouch, final int yTouch) {
CircleArea touched = null;
for (CircleArea circle : mCircles) {
if ((circle.centerX - xTouch) * (circle.centerX - xTouch) + (circle.centerY - yTouch) * (circle.centerY - yTouch) <= circle.radius * circle.radius) {
touched = circle;
break;
}
}
return touched;
}
我很清楚我编写的破旧代码,但却无法生成关于如何将拖动的圆放置到最近的可用画布圆的数学计算。下图是一个有助于更多理解的截图。
需要注意的要点:
函数obtainTouchedCircle
和getTouchedCircle
至关重要。
MotionEvent.ACTION_MOVE
帮助我移动一个圆圈,但它的作用是它每次生成一个具有相同尺寸的新圆圈,这完全没问题但是当用户在某个地方拖拽并掉落时,它应放在最近的位置可用的圈子。
考虑下面的图像,黄色圆圈需要根据用户的意愿移动并放置在蓝色圆圈中。这是我的目标。
如果有人可以帮我计算出如何找出最近的可用圆圈,那么拖动会有很大的帮助!!!!提前谢谢。