我在创建three circle and lines between them
时正在学习自定义视图,并且成功。我该如何使这些圈子成为可拖动对象。
首先,我想知道我使用onTouch()在圆圈内单击,然后相应地更新了这些圆圈的位置。
MyDrawingView
public class CustomDrawing extends View {
private static final String TAG = "CustomDrawing";
private Paint circlePaint;
private Paint linePaint;
private Paint textPaint;
private int centerX,centerY;
private float circleSize = 80;
public CustomDrawing(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setFocusable(true);
setFocusableInTouchMode(true);
setupPaint();
}
private void setupPaint() {
circlePaint = new Paint();
circlePaint.setColor(Color.BLACK);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeWidth(5);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.ROUND);
circlePaint.setStrokeCap(Paint.Cap.ROUND);
linePaint = new Paint();
linePaint.setColor(Color.WHITE);
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth((float) 1.5);;
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(60);
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setFakeBoldText(true);
}
@Override
protected void onDraw(Canvas canvas) {
///super.onDraw(canvas);
centerX = canvas.getWidth()/2;
centerY = canvas.getHeight()/2;
//Top Left Circle
canvas.drawCircle(circleSize, circleSize, 80, circlePaint);
canvas.drawText("LC",circleSize,getyPositionOfText(circleSize,textPaint),textPaint);
//Center Circle
circlePaint.setColor(Color.GREEN);
canvas.drawCircle(centerX, centerY, circleSize, circlePaint);
////int yPos = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2)) ;
//((textPaint.descent() + textPaint.ascent()) / 2) is the distance from the baseline to the center.
canvas.drawText("CC",centerX,getyPositionOfText(canvas.getHeight()/2,textPaint),textPaint);
///canvas.drawText("CC",50,50,20,20,textPaint);
//Bottom Right Circle
circlePaint.setColor(Color.BLACK);
canvas.drawCircle(canvas.getWidth() - circleSize, canvas.getHeight() - circleSize, 80, circlePaint);
//Center to Left TOP and Center to Right TOP LINE
canvas.drawLine(centerX,centerY,circleSize,circleSize,linePaint);//center to top left
canvas.drawLine(centerX,centerY,canvas.getWidth() - circleSize,circleSize,linePaint);//center to top right
//Center to Left BOTTOM and Center to Right BOTTOM LINE
linePaint.setColor(Color.BLACK);
canvas.drawLine(centerX,centerY, circleSize,
canvas.getHeight() - circleSize,linePaint);// center to bottom left
canvas.drawLine(centerX,centerY,canvas.getWidth() - circleSize,
canvas.getHeight() - circleSize,linePaint);// center to bottom right
linePaint.setColor(Color.WHITE);
canvas.drawLine(centerX,centerY,circleSize,canvas.getHeight()/2,linePaint);
linePaint.setColor(Color.BLACK);
canvas.drawLine(centerX,centerY,canvas.getWidth() - circleSize,canvas.getHeight()/2,linePaint);
//Left top to left bottom
canvas.drawLine(circleSize,circleSize,circleSize,canvas.getHeight() - circleSize,linePaint);
//Right t top to Right bottom
canvas.drawLine(canvas.getWidth() - circleSize,circleSize,canvas.getWidth() - circleSize,canvas.getHeight() - circleSize,linePaint);
linePaint.setColor(Color.GREEN);
canvas.drawLine(circleSize,circleSize,canvas.getWidth()-circleSize,circleSize,linePaint);
canvas.drawLine(circleSize,canvas.getHeight() -circleSize,canvas.getWidth()-circleSize,canvas.getHeight() -circleSize,linePaint);
}
private int getyPositionOfText(float yPositionOfText,Paint mPaint){
return (int) ((yPositionOfText) - ((mPaint.descent() + mPaint.ascent()) / 2)) ;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float pointX = event.getX();
float pointY = event.getY();
// Checks for the event that occurs
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_MOVE:
break;
default:
return false;
}
// Force a view to draw again
postInvalidate();
return true;
}
}
也提出改善建议。
要使视图可拖动,请使用以下代码。
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
dX = v.getX() - event.getRawX();
dY = v.getY() - event.getRawY();
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
v.animate()
.x(event.getRawX() + dX)
.y(event.getRawY() + dY)
.setDuration(0)
.start();
break;
}
invalidate();//reDraw
return true;
}
上面的代码对View正常工作。我该如何使用它来动画(拖动)圆?
然后为了检测任何位置inside circle ...
Math.sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)) < r
答案 0 :(得分:0)
似乎您在处理多点触控/绘图时可能会遇到问题。 Android Developer网站和Android Blog上都有一些有用的教程。
基于此,我能够创建一个示例,我认为它与您尝试实现的示例非常相似(没有完整的圆图-圆点通过单触产生):
public class CirclesDrawingView extends View {
private static final String TAG = "CirclesDrawingView";
/** Main bitmap */
private Bitmap mBitmap = null;
private Rect mMeasuredRect;
/** Stores data about single circle */
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;
}
@Override
public String toString() {
return "Circle[" + centerX + ", " + centerY + ", " + radius + "]";
}
}
/** Paint to draw circles */
private Paint mCirclePaint;
private final Random mRadiusGenerator = new Random();
// Radius limit in pixels
private final static int RADIUS_LIMIT = 100;
private static final int CIRCLES_LIMIT = 3;
/** All available circles */
private HashSet<CircleArea> mCircles = new HashSet<CircleArea>(CIRCLES_LIMIT);
private SparseArray<CircleArea> mCirclePointer = new SparseArray<CircleArea>(CIRCLES_LIMIT);
/**
* Default constructor
*
* @param ct {@link android.content.Context}
*/
public CirclesDrawingView(final Context ct) {
super(ct);
init(ct);
}
public CirclesDrawingView(final Context ct, final AttributeSet attrs) {
super(ct, attrs);
init(ct);
}
public CirclesDrawingView(final Context ct, final AttributeSet attrs, final int defStyle) {
super(ct, attrs, defStyle);
init(ct);
}
private void init(final Context ct) {
// Generate bitmap used for background
mBitmap = BitmapFactory.decodeResource(ct.getResources(), R.drawable.up_image);
mCirclePaint = new Paint();
mCirclePaint.setColor(Color.BLUE);
mCirclePaint.setStrokeWidth(40);
mCirclePaint.setStyle(Paint.Style.FILL);
}
@Override
public void onDraw(final Canvas canv) {
// background bitmap to cover all area
canv.drawBitmap(mBitmap, null, mMeasuredRect, null);
for (CircleArea circle : mCircles) {
canv.drawCircle(circle.centerX, circle.centerY, circle.radius, mCirclePaint);
}
}
@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:
// it's the first pointer, so clear all existing pointers data
clearCirclePointer();
xTouch = (int) event.getX(0);
yTouch = (int) event.getY(0);
// check if we've touched inside some circle
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
touchedCircle = obtainTouchedCircle(xTouch, yTouch);
mCirclePointer.put(pointerId, touchedCircle);
touchedCircle.centerX = xTouch;
touchedCircle.centerY = yTouch;
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);
xTouch = (int) event.getX(actionIndex);
yTouch = (int) event.getY(actionIndex);
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;
}
/**
* Clears all CircleArea - pointer id relations
*/
private void clearCirclePointer() {
Log.w(TAG, "clearCirclePointer");
mCirclePointer.clear();
}
/**
* Search and creates new (if needed) circle based on touch area
*
* @param xTouch int x of touch
* @param yTouch int y of touch
*
* @return obtained {@link CircleArea}
*/
private CircleArea obtainTouchedCircle(final int xTouch, final int yTouch) {
CircleArea touchedCircle = getTouchedCircle(xTouch, yTouch);
if (null == touchedCircle) {
touchedCircle = new CircleArea(xTouch, yTouch, mRadiusGenerator.nextInt(RADIUS_LIMIT) + RADIUS_LIMIT);
if (mCircles.size() == CIRCLES_LIMIT) {
Log.w(TAG, "Clear all circles, size is " + mCircles.size());
// remove first circle
mCircles.clear();
}
Log.w(TAG, "Added circle " + touchedCircle);
mCircles.add(touchedCircle);
}
return touchedCircle;
}
/**
* Determines touched circle
*
* @param xTouch int x touch coordinate
* @param yTouch int y touch coordinate
*
* @return {@link CircleArea} touched circle or null if no circle has been touched
*/
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;
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mMeasuredRect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
}
}
活动仅包含setContentView(R.layout.main),其中main.xml如下:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="@+id/scroller">
<com.example.TestApp.CirclesDrawingView
android:layout_width="match_parent"
android:layout_height="match_parent" />