I was searching for a way to display a very large scrollable image (3700x2400) at full size with ZoomIn/ZoomOut functionality.
The following question gave me a perfect solution:
Android imageView Zoom-in and Zoom-Out
package com.oryx.hanenberg;
/**
* Created by Jordy on 9-2-2017.
*/
import android.app.Activity;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class ZoomInZoomOut extends Activity implements OnTouchListener
{
private static final String TAG = "Touch";
#SuppressWarnings("unused")
private static final float MIN_ZOOM = 1f,MAX_ZOOM = 1f;
// These matrices will be used to scale points of the image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// The 3 states (events) which the user is trying to perform
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// these PointF objects are used to record the point(s) the user is touching
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
private ImageView imageView;
private int fieldImgXY[] = new int[2];
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
imageView = (ImageView) findViewById(R.id.map);
int[] posXY = new int[2];
imageView.getLocationOnScreen(posXY);
int x = posXY[0];
int y = posXY[1];
Log.d(TAG, TAG + " " + String.valueOf(x));
Log.d(TAG, TAG + " " + String.valueOf(y));
imageView.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
ImageView view = (ImageView) v;
view.setScaleType(ImageView.ScaleType.MATRIX);
float scale;
dumpEvent(event);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN: // first finger down only
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG"); // write to LogCat
mode = DRAG;
break;
case MotionEvent.ACTION_UP: // first finger lifted
System.out.println(event.getX());
System.out.println(event.getY());
break;
case MotionEvent.ACTION_POINTER_UP: // second finger lifted
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_POINTER_DOWN: // first and second finger down
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 5f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); // create the transformation in the matrix of points
}
else if (mode == ZOOM)
{
// pinch zooming
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 5f)
{
matrix.set(savedMatrix);
scale = newDist / oldDist; // setting the scaling of the
// matrix...if scale > 1 means
// zoom in...if scale < 1 means
// zoom out
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix); // display the transformation on screen
return true; // indicate event was handled
}
/*
* --------------------------------------------------------------------------
* Method: spacing Parameters: MotionEvent Returns: float Description:
* checks the spacing between the two fingers on touch
* ----------------------------------------------------
*/
private float spacing(MotionEvent event)
{
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
/*
* --------------------------------------------------------------------------
* Method: midPoint Parameters: PointF object, MotionEvent Returns: void
* Description: calculates the midpoint between the two fingers
* ------------------------------------------------------------
*/
private void midPoint(PointF point, MotionEvent event)
{
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
/** Show an event in the LogCat view, for debugging */
private void dumpEvent(MotionEvent event)
{
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE","POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP)
{
sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")");
}
sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++)
{
sb.append("#").append(i);
sb.append("(pid ").append(event.getPointerId(i));
sb.append(")=").append((int) event.getX(i));
sb.append(",").append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";");
}
sb.append("]");
Log.d("Touch Events ---------", sb.toString());
}
}
activity_map.xml
<LinearLayout android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity = "center_vertical|center_horizontal|center"
android:layout_weight="1"
>
<ImageView
android:id="#+id/map"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/bt_587f3ef7ccafa_bt_origineel"/>
</LinearLayout>
However, I want the touch events to register the X/Y-coordinates relative to the image. Now it's creating white space around the image when I'm zooming resulting false X/Y-coordinates. The X/Y-coordinates are also of the viewport, not of the entire content. How can I accomplish this?
You can get the top left corner of your Imageview as mentioned below:
int[] posXY = new int[2];
imageView.getLocationOnScreen(posXY);
With this and the touch coordinates you can calculate the point inside the ImageView as follows:
int touchX = (int) event.getX();
int touchY = (int) event.getY();
int imageX = touchX - posXY[0]; // posXY[0] is the X coordinate
int imageY = touchY - posXY[1]; // posXY[1] is the y coordinate
Related
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;
}
});
}
I have drag and drop imageView(multiple imageView with same object) in layout and after that ImageView onTouch it move around layout. but after move imageView it overlapping with each other, how do prevent overalapping image?
also every image object is same. here is my code :
public boolean onDrag(View view, DragEvent event) {
recyclerViewFloorTiles = findViewById(R.id.rvfloortiles);
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_ENDED:
break;
case DragEvent.ACTION_DROP:
dropX = event.getX();
dropY = event.getY();
final ObjectAdapter.DragData state = (ObjectAdapter.DragData) event.getLocalState();
final ImageView shape = (ImageView) LayoutInflater.from(this).inflate(
R.layout.layout_drag_image, dropContainer, false);
shape.setImageResource(state.item.getDrawableRes());
shape.setX(dropX - (float) state.width / 2);
shape.setY(dropY - (float) state.height / 2);
shape.getLayoutParams().width = state.width;
shape.getLayoutParams().height = state.height;
dropContainer.addView(shape);
shape.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
ImageView objectDropImage = new ImageView(DashboardActivity.this);
objectDropImage.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
dropContainer.addView(objectDropImage);
float newX, newY;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
dX = view.getX() - event.getRawX();
dY = view.getY() - event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
newX = event.getRawX() + dX;
newY = event.getRawY() + dY;
if ((newX <= 0 || newX >= screenWidth-view.getWidth()) || (newY <= 0 || newY >= screenHight-view.getHeight()))
{
break;
}
view.setX(newX);
view.setY(newY);
break;
}
return false;
}
});
}
break;
default:
break;
}
return true;
}
Edited: Adding the XML layout of my view (How to achieve flip animation android (GIF Added))
TopLayout : ivImage
BottomLayout : layoutL
I want to implement Vertical ViewPager as shown in the GIF image below. Implemented Vertical ViewPager but can't implement Flip Animation
Any Code snippet or Library
My Customized VerticalViewPager Class Implemented Vertical ViewPager with normal animation Motionevent in VerticalPageTransformer
public class VViewPager2 extends ViewPager {
String TAG = "VViewPager";
float x = 0;
float mStartDragX = 0;
private static final float SWIPE_X_MIN_THRESHOLD = 15; // Decide this magical number as per your requirement
private boolean disableSwipe = false;
public VViewPager2(#NonNull Context context) {
super(context);
init();
}
public VViewPager2(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
// setPageTransformer(true, new PagerTransformer());
}
private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (getAdapter() != null) {
if (getCurrentItem() >= 0 || getCurrentItem() < getAdapter().getCount()) {
swapXY(event);
final int action = event.getAction();
switch (action & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
mStartDragX = event.getX();
if (x < mStartDragX
&& (mStartDragX - x > SWIPE_X_MIN_THRESHOLD)
&& getCurrentItem() > 0) {
Log.i(TAG, "down " + x + " : " + mStartDragX + " : " + (mStartDragX - x));
setCurrentItem(getCurrentItem() - 1, true);
return true;
} else if (x > mStartDragX
&& (x - mStartDragX > SWIPE_X_MIN_THRESHOLD)
&& getCurrentItem() < getAdapter().getCount() - 1) {
Log.i(TAG, "up " + x + " : " + mStartDragX + " : " + (x - mStartDragX));
mStartDragX = 0;
setCurrentItem(getCurrentItem() + 1, true);
return true;
}
break;
}
} else {
mStartDragX = 0;
}
swapXY(event);
return !disableSwipe && super.onTouchEvent(swapXY(event));
}
return false;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = !disableSwipe && super.onInterceptTouchEvent(swapXY(event));
if ((event.getAction() & MotionEventCompat.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
x = event.getX();
}
swapXY(event); // return touch coordinates to original reference frame for any child views
return intercepted;
}
public void disableScroll(Boolean disableSwipe) {
//When disable = true not work the scroll and when disble = false work the scroll
this.disableSwipe = disableSwipe;
Log.d(TAG, "disableSwipe " + disableSwipe);
}
/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
private class VerticalPageTransformer implements PageTransformer {
private static final float MIN_SCALE = 0.75f;
#Override
public void transformPage(#NonNull View view, float position) {
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(-position * view.getWidth());
// set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
ScaleAnimation flipDown = new ScaleAnimation(1.0f, 1.0f, -1.0f, 0.0f, 1, 1);
flipDown.setDuration(500);
flipDown.setFillAfter(true); // If fillAfter is true, the transformation that this animation performed will persist when it is finished.
// view.startAnimation(flipDown);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
view.setAlpha(1);
// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);
//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
view.setScaleX(1);
view.setScaleY(1);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
}
I want to flip the screen between these Layouts From TOP & Bottom
<androidx.cardview.widget.CardView
app:cardCornerRadius="6dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true"
app:cardBackgroundColor="#color/White"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/ivImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="#string/activity_images"
android:scaleType="fitXY" />
<LinearLayout
android:id="#+id/layoutL"
android:layout_weight="5.5"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="8dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp">
<TextView
android:id="#+id/tvTTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="4dp"
android:textStyle="bold"
android:text="#string/Topic_Title"
android:textColor="#color/Black"
android:textSize="20sp" />
<TextView
android:id="#+id/postDetails"
android:textAllCaps="false"
android:text="text"
android:textSize="12sp"
android:layout_marginStart="4dp"
android:textStyle="normal"
android:textColor="#color/Silver"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/tvTopicDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:lineSpacingExtra="2dp"
android:text="#string/invalid_email_contactno"
android:textAllCaps="false"
android:textColor="#6D6D6D"
android:textSize="15sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
I want to create a layout like a given GIF, I tried so many animations but not worked perfectly for me.
Try below solution and set yourSecondView as gone in Xml.
yourButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final ObjectAnimator oa1 = ObjectAnimator.ofFloat(yourFirstView, "scaleY", 1f, 0f);
final ObjectAnimator oa2 = ObjectAnimator.ofFloat(yourSecondView, "scaleY", 0f, 1f);
oa1.setInterpolator(new DecelerateInterpolator());
oa1.setDuration(1000);
oa2.setInterpolator(new AccelerateDecelerateInterpolator());
oa2.setDuration(1000);
oa1.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
yourFirstView.setVisibility(View.GONE);
yourSecondView.setVisibility(View.VISIBLE);
oa2.start();
}
});
oa1.start();
}
});
Output
I hope this can help you!
I am working on a project in which user can move view with finger touch . It works but not accurate to the finger position. I am not asking the good code you have, but rather to wondering why my code make the view not fit to the finger. It's like the view have more margin about 20dp.Here's the code :
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/lyRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.zihadrizkyef.dragviewwithfinger.MainActivity">
<TextView
android:id="#+id/tvText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:text="Hello World!"/>
</LinearLayout>
MainActivity.java
package com.zihadrizkyef.dragviewwithfinger;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
ViewGroup lyRoot;
TextView tvText;
LinearLayout.LayoutParams layoutParams;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lyRoot = (ViewGroup)findViewById(R.id.lyRoot);
tvText = (TextView)findViewById(R.id.tvText);
layoutParams = (LinearLayout.LayoutParams)tvText.getLayoutParams();
lyRoot.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int)event.getRawX();
int y = (int)event.getRawY();
if (event.getAction() == MotionEvent.ACTION_MOVE) {
layoutParams.leftMargin = x;
layoutParams.topMargin = y;
tvText.setLayoutParams(layoutParams);
}
lyRoot.invalidate();
if (event.getAction() == MotionEvent.ACTION_UP) {
System.out.println("mouseX:"+x+" ; mouseY:"+y);
System.out.println("viewX:"+layoutParams.leftMargin+" ; viewY:"+layoutParams.topMargin);
}
return true;
}
}
You should use the dragged distance instead of the coordinates on screen.
layoutParams.leftMargin = layoutParams.leftMargin + deltaX;
layoutParams.topMargin = layoutParams.leftMargin + deltaY;
You can get the full solution from Android developers site
https://developer.android.com/training/gestures/scale.html#drag
You will have to adapt it to your needs. I adapted it a little.
// 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;
layoutParams.leftMargin += dx;
layoutParams.topMargin += dy;
tvText.setLayoutParams(layoutParams);
lyRoot.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;
}
I programming an android app that can drag image. Top and left of image in default mode is 0, 0. My question is how can I get top and left of visible image after drag.
Touch class:
public class Touch implements OnTouchListener {
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private static final float MIN_ZOOM = 1f;
private static final float MAX_ZOOM = 5f;
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private PointF start = new PointF();
private PointF mid = new PointF();
private float[] values = new float[9];
private int mode = NONE;
private float dx;
private float dy;
private float matrixX = 0;
private float matrixY = 0;
private float width = 0;
private float height = 0;
private float oldDistance = 1f;
public boolean onTouch(View view, MotionEvent event) {
ImageView imageView = (ImageView)view;
switch(event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDistance = spacing(event);
if(oldDistance > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
case MotionEvent.ACTION_MOVE:
if(mode == DRAG) {
matrix.set(savedMatrix);
matrix.getValues(values);
matrixX = values[Matrix.MTRANS_X];
matrixY = values[Matrix.MTRANS_Y];
width = values[Matrix.MSCALE_X] * imageView.getDrawable().getIntrinsicWidth();
height = values[Matrix.MSCALE_Y] * imageView.getDrawable().getIntrinsicHeight();
dx = event.getX() - start.x;
dy = event.getY() - start.y;
if(matrixY + dy > 0)
while(matrixY + dy > 0)
dy--;
if(matrixX + dx + width < imageView.getWidth())
while(matrixX + dx + width < imageView.getWidth())
dx++;
if(matrixY + dy + height < imageView.getHeight())
while(matrixY + dy + height < imageView.getHeight())
dy++;
if(matrixX + dx > 0)
while(matrixX + dx > 0)
dx--;
matrix.postTranslate(dx, dy);
}
else if(mode == ZOOM) {
float newDistance = spacing(event);
if(newDistance > 10f) {
matrix.set(savedMatrix);
float scale = newDistance / oldDistance;
matrix.getValues(values);
float currentScale = values[Matrix.MSCALE_X];
if(scale * currentScale > MAX_ZOOM)
scale = MAX_ZOOM / currentScale;
else if (scale * currentScale < MIN_ZOOM)
scale = MIN_ZOOM / currentScale;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
imageView.setImageMatrix(matrix);
return true;
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
point.set((event.getX(0) + event.getX(1)) / 2, (event.getY(0) + event.getY(1)) / 2);
}
}
Activity class:
public class RepositionTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reposition_test_layout);
imageView = (ImageView)findViewById(R.id.android_image);
imageView.setOnTouchListener(new Touch());
}
}
Layout xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/reposition_test_layout"
android:paddingLeft="20dp"
android:paddingTop="20dp"
android:paddingRight="20dp"
android:paddingBottom="20dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="#+id/android_image"
android:src="#drawable/android"
android:layout_width="300dp"
android:layout_height="300dp"
android:scaleType="matrix"
android:contentDescription="#string/android_image_description" >
</ImageView>
</LinearLayout>
Thanks for your help.
I finally solve the problem. When the user reposition the image, then we can save the matrix information in a file or db.
Activity class:
public class RepositionTestActivity extends Activity {
private ImageView imageView;
private Button button;
private SQLiteDatabase db;
private Cursor cursor;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reposition_test_layout);
imageView = (ImageView)findViewById(R.id.android_image);
button = (Button)findViewById(R.id.reposition_button);
ViewTreeObserver viewTreeObserver = imageView.getViewTreeObserver();
if(viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
db = openOrCreateDatabase("DB_DATING", MODE_PRIVATE, null);
db.execSQL("" +
"CREATE TABLE IF NOT EXISTS tbl_images (" +
" id INTEGER PRIMARY KEY AUTOINCREMENT," +
" name VARCHAR(50) UNIQUE NOT NULL," +
" scale_x FLOAT NOT NULL," +
" scale_y FLOAT NOT NULL," +
" trans_x FLOAT NOT NULL," +
" trans_y FLOAT NOT NULL" +
");");
cursor = db.query("tbl_images", new String[] {"name", "scale_x", "scale_y", "trans_x", "trans_y"}, "name = \"android\"", null, null, null, null);
imageView.setScaleType(ScaleType.MATRIX);
cursor.moveToNext();
if(cursor.getCount() > 0) {
Matrix matrix = new Matrix();
matrix.postScale(cursor.getFloat(1), cursor.getFloat(2));
matrix.postTranslate(cursor.getFloat(3), cursor.getFloat(4));
imageView.setImageMatrix(matrix);
}
imageView.setOnTouchListener(new Touch(imageView.getImageMatrix()));
button.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
float[] values = new float[9];
imageView.getImageMatrix().getValues(values);
ContentValues contentValues = new ContentValues();
contentValues.put("scale_x", values[Matrix.MSCALE_X]);
contentValues.put("scale_y", values[Matrix.MSCALE_Y]);
contentValues.put("trans_x", values[Matrix.MTRANS_X]);
contentValues.put("trans_y", values[Matrix.MTRANS_Y]);
if(cursor.getCount() > 0) {
long count = db.update("tbl_images", contentValues, "name = \"android\"", null);
Log.d("Update Count", "===========> " + count);
}
else {
contentValues.put("name", "android");
long count = db.insert("tbl_images", null, contentValues);
Log.d("Insert Count", "===========> " + count);
}
}
});
}
});
}
}
}