How to make draggable and zoomable image in android? - java

I'm currently creating my own game and I'm finding a way to recreate some sort of Clash of Clans kind of functionality where you can zoom in and out and drag the view of the screen these is what so far, I've done and it's kind of close to it I guess any other recommendations.
Functionality for it to zoom
image = (ImageView) findViewById(R.id.imageView);
sgd = new ScaleGestureDetector(this, new ScaleListener());
#Override
public boolean onTouchEvent(MotionEvent event) {
sgd.onTouchEvent(event);
return super.onTouchEvent(event);
}
class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
#Override
public boolean onScale(ScaleGestureDetector detector) {
FACTOR *= detector.getScaleFactor();
FACTOR = Math.max(.01f,Math.min(FACTOR, 10.f));
image.setScaleX(FACTOR);
image.setScaleY(FACTOR);
return true;
}
}
For it to drag
image.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getActionMasked()) {
//checks if the user place finger in the screen
case MotionEvent.ACTION_DOWN:
xDown = motionEvent.getX();
yDown = motionEvent.getY();
break;
//checks if the user moves thier finger
case MotionEvent.ACTION_MOVE:
float movedX, movedY;
movedX = motionEvent.getX();
movedY = motionEvent.getY();
//calculate how much the user move their fingers
float distanceX = movedX - xDown;
float distanceY = movedY - yDown;
//will move the view to that position
image.setX(image.getX() + distanceX);
image.setY(image.getY() + distanceY);
break;
}
return true;
}
});
}

Related

How do drag an object around on the screen on Android? I don't know how to integrate the example onTouchEvent() code on Android doc website

I simply want to touch and drag/move an object around on the screen.
I know there are plenty of given codes out there, using surface holder and imageview matrix. But these codes are not well notated, and I don't know what is going on. I want to just copy and paste them into my own code.
I know there is this documentation on Android Dev website that teaches you how to drag and scale. But for dragging, it only gives an example for the onTouchEvent(), but I don't how I can integrate this method into my MainActivity.java and activity_main.xml files. Specically, in the code snippet, there are mPosX and mPosY, and I don't know how to use these global variables.
I tried creating a new class extending View class and put onTouchEvent().
I know you can use onDraw() and override it to utilize mPosX and mPosY to redraw the object every time your finger moves, but how exactly i don't know. I need some example codes implementing onDraw().
This is the code snippet I am talking about:
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = MotionEventCompat.getActionMasked(ev);
switch (action) {
case MotionEvent.ACTION_DOWN: {
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);
// Remember where we started (for dragging)
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer (for dragging)
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex =
MotionEventCompat.findPointerIndex(ev, mActivePointerId);
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);
// Calculate the distance moved
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
// Remember this touch position for the next move event
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex);
mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex);
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
}
break;
}
}
return true;
}
Create a class MoveViewTouchListener
public class MoveViewTouchListener
implements View.OnTouchListener
{
private GestureDetector mGestureDetector;
private View mView;
public MoveViewTouchListener(View view)
{
mGestureDetector = new GestureDetector(view.getContext(), mGestureListener);
mView = view;
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
return mGestureDetector.onTouchEvent(event);
}
private GestureDetector.OnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener()
{
private float mMotionDownX, mMotionDownY;
#Override
public boolean onDown(MotionEvent e)
{
mMotionDownX = e.getRawX() - mView.getTranslationX();
mMotionDownY = e.getRawY() - mView.getTranslationY();
Log.d("imageview"," down");
return true;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
mView.setTranslationX(e2.getRawX() - mMotionDownX);
mView.setTranslationY(e2.getRawY() - mMotionDownY);
if((distanceX==0)&&(distanceY==0))
{
Log.d("imageview"," zoomed");
}
return true;
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
Log.d("imageview"," tapped");
return true;
}
};
}
In activity call:
ImageView imageView= findViewById(R.id.imageView);
imageView.setOnTouchListener(new MoveViewTouchListener(imageView));

How to handle Two ToucheventListener calls on the same View? Android

I have a library which handles onTouchListener Events for a ImageView.
view.setOnTouchListener(new View.OnTouchListener() {
int lastAction;
float dX = 0;
float dY = 0;
int DELTA = 50;
private static final int MAX_CLICK_DURATION = 200;
private long pressStartTime;
#Override
public boolean onTouch(View view, final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
pressStartTime = System.currentTimeMillis();
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
lastAction = MotionEvent.ACTION_DOWN;
break;
case MotionEvent.ACTION_UP:
if (lastAction == MotionEvent.ACTION_DOWN) {
break;
}
break;
case MotionEvent.ACTION_MOVE:
lastAction = MotionEvent.ACTION_MOVE;
break;
}
return false;
}
});
And then once installing the library into my app i also wanted to set my own onTouchEvent for that ImageView.
view.setOnTouchListener(new new View.OnTouchListener(){});
The problem is that only the library touchListener event gets called and the app one is lost/neglected. If I remove the library then the app touch event gets called. How can I make it so that both the library and the app touchListeners are called?

Drag and fling map

Hello,
I am trying to implement dynamic map (View) into my application and I need to make it's movement behave like Google Map has. So It has to do both, scroll and fling. (I have reasons for not using the actual Google Maps).
At First time, I handled dragging and flinging of map by it's Scroll. But it jittered, because void View.setScrollX(int) can't have parameter of float and so it isn't smooth enough.
At Second, I tried Translation for moving of the map, but even when dragging alone was working and fling alone was working, together it did strange behaviour on fling.
My question is: How to make Scroll and Fling work together well? I will be glad of every advice or snipped of code :)
This is the second solution:
ImageView img;
String msg = "My LOG";
float firstPosX = 0;
float firstPosY = 0;
int touchCount;
FlingAnimation flingAnimX;
FlingAnimation flingAnimY;
GestureDetector gestureDetector;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView) findViewById(R.id.imageView);
gestureDetector = new GestureDetector(getApplicationContext(), mGestureListener);
img.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
touchCount = event.getPointerCount();
//Stops Fling, so on the new touch it dont continue
if (flingAnimX != null) {
flingAnimX.cancel();
}
if (flingAnimY != null) {
flingAnimY.cancel();
}
if (touchCount == 1) {
float deltaPosX = 0;
float deltaPosY = 0;
if (event.getAction() == MotionEvent.ACTION_DOWN) {
firstPosX = event.getX();
firstPosY = event.getY();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
deltaPosX = -firstPosX + event.getX();
deltaPosY = -firstPosY + event.getY();
img.setTranslationX(deltaPosX + img.getTranslationX());
img.setTranslationY(deltaPosY + img.getTranslationY());
}
}
gestureDetector.onTouchEvent(event);
return true;
}
});
}
GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
if (touchCount == 1) {
flingAnimX = new FlingAnimation(img, DynamicAnimation.TRANSLATION_X)
.setStartVelocity(velocityX);
flingAnimX.start();
flingAnimY = new FlingAnimation(img, DynamicAnimation.TRANSLATION_Y)
.setStartVelocity(velocityY);
flingAnimY.start();
}
return true;
}
};

Resize ImageView with only one finger movement instead of two

I'm trying to change an ImageView's height with only one finger movement (upside or downside). The code below changes height with two fingers (like pinching or reverse). How can I modify this code to do what I want? Thanks.
public class MainActivity extends Activity {
private ImageView iv;
private Matrix matrix = new Matrix();
private float scale = 1f;
private ScaleGestureDetector SGD;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = iv=(ImageView)findViewById(R.id.imageView);
SGD = new ScaleGestureDetector(this, new ScaleListener());
}
public boolean onTouchEvent(MotionEvent ev) {
SGD.onTouchEvent(ev);
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
{
#Override
public boolean onScale(ScaleGestureDetector detector) {
scale *= detector.getScaleFactor();
scale = Math.max(0.1f, Math.min(scale, 5.0f));
matrix.setScale(1, scale);
iv.setImageMatrix(matrix);
return true;
}
}
}
Use GestureDetector for scroll:
#Bind(R.id.container)
ViewGroup container;
#Bind(R.id.image)
ImageView image;
private GestureDetectorCompat detector;
private float yscale = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ButterKnife.bind(this);
image.setScaleType(ImageView.ScaleType.MATRIX);
detector = new GestureDetectorCompat(this, new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Matrix m = new Matrix();
yscale += distanceY / container.getHeight();
m.setScale(1, yscale, 0, 0);
image.setImageMatrix(m);
return true;
}
});
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return detector.onTouchEvent(event);
} detector.onTouchEvent(event);
}
change
public boolean onTouchEvent(MotionEvent ev) {
SGD.onTouchEvent(ev);
return true;
}
to
public boolean onTouchEvent(MotionEvent ev) {
switch(ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN, case MotionEvent.ACTION_UP:
SGD.onTouchEvent(ev);
break;
return true;
}
This code snipet should help you to detect up and down
private VelocityTracker mVelocityTracker = null;
#Override
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int action = event.getActionMasked();
int pointerId = event.getPointerId(index);
switch(action) {
case MotionEvent.ACTION_DOWN:
if(mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
}
else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
}
// Add a user's movement to the tracker.
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
// When you want to determine the velocity, call
// computeCurrentVelocity(). Then call getXVelocity()
// and getYVelocity() to retrieve the velocity for each pointer ID.
mVelocityTracker.computeCurrentVelocity(1000);
// Log velocity of pixels per second
// Best practice to use VelocityTrackerCompat where possible.
Log.d("", "X velocity: " +
VelocityTrackerCompat.getXVelocity(mVelocityTracker,
pointerId));
Log.d("", "Y velocity: " +
VelocityTrackerCompat.getYVelocity(mVelocityTracker,
pointerId));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Return a VelocityTracker object back to be re-used by others.
mVelocityTracker.recycle();
break;
}
return true;
}

Rotating an image with onTouchListener without scaling it

I have got this simple code to rotate an image with onTouchListener, but it seems to be zooming in and out on the image as well. I am really new to using onTouchListener. Could someone tell me what is happening, or how to fix this. Anything helps thanks:)
public class MainActivity extends Activity implements OnTouchListener {
private ImageView dialer;
private float y=0;
public boolean onTouch(View v, MotionEvent event) {
double r=Math.atan2(event.getX()-dialer.getWidth()/2, dialer.getHeight()/2-event.getY());
int rotation=(int)Math.toDegrees(r);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
//x=event.getX();
y=event.getY();
updateRotation(rotation);
break;
case MotionEvent.ACTION_UP:
break;
}//switch
return true;
}//onTouch
private void updateRotation(double rot){
float newRot= new Float(rot);
Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.round_button_big);
Matrix matrix= new Matrix();
matrix.postRotate(newRot,bitmap.getWidth()/2,bitmap.getHeight()/2);
if(y>250){
Bitmap reDrawnBitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
dialer.setImageBitmap(reDrawnBitmap);
}
else{
Bitmap reDrawnBitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
dialer.setImageBitmap(reDrawnBitmap);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dialer = (ImageView) findViewById(R.id.image);
dialer.setOnTouchListener(this);
}//onCreate
}
Try to use this code on touch 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 currentAngle = getAngle(event.getX(), event.getY());
rotateDialer((float) (startAngle - currentAngle));
startAngle = 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;
And here you can find an example :http://code.tutsplus.com/tutorials/android-sdk-creating-a-rotating-dialer--mobile-8868

Categories

Resources