I am trying to write a simple proof of concept app that allows a user to rotate minute hand of a clock. I am having hard time coming up with the right logic for OnTouchEvent.
So far I have the following code:
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
//find an approximate angle between them.
float dx = x-cx;
float dy = y-cy;
double a=Math.atan2(dy,dx);
this.degree = Math.toDegrees(a);
this.invalidate();
}
return true;
}
protected void onDraw(Canvas canvas) {
super .onDraw(canvas);
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
int availableWidth = getRight() - getLeft();
int availableHeight = getBott开发者_JAVA技巧om() - getTop();
int x = availableWidth / 2;
int y = availableHeight / 2;
cx = x;
cy = y;
final Drawable dial = mDial;
int w = dial.getIntrinsicWidth() + 100;
int h = dial.getIntrinsicHeight() + 100;
boolean scaled = false;
if (availableWidth < w || availableHeight < h) {
scaled = true;
float scale = Math.min((float) availableWidth / (float) w, (float) availableHeight / (float) h);
canvas.save();
canvas.scale(scale, scale, x, y);
}
if (changed)
{
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
dial.draw(canvas);
canvas.save();
float hour = mHour / 12.0f * 360.0f;
canvas.rotate(hour, x, y);
final Drawable hourHand = mHourHand;
if (changed) {
w = hourHand.getIntrinsicWidth() + 30;
h = hourHand.getIntrinsicHeight() + 30;
hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
hourHand.draw(canvas);
canvas.restore();
canvas.save();
float minute = mMinutes / 60.0f * 360.0f;
if (bearing == 0)
{
canvas.rotate(minute, x, y);
}
else
{
canvas.rotate((float)bearing, x, y);
}
final Drawable minuteHand = mMinuteHand;
if (changed) {
w = minuteHand.getIntrinsicWidth() + 30;
h = minuteHand.getIntrinsicHeight() + 30;
minuteHand.setBounds(x - w, y - h, x + w, y + h);
}
minuteHand.draw(canvas);
canvas.restore();
if (scaled) {
canvas.restore();
}
}
Then based on that, my OnDraw method rotates the minute hand to the specified "this.degree"(just calls canvas.rotate). I am assuming my math is off here. I tried to follow the example here: Calculate angle for rotation in Pie Chart, but that's still not rotating the minute hand correctly. Any help would be appreciated.
The math looks correct. Your calculations should give you the angle of the touch event, where a touch that is to the exact right of the center point should give you 0 degrees.
A few things to watch out for
- Make sure that you're rotating in the correct direction. It is hard to keep this straight, and thus easy to screw it up
- Make sure that you're taking into account that a value of 0 means that the minute hand should be pointing to the right. For example, if you start out with a minute hand that is pointing upwards, you would have to add/subtract 90 degrees to the result of your calculation (depending on the direction of rotation - not sure which is correct offhand)
- Make sure that (cx, cy) is the center point around which you want to calculate the angle
- When rotating, you'll need to either use the 3 arg
Canvas.rotate(float, float, float)
method, or add an additional translation seperately, to make sure that you are rotating around the correct point. Without any translation, it will rotate around (0,0) (the top left corner of the view)
More on rotation: Rotation always happens around the "current" (0,0) point. By "current", I mean the (0,0) point after the current matrix has been applied. When you first enter onDraw, the (0,0) point should be the upper-left corner of the view. Whenever you apply a translation/scaling/etc, you will potentially change where the (0,0) point is, relative to the view.
I think something like the following should work, in regards to setting the correct center of rotation:
//first we save the initial matrix, so we can easily get
//back to this state after we're done rotating
canvas.save();
//I *think* you need to negate the center offsets here,
//because you are conceptually moving the canvas, rather
//than moving the center directly
canvas.translate(-cx, -cy);
//<perform the rotation and draw the clock hand>
//...
//and now restore the matrix back to the initial state
canvas.restore();
Your calculation is good for measuring angle for minutes hand to rotate in corresponding quadrants in analog clock... here with little bit changes can make either minutes or hours hand to rotate at the touch position....call the below method in onTouch() method for action move
public float getRotationAngle(float x, float y) {
float dx = x - cx;
float dy = y - cy;
double a = Math.atan2(dy, dx);
double degree = Math.toDegrees(a)+90;
if(angle<0){
degree=degree+360;
}
return (float) degree;
}
i have this approach with as vectors concept for calculating the angle but if little bit more than your code if u want i will give that logic....
精彩评论