How the onTap listener works in android map view even if the map view is moved.
actually i am rotating map view based on user direction.
i am getting bearing angle from sesor manager.
if angle is 0 the onTap works correctly on Pin.If the angle is changed say 20 onTap not working exactly on pin it works beside the pin after some space .
I taken on Rotate View inside that i taken mapview .Now i rotation rotateview after bearing changes.
RotateView setting bearing code
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
//if mHeading is zero its work otherwise onTap position is changing
canvas.rotate(mHeading, getWidth()/2, getHeight());
mCanvas.delegate = canvas;
super.dispatchDraw(mCanvas);
canvas.restore();
}
Overlay class
public class SonarOverlay1 extends ItemizedOverlay<OverlayItem>
{
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
private Context mContext;
public SonarOverlay1(Drawable defaultMarker,Context context) {
super(boundCenter(defaultMarker));
this.mContext=context;
populate();
}
#Override
protected OverlayItem createItem(int arg0) {
return mOverlays.get(arg0);
}
public void addOverlay(OverlayItem item) {
mOverlays.add(item);
populate();
}
#Override
public int size() {
//Log.e("overlay size..",""+mOverlays.size());
return mOverlays.size();
}
#Override
protected boolean onTap(int index) {
// TODO Auto-generated method stub
OverlayItem item = mOverlays.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.show();
return true;
}
}
Here while rotating map we have to rotate touch evnts also along with map using onDispatchTouch method
see below code
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
float[] coords = new float[] {
event.getX(), event.getY()
};
adjustCoords(coords, getRotation());
MotionEvent evt = MotionEvent.obtain(event.getDownTime(), event.getEventTime(), event
.getAction(), coords[0], coords[1], event.getPressure(), event.getSize(), event
.getMetaState(), event.getXPrecision(), event.getYPrecision(), event.getDeviceId(),
event.getEdgeFlags());
return super.dispatchTouchEvent(evt);
}
protected void adjustCoords(float[] coords, float deg) {
float x = coords[0];
float y = coords[1];
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
// convert to radians
float rad = (float) ((deg * Math.PI) / 180F);
float s = (float) Math.sin(rad);
float c = (float) Math.cos(rad);
// translate point back to origin:
x -= centerX;
y -= centerY;
// apply rotation
float tmpX = x * c - y * s;
float tmpY = x * s + y * c;
x = tmpX;
y = tmpY;
// translate point back:
x += centerX;
y += centerY;
coords[0] = x;
coords[1] = y;
}
Please refer below link
How to manage overlays in MapViewCompassDemo in android sdk samples
Related
Guys I know How to draw circle in android..But what I need is using onTouch method to rotate that circle depending on the user hand movement on that circle. Please help.
public class MainActivity extends Activity {
public class SampleView extends View {
Paint mPaint = new Paint();
private Animation anim;
public SampleView(Context context) {
super(context);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(10);
mPaint.setColor(Color.RED);
}
private void createAnimation(Canvas canvas) {
anim = new RotateAnimation(0, 360, getWidth()/2, getHeight()/2);
anim.setRepeatMode(Animation.RESTART);
anim.setRepeatCount(Animation.INFINITE);
anim.setDuration(10000L);
startAnimation(anim);
}
protected void onDraw(Canvas canvas) {
int cx = getWidth()/2; // x-coordinate of center of the screen
int cy = getHeight()/2; // y-coordinate of the center of the screen
// Starts the animation to rotate the circle.
if (anim == null)
createAnimation(canvas);
canvas.drawCircle(cx, cy, 150, mPaint); // drawing the circle.
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
}
First, we have to determine the angle between old and new position of circle (as below figure).
cos a = uv / (|u|*|v|)
The simple equation may be
double tx = touch_x - center_x, ty = touch_y - center_y;
double t_length = Math.sqrt(tx*tx + ty*ty);
double angle = Math.acos(ty / t_length);
Then to rotate your Canvas. you can use the code
canvas.rotate(angle);
Or you can use another method as
public int touch_x,touch_y,cx,cy;
public float angle=0;
#Override
public boolean onTouchEvent(MotionEvent event) {
touch_x = (int)event.getX();
touch_y = (int)event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
}
//double tx = touch_x - cx, ty = touch_y - cy;
// double t_length = Math.sqrt(tx*tx + ty*ty);
//angle = (float) Math.acos(ty / t_length);
double dx = touch_x - cx;
// Minus to correct for coord re-mapping
double dy = -touch_y - cy;
double inRads = Math.atan2(dy,dx);
// We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12 O'clock
if (inRads < 0)
inRads = Math.abs(inRads);
else
inRads = 2*Math.PI - inRads;
angle= (float) Math.toDegrees(inRads);
return false;
}
I try to make a activity and a View on the screen, cause the activity have the buttons which I need. My question is how can I do it, that when I start the app I see the buttons from the activity and the ball and the box from the view class??
How should I take the view in the layout?
that is the activity:
public class GameView extends Activity implements OnClickListener {
private Button bPAUSE;
private TextView tvTries;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameview);
initialize();
}
public void onClick(View v) {
}
public void initialize(){
bPAUSE = (Button) findViewById(R.id.button1);
bPAUSE.setOnClickListener(this);
tvTries = (TextView) findViewById(R.id.textView1);
}
}
that the View class:
public class BouncingBallView extends View {
private Ball ball;
private Box box;
// For touch inputs - previous touch (x, y)
private float previousX;
private float previousY;
// Constructor
public BouncingBallView(Context context) {
super(context);
box = new Box(0xff00003f); // ARGB
ball = new Ball(Color.GREEN);
// To enable keypad
this.setFocusable(true);
this.requestFocus();
// To enable touch mode
this.setFocusableInTouchMode(true);
}
// Called back to draw the view. Also called after invalidate().
#Override
protected void onDraw(Canvas canvas) {
// Draw the components
box.draw(canvas);
ball.draw(canvas);
// Update the position of the ball, including collision detection and reaction.
ball.moveWithCollisionDetection(box);
// Delay
try {
Thread.sleep(30);
} catch (InterruptedException e) { }
invalidate(); // Force a re-draw
}
// Called back when the view is first created or its size changes.
#Override
public void onSizeChanged(int w, int h, int oldW, int oldH) {
// Set the movement bounds for the ball
box.set(0, 0, w, h);
}
int touchCounter = 2;
#Override
public boolean onTouchEvent(MotionEvent event) {
float currentX = event.getX();
float currentY = event.getY();
float deltaX, deltaY;
float scalingFactor = 1.0f / ((box.xMax > box.yMax) ? box.yMax : box.xMax);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchCounter = 2;
if (currentX >= previousX) {
deltaX = currentX - previousX;
ball.speedX += deltaX * scalingFactor;
} else if (previousX >= currentX) {
deltaX = previousX - currentX;
ball.speedX += deltaX * scalingFactor;
} if (currentY >= previousY) {
deltaY = currentY - previousY;
ball.speedX += deltaY * scalingFactor;
} else if (previousY >= currentY) {
deltaY = previousY - currentY;
ball.speedY += deltaY * scalingFactor;
}
//vorherig(previous) - aktuell
break;
case MotionEvent.ACTION_UP:
touchCounter = 1;
// Modify rotational angles according to movement
break;
}
// Save current x, y
previousX = currentX;
previousY = currentY;
return true; // Event handled
}
}
I actually tries to do this in the activity class but the layout is missing...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View BouncingBallView= new BouncingBallView(this);
setContentView(BouncingBallView);
initialize();
}
During the past weeks I was looking for appropriate source code showing how to enable zoom and pan functionality on a custom view. All solutions that I found had some problems. For example the movement/zoom was not smooth enough or the view jumped around when releasing one finger after a scaling (two-finger) operation. So I came up with a modified solution that I want to share with you. Suggestions and enhancements are welcomed.
What’s different?
It is bad practice to calculate the difference (distance vector) on any interaction (pan, zoom) between each single events and use it to set new values. If you do so, the action does not look smooth and the view might flicker (jump around in some pixels). A better approach is to remember values when the action starts (onScaleBegin, touch-down) and calculate distances for each event in comparison to those start values.
You could handle finger indices in onTouchEvent to better distinguish between pan/move and zoom/scale interaction.
public class CanvasView extends SurfaceView implements SurfaceHolder.Callback {
final static String TAG = "CanvasView";
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
ScaleGestureDetector mScaleDetector;
InteractionMode mode;
Matrix mMatrix = new Matrix();
float mScaleFactor = 1.f;
float mTouchX;
float mTouchY;
float mTouchBackupX;
float mTouchBackupY;
float mTouchDownX;
float mTouchDownY;
Rect boundingBox = new Rect();
public CanvasView(Context context) {
super(context);
// we need to get a call for onSurfaceCreated
SurfaceHolder sh = this.getHolder();
sh.addCallback(this);
// for zooming (scaling) the view with two fingers
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
boundingBox.set(0, 0, 1024, 768);
paint.setColor(Color.GREEN);
paint.setStyle(Style.STROKE);
setFocusable(true);
// initial center/touch point of the view (otherwise the view would jump
// around on first pan/move touch
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
mTouchX = metrics.widthPixels / 2;
mTouchY = metrics.heightPixels / 2;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mScaleDetector.onTouchEvent(event);
if (!this.mScaleDetector.isInProgress()) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
// similar to ScaleListener.onScaleEnd (as long as we don't
// handle indices of touch events)
mode = InteractionMode.None;
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "Touch down event");
mTouchDownX = event.getX();
mTouchDownY = event.getY();
mTouchBackupX = mTouchX;
mTouchBackupY = mTouchY;
// pan/move started
mode = InteractionMode.Pan;
break;
case MotionEvent.ACTION_MOVE:
// make sure we don't handle the last move event when the first
// finger is still down and the second finger is lifted up
// already after a zoom/scale interaction. see
// ScaleListener.onScaleEnd
if (mode == InteractionMode.Pan) {
Log.d(TAG, "Touch move event");
// get current location
final float x = event.getX();
final float y = event.getY();
// get distance vector from where the finger touched down to
// current location
final float diffX = x - mTouchDownX;
final float diffY = y - mTouchDownY;
mTouchX = mTouchBackupX + diffX;
mTouchY = mTouchBackupY + diffY;
CalculateMatrix(true);
}
break;
}
}
return true;
}
#Override
public void onDraw(Canvas canvas) {
int saveCount = canvas.getSaveCount();
canvas.save();
canvas.concat(mMatrix);
canvas.drawColor(Color.BLACK);
canvas.drawRect(boundingBox, paint);
canvas.restoreToCount(saveCount);
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
// otherwise onDraw(Canvas) won't be called
this.setWillNotDraw(false);
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
}
void CalculateMatrix(boolean invalidate) {
float sizeX = this.getWidth() / 2;
float sizeY = this.getHeight() / 2;
mMatrix.reset();
// move the view so that it's center point is located in 0,0
mMatrix.postTranslate(-sizeX, -sizeY);
// scale the view
mMatrix.postScale(mScaleFactor, mScaleFactor);
// re-move the view to it's desired location
mMatrix.postTranslate(mTouchX, mTouchY);
if (invalidate)
invalidate(); // re-draw
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
float mFocusStartX;
float mFocusStartY;
float mZoomBackupX;
float mZoomBackupY;
public ScaleListener() {
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = InteractionMode.Zoom;
mFocusStartX = detector.getFocusX();
mFocusStartY = detector.getFocusY();
mZoomBackupX = mTouchX;
mZoomBackupY = mTouchY;
return super.onScaleBegin(detector);
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
mode = InteractionMode.None;
super.onScaleEnd(detector);
}
#Override
public boolean onScale(ScaleGestureDetector detector) {
if (mode != InteractionMode.Zoom)
return true;
Log.d(TAG, "Touch scale event");
// get current scale and fix its value
float scale = detector.getScaleFactor();
mScaleFactor *= scale;
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
// get current focal point between both fingers (changes due to
// movement)
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
// get distance vector from initial event (onScaleBegin) to current
float diffX = focusX - mFocusStartX;
float diffY = focusY - mFocusStartY;
// scale the distance vector accordingly
diffX *= scale;
diffY *= scale;
// set new touch position
mTouchX = mZoomBackupX + diffX;
mTouchY = mZoomBackupY + diffY;
CalculateMatrix(true);
return true;
}
}
}
I am trying to implement pinch zoom and drag using Android's gesture listener and scale listener. The problem is that when I perform pinch zoom, the image (which I am trying to zoom) bounces to a particular location. Also the zoom position is not centered.
The following code demonstrates what I am trying to achieve. Any idea why the image is jumping (and how to correct it) ?
public class CustomView extends View {
Bitmap image;
int screenHeight;
int screenWidth;
Paint paint;
GestureDetector gestures;
ScaleGestureDetector scaleGesture;
float scale = 1.0f;
float horizontalOffset, verticalOffset;
int NORMAL = 0;
int ZOOM = 1;
int DRAG = 2;
boolean isScaling = false;
float touchX, touchY;
int mode = NORMAL;
public CustomView(Context context) {
super(context);
//initializing variables
image = BitmapFactory.decodeResource(getResources(),
R.drawable.image_name);
//This is a full screen view
screenWidth = getResources().getDisplayMetrics().widthPixels;
screenHeight = getResources().getDisplayMetrics().heightPixels;
paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setColor(Color.WHITE);
scaleGesture = new ScaleGestureDetector(getContext(),
new ScaleListener());
gestures = new GestureDetector(getContext(), new GestureListener());
mode = NORMAL;
initialize();
}
//Best fit image display on canvas
private void initialize() {
float imgPartRatio = image.getWidth() / (float) image.getHeight();
float screenRatio = (float) screenWidth / (float) screenHeight;
if (screenRatio > imgPartRatio) {
scale = ((float) screenHeight) / (float) (image.getHeight()); // fit height
horizontalOffset = ((float) screenWidth - scale
* (float) (image.getWidth())) / 2.0f;
verticalOffset = 0;
} else {
scale = ((float) screenWidth) / (float) (image.getWidth()); // fit width
horizontalOffset = 0;
verticalOffset = ((float) screenHeight - scale
* (float) (image.getHeight())) / 2.0f;
}
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.drawColor(0, Mode.CLEAR);
canvas.drawColor(Color.WHITE);
if(mode == DRAG || mode == NORMAL) {
//This works perfectly as expected
canvas.translate(horizontalOffset, verticalOffset);
canvas.scale(scale, scale);
canvas.drawBitmap(image, getMatrix(), paint);
}
else if (mode == ZOOM) {
//PROBLEM AREA - when applying pinch zoom,
//the image jumps to a position abruptly
canvas.scale(scale, scale, touchX, touchY);
canvas.drawBitmap(image, getMatrix(), paint);
}
canvas.restore();
}
public class ScaleListener implements OnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactorNew = detector.getScaleFactor();
if (detector.isInProgress()) {
touchX = detector.getFocusX();
touchY = detector.getFocusY();
scale *= scaleFactorNew;
invalidate(0, 0, screenWidth, screenHeight);
}
return true;
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
isScaling = true;
mode=ZOOM;
return true;
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
mode = NORMAL;
isScaling = false;
}
}
public class GestureListener implements GestureDetector.OnGestureListener,
GestureDetector.OnDoubleTapListener {
#Override
public boolean onDown(MotionEvent e) {
isScaling = false;
return true;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
if (!isScaling) {
mode = DRAG;
isScaling = false;
horizontalOffset -= distanceX;
verticalOffset -= distanceY;
invalidate(0, 0, screenWidth, screenHeight);
} else {
mode = ZOOM;
isScaling = true;
}
return true;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
scaleGesture.onTouchEvent(event);
gestures.onTouchEvent(event);
return true;
}
}
Thanks in advance.
I have implemented this behaviour, and I used a matrix to handle all the zooming and scrolling (and rotation, in my case). It makes for neat code and works like clockwork.
Store a Matrix as a class member:
Matrix drawMatrix;
Edit: Store old focus point, used to get the focus shift during scaling.
float lastFocusX;
float lastFocusY;
Edit: Set lastFocus variables in onScaleBegin
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
lastFocusX = detector.getFocusX();
lastFocusY = detector.getFocusY();
return true;
}
Replace your onScale:
#Override
public boolean onScale(ScaleGestureDetector detector) {
Matrix transformationMatrix = new Matrix();
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
//Zoom focus is where the fingers are centered,
transformationMatrix.postTranslate(-focusX, -focusY);
transformationMatrix.postScale(detector.getScaleFactor(), detector.getScaleFactor());
/* Adding focus shift to allow for scrolling with two pointers down. Remove it to skip this functionality. This could be done in fewer lines, but for clarity I do it this way here */
//Edited after comment by chochim
float focusShiftX = focusX - lastFocusX;
float focusShiftY = focusY - lastFocusY;
transformationMatrix.postTranslate(focusX + focusShiftX, focusY + focusShiftY);
drawMatrix.postConcat(transformationMatrix);
lastFocusX = focusX;
lastFocusY = focusY;
invalidate();
return true;
}
Similarly in onScroll:
#Override
public boolean onScroll(MotionEvent downEvent, MotionEvent currentEvent,
float distanceX, float distanceY) {
drawMatrix.postTranslate(-distanceX, -distanceY);
invalidate();
return true;
}
in onDraw; Draw with your drawMatrix:
canvas.drawBitmap(image, drawMatrix, paint);
Happy coding!
All I want rotate image in particular angle as like below image. I have code for rotation but it rotate 360 degree but I want it only for particular degrees and get the selected number which is upper side of dial.
below is my code.
My custom View this work fine but lake of perfomance.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector.OnGestureListener;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class MyDialView extends View implements OnGestureListener{
private static Bitmap bimmap;
private static Paint paint;
private static Rect bounds;
private int totalNicks = 100;
private int currentNick = 0;
private GestureDetector gestureDetector;
private float dragStartDeg = Float.NaN;
float dialerWidth = 0,dialerHeight = 0;
private static Paint createDefaultPaint() {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
return paint;
}
private float xyToDegrees(float x, float y) {
float distanceFromCenter = PointF.length((x - 0.5f), (y - 0.5f));
if (distanceFromCenter < 0.1f
|| distanceFromCenter > 0.5f) { // ignore center and out of bounds events
return Float.NaN;
} else {
return (float) Math.toDegrees(Math.atan2(x - 0.5f, y - 0.5f));
}
}
public final float getRotationInDegrees() {
return (360.0f / totalNicks) * currentNick;
}
public final void rotate(int nicks) {
currentNick = (currentNick + nicks);
if (currentNick >= totalNicks) {
currentNick %= totalNicks;
} else if (currentNick < 0) {
currentNick = (totalNicks + currentNick);
}
Log.e("Current nick", String.valueOf(currentNick));
if((currentNick > 80 || currentNick < 20)){
invalidate();
}
}
public MyDialView(Context context, AttributeSet attrs) {
super(context, attrs);
bimmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.out_round);
paint = createDefaultPaint();
gestureDetector = new GestureDetector(getContext(), this);
dialerWidth = bimmap.getWidth() /2.0f;
dialerHeight = bimmap.getHeight() / 2.0f;
bounds = new Rect();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.getClipBounds(bounds);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
//{
canvas.translate(bounds.left, bounds.top);
float rotation = getRotationInDegrees();
canvas.rotate(rotation, dialerWidth, dialerHeight);
canvas.drawBitmap(bimmap, 0,0,null);
//canvas.rotate(- rotation, dialerWidth, dialerHeight);
//}
canvas.restore();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
} else {
return super.onTouchEvent(event);
}
}
//Gesture detector methods
#Override
public boolean onDown(MotionEvent e) {
float x = e.getX() / ((float) getWidth());
float y = e.getY() / ((float) getHeight());
dragStartDeg = xyToDegrees(x, y);
//Log.d("deg = " , ""+dragStartDeg);
if (! Float.isNaN(dragStartDeg)) {
return true;
} else {
return false;
}
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
#Override
public void onLongPress(MotionEvent e) {
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
if (! Float.isNaN(dragStartDeg)) {
float currentDeg = xyToDegrees(e2.getX() / getWidth(),
e2.getY() / getHeight());
if (! Float.isNaN(currentDeg)) {
float degPerNick = 360.0f / totalNicks;
float deltaDeg = dragStartDeg - currentDeg;
final int nicks = (int) (Math.signum(deltaDeg)
* Math.floor(Math.abs(deltaDeg) / degPerNick));
if (nicks != 0) {
dragStartDeg = currentDeg;
rotate(nicks);
}
}
return true;
} else {
return false;
}
}
#Override
public void onShowPress(MotionEvent e) {
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
}
I want 0-9 according to user selection & also allow user rotation to 0-9 not more rotation.
I have also check another code this is below.
dialer = (ImageView) findViewById(R.id.imageView_ring);
dialer.setOnTouchListener(new MyOnTouchListener());
dialer.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// method called more than once, but the values only need to be initialized one time
if (dialerHeight == 0 || dialerWidth == 0) {
dialerHeight = dialer.getHeight();
dialerWidth = dialer.getWidth();
// resize
Matrix resize = new Matrix();
resize.postScale((float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getWidth(), (float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getHeight());
imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false);
// translate to the image view's center
float translateX = dialerWidth / 2 - imageScaled.getWidth() / 2;
float translateY = dialerHeight / 2 - imageScaled.getHeight() / 2;
matrix.postTranslate(translateX, translateY);
dialer.setImageBitmap(imageScaled);
dialer.setImageMatrix(matrix);
Log.e("Rotation degree :"+rotationDegrees, String.valueOf(tickNumber));
}
}
});
int tickNumber = 0;
private void rotateDialer(float degrees) {
//System.out.println("Rotation Done :: "+rotationDone);
// if(!rotationDone) {
this.rotationDegrees += degrees;
this.rotationDegrees = this.rotationDegrees % 360;
tickNumber = (int)this.rotationDegrees*100/360;
// It could be negative
if (tickNumber > 0) tickNumber = 100 - tickNumber;
//this.rotationDegrees = Math.abs(rotationDegrees);
this.tickNumber = Math.abs(tickNumber);
if(tickNumber < 20 || tickNumber > 80){
Log.e("Rotation degree :"+rotationDegrees, String.valueOf(tickNumber));
matrix.postRotate(degrees, dialerWidth / 2, dialerHeight / 2);
dialer.setImageMatrix(matrix);
}
// }
}
/**
* #return The angle of the unit circle with the image view's center
*/
private double getAngle(double xTouch, double yTouch) {
double delta_x = xTouch - (dialerWidth) /2;
double delta_y = (dialerHeight) /2 - yTouch;
double radians = Math.atan2(delta_y, delta_x);
double dx = xTouch - dWidth;
double dy = (dHeight - ((dialerHeight) /2)) - yTouch;
double dRadi = Math.atan2(dy, dx);
//Log.e("MY degree", String.valueOf( Math.toDegrees(dRadi)));
//return Math.toDegrees(dRadi);
return Math.toDegrees(radians);
}
/**
* Simple implementation of an {#link OnTouchListener} for registering the dialer's touch events.
*/
private class MyOnTouchListener implements OnTouchListener {
private double startAngle;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// reset the touched quadrants
/*for (int i = 0; i < quadrantTouched.length; i++) {
quadrantTouched[i] = false;
}*/
//allowRotating = false;
startAngle = getAngle(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
/*double rotationAngleRadians = Math.atan2(event.getX() - (dialer.getWidth() / 2 ), ( (dialer.getHeight() / 2 ) - event.getY()));
double angle = (int) Math.toDegrees(rotationAngleRadians);
Log.i("gg", "rotaion angle"+angle);*/
double currentAngle = getAngle(event.getX(), event.getY());
//if(currentAngle < 130 || currentAngle < 110){
//Log.e("Start angle :"+startAngle, "Current angle:"+currentAngle);
rotateDialer((float) (startAngle - currentAngle));
startAngle = currentAngle;
//}
//Log.e("MOVE start Degree:"+startAngle, "Current Degree :"+currentAngle);
break;
case MotionEvent.ACTION_UP:
//allowRotating = true;
break;
}
// set the touched quadrant to true
//quadrantTouched[getQuadrant(event.getX() - (dialerWidth / 2), dialerHeight - event.getY() - (dialerHeight / 2))] = true;
//detector.onTouchEvent(event);
return true;
}
}
I do not understand your problem. The code below rotate the image 48 degrees.
ImageView dialer = (ImageView) findViewById(R.id.imageView_ring);
int degrees = 48;
Matrix matrix = new Matrix();
matrix.setRotate(degrees);
Bitmap bmpBowRotated = Bitmap.createBitmap(imageOrginal, 0, 0, imageOrginal.getWidth(),imageOrginal.getHeight(), matrix, false);
dialer.setImageBitmap(bmpBowRotated);
Hi Girish there is a class Named RotateAnimation by using this class u can easily do it
look Example like
RotateAnimation r = new RotateAnimation(0f, -90f,200,200); // HERE
r.setStartOffset(1000);
r.setDuration(1000);
r.setFillAfter(true); //HERE
animationSet.addAnimation(r);
I would like to first know what will be there for deployment? Does it allow manipulation Evenets? if yes then you get handle ManipulationStatring and ManipulationDelta Event to rotate the element.
If the same is not the case where Manipulation is not available then you can try RenderTransformation property with RorateTransform of the element is you are working with WPf.
I was able to achieve this by doing few of the following tweaks on your code
Making user click exactly on the arrow always to get the initial angle at which the arrow is placed, in your case 90 degree, else return false
Also save the angle at which the user removed his finger and use that angle as the initial value for his next touch ,like if he placed arrow at 100 deg make that his initial touch position to activate rotation again
Now for checking his answer take the angle at which your numbers 0 to 9 are placed ,im guessing your values take 120 deg from 0 to 9, divide that angle by 10, you can easily find out what angle represents what value and get your result
Also touching exactly at 90deg to begin rotation is very irritating, so always check for value which is bw 90+4 and 90-4 to begin, but always use the 90 as your start angle