Does android have equivalent of UIScrollView? - android

Is there an equivalent in android of UIScrollView where I can slide an image around. Thank you.
Sorry I was not more specific. I need to slide in all directions. Androids ScrollView will not do this. I been using a WebView which works but it only works on 4.0 and higher it seems like.
This is what I came up with. I put my ImageView inside of a WebView and I assigned setOnTouchListener on ImageView. It seems to work well.
web = new WebView(this);
web.setVerticalScrollBarEnabled(false);
web.setHorizontalScrollBarEnabled(false);
web.setBackgroundColor(Color.RED);
web.setId(100);
RelativeLayout.LayoutParams layoutForContainer = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutForContainer.height = 300;
layoutForContainer.width = 300;
layoutForContainer.addRule(RelativeLayout.CENTER_IN_PARENT);
web.setLayoutParams(layoutForContainer);
layout.addView(web);
myImageView = new ImageView(this);
myImageView.setImageResource(R.drawable.myImage);
RelativeLayout.LayoutParams layoutForLargeImage = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutForLargeImage.height = (int) 768;
layoutForLargeImage.width = (int) 1024;
myImageView.setLayoutParams(layoutForLargeImage);
web.addView(myImageView);
myImageView.setOnTouchListener(new View.OnTouchListener() {
float downX, downY;
int scrollByX, scrollByY;
public boolean onTouch(View view, MotionEvent event) {
float currentX, currentY;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
currentX = event.getX();
currentY = event.getY();
scrollByX = (int)(downX - currentX);
scrollByY = (int)(downY - currentY);
myImageView.scrollBy(scrollByX, scrollByY);
downX = currentX;
downY = currentY;
break;
}
return true;
}
});

This question's almost a year old, but it's the top in a google search for this problem, so I thought I'd add some details.
If you're looking for a generic one direction view that can scroll, the other answers of using Android's built in ScrollView will work fine.
However, if you want the multidirectional aspect of iOS's UIScrollView, you'll have to design/use a custom view (or use a hack such as using a webview). An example implementation of a view that can do this can be found in a related question here:
View with horizontal and vertical pan/drag and pinch-zoom
Then depending on your tastes, you can modify it as needed, such as this implementation without the zooming (just the panning):
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.*;
public class MultiDirectionPanGroup extends ViewGroup {
private static final int INVALID_POINTER_ID = 1;
private int mActivePointerId = INVALID_POINTER_ID;
private float mPosX;
private float mPosY;
private Matrix mTranslateMatrix = new Matrix();
private Matrix mTranslateMatrixInverse = new Matrix();
private float mLastTouchX;
private float mLastTouchY;
private float mFocusY;
private float mFocusX;
private float[] mInvalidateWorkingArray = new float[6];
private float[] mDispatchTouchEventWorkingArray = new float[2];
private float[] mOnTouchEventWorkingArray = new float[2];
public MultiDirectionPanGroup(Context context) {
super(context);
mTranslateMatrix.setTranslate(0, 0);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
child.layout(l, t, l+child.getMeasuredWidth(), t + child.getMeasuredHeight());
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.translate(mPosX, mPosY);
super.dispatchDraw(canvas);
canvas.restore();
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mDispatchTouchEventWorkingArray[0] = ev.getX();
mDispatchTouchEventWorkingArray[1] = ev.getY();
mDispatchTouchEventWorkingArray = screenPointsToScaledPoints(mDispatchTouchEventWorkingArray);
ev.setLocation(mDispatchTouchEventWorkingArray[0],
mDispatchTouchEventWorkingArray[1]);
return super.dispatchTouchEvent(ev);
}
/**
* Although the docs say that you shouldn't override this, I decided to do
* so because it offers me an easy way to change the invalidated area to my
* likening.
*/
#Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
mInvalidateWorkingArray[0] = dirty.left;
mInvalidateWorkingArray[1] = dirty.top;
mInvalidateWorkingArray[2] = dirty.right;
mInvalidateWorkingArray[3] = dirty.bottom;
mInvalidateWorkingArray = scaledPointsToScreenPoints(mInvalidateWorkingArray);
dirty.set(Math.round(mInvalidateWorkingArray[0]), Math.round(mInvalidateWorkingArray[1]),
Math.round(mInvalidateWorkingArray[2]), Math.round(mInvalidateWorkingArray[3]));
location[0] *= mScaleFactor;
location[1] *= mScaleFactor;
return super.invalidateChildInParent(location, dirty);
}
private float[] scaledPointsToScreenPoints(float[] a) {
mTranslateMatrix.mapPoints(a);
return a;
}
private float[] screenPointsToScaledPoints(float[] a){
mTranslateMatrixInverse.mapPoints(a);
return a;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
mOnTouchEventWorkingArray[0] = ev.getX();
mOnTouchEventWorkingArray[1] = ev.getY();
mOnTouchEventWorkingArray = scaledPointsToScreenPoints(mOnTouchEventWorkingArray);
ev.setLocation(mOnTouchEventWorkingArray[0], mOnTouchEventWorkingArray[1]);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
mTranslateMatrix.preTranslate(dx, dy);
mTranslateMatrix.invert(mTranslateMatrixInverse);
mLastTouchX = x;
mLastTouchY = y;
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(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 = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
}

Obviously, there are many options like UIScrollView, (1) you can take HorizontalScrollView (2) you can take Viewpager.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<WebView
android:id="#+id/webview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>

you can do this using in android
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
</ScrollView>

Related

How to make Zoom on whole content in RecyclerView?

I need zoom in/out on whole content in RecyclerView.
In fact I need to resize all child views by width, and text inside each item.
public class ViewHolder {
Button btn;
...
}
When User make zoom in, the text of Button should be decrease down to 8sp and disappear if user continue zoom in.
So, now I have dilemma : what I need to do? Resize items in Adapter, or resize them in LayoutManager, and update whole adapter.
Both of scenarios seems affect an performance of visual effect, so I need help. Maybe you give me a better solution.
For state of 21/11/2016 I can't found any box-solution for this case.
So I decide write my own view and do remeasurement of visible views in each zoom scale factor change.
Which adapter do you use?
I've tried Horizontal LinearLayoutManager and do resize items inside adapter:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
final ViewGroup.LayoutParams layoutParams = viewHolder.rootView.getLayoutParams();
layoutParams.width = getItemWidth(position); //width calculation using current zoom level
layoutParams.height = mItemLayoutHeight;
viewHolder.rootView.setLayoutParams(layoutParams);
...
and setZoom(..) method of the activity/fragment looks like:
public void setZoom(float newValue) {
int dScroll = (int) ((ADAPTER_ZOOM - newValue) * getResources().getDisplayMetrics().widthPixels/2f); //assume you Recycler view uses whole display
ADAPTER_ZOOM = newValue;
resetBoundaries();
//
epgAdapter.notifyDataSetChanged();
//
epgRecyclerView.scrollBy(dScroll, 0);
}
But with my custom LayoutManager performance is bad, seems there is a list of optimisations inside the LinearLayoutManager
for complete implementation refer to :
github.com/mosayeb-masoumi/zoom_whole_recyclerview
user this code. it's working fine for zooming all content of recyclerview.
import android.content.Context;
import android.graphics.Canvas;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
/**
#author yogesh
* */
public class PinchRecyclerView extends RecyclerView {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
private float maxWidth = 0.0f;
private float maxHeight = 0.0f;
private float mLastTouchX;
private float mLastTouchY;
private float mPosX;
private float mPosY;
private float width;
private float height;
public PinchRecyclerView(Context context) {
super(context);
if (!isInEditMode())
mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
}
public PinchRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode())
mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
}
public PinchRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (!isInEditMode())
mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
#Override
public boolean onTouchEvent(#NonNull MotionEvent ev) {
super.onTouchEvent(ev);
final int action = ev.getAction();
mScaleDetector.onTouchEvent(ev);
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
/* this line is replaced because here came below isssue
java.lang.IllegalArgumentException: pointerIndex out of range
ref http://stackoverflow.com/questions/6919292/pointerindex-out-of-range-android-multitouch
*/
//final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
if (mPosX > 0.0f)
mPosX = 0.0f;
else if (mPosX < maxWidth)
mPosX = maxWidth;
if (mPosY > 0.0f)
mPosY = 0.0f;
else if (mPosY < maxHeight)
mPosY = maxHeight;
mLastTouchX = x;
mLastTouchY = y;
invalidate();
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 = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
canvas.restore();
}
#Override
protected void dispatchDraw(#NonNull Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
if (mScaleFactor == 1.0f) {
mPosX = 0.0f;
mPosY = 0.0f;
}
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
super.dispatchDraw(canvas);
canvas.restore();
invalidate();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 3.0f));
maxWidth = width - (width * mScaleFactor);
maxHeight = height - (height * mScaleFactor);
invalidate();
return true;
}
}
}
Code taken from this StackOverflow answer: Android change recycler view column no. on pinch zoom

Android: ImageView click is not get perfect after reset zoom

I have multiple dynamic images which is displayed on basis of X,Y,Height,Width. These images are bind with RelativeLayout and this layout is bind with my ZoomableViewGroup class. When I click on the image,the color is fill in it.
public class ZoomableViewGroup extends ViewGroup {
private Context mContext;
private static final int INVALID_POINTER_ID = 1;
private int mActivePointerId = INVALID_POINTER_ID;
private float mScaleFactor = 1;
private ScaleGestureDetector mScaleDetector;
private Matrix mScaleMatrix = new Matrix();
private Matrix mScaleMatrixInverse = new Matrix();
private float mPosX;
private float mPosY;
private Matrix mTranslateMatrix = new Matrix();
private Matrix mTranslateMatrixInverse = new Matrix();
private float mLastTouchX;
private float mLastTouchY;
private float mFocusY;
private float mFocusX;
private float[] mInvalidateWorkingArray = new float[6];
private float[] mDispatchTouchEventWorkingArray = new float[2];
private float[] mOnTouchEventWorkingArray = new float[2];
public ZoomableViewGroup(Context context) {
super(context);
this.mContext = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
mTranslateMatrix.setTranslate(0, 0);
mScaleMatrix.setScale(1, 1);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
child.layout(l, t, l + child.getMeasuredWidth(),
t + child.getMeasuredHeight());
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor, mFocusX, mFocusY);
super.dispatchDraw(canvas);
canvas.restore();
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mDispatchTouchEventWorkingArray[0] = ev.getX();
mDispatchTouchEventWorkingArray[1] = ev.getY();
mDispatchTouchEventWorkingArray = screenPointsToScaledPoints(mDispatchTouchEventWorkingArray);
ev.setLocation(mDispatchTouchEventWorkingArray[0],
mDispatchTouchEventWorkingArray[1]);
return super.dispatchTouchEvent(ev);
}
#Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
mInvalidateWorkingArray[0] = dirty.left;
mInvalidateWorkingArray[1] = dirty.top;
mInvalidateWorkingArray[2] = dirty.right;
mInvalidateWorkingArray[3] = dirty.bottom;
mInvalidateWorkingArray = scaledPointsToScreenPoints(mInvalidateWorkingArray);
dirty.set(Math.round(mInvalidateWorkingArray[0]),
Math.round(mInvalidateWorkingArray[1]),
Math.round(mInvalidateWorkingArray[2]),
Math.round(mInvalidateWorkingArray[3]));
location[0] *= mScaleFactor;
location[1] *= mScaleFactor;
return super.invalidateChildInParent(location, dirty);
}
private float[] scaledPointsToScreenPoints(float[] a) {
mScaleMatrix.mapPoints(a);
mTranslateMatrix.mapPoints(a);
return a;
}
private float[] screenPointsToScaledPoints(float[] a) {
mTranslateMatrixInverse.mapPoints(a);
mScaleMatrixInverse.mapPoints(a);
return a;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
mOnTouchEventWorkingArray[0] = ev.getX();
mOnTouchEventWorkingArray[1] = ev.getY();
mOnTouchEventWorkingArray = scaledPointsToScreenPoints(mOnTouchEventWorkingArray);
ev.setLocation(mOnTouchEventWorkingArray[0],
mOnTouchEventWorkingArray[1]);
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
mTranslateMatrix.preTranslate(dx, dy);
mTranslateMatrix.invert(mTranslateMatrixInverse);
mLastTouchX = x;
mLastTouchY = y;
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(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 = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
if (detector.isInProgress()) {
mFocusX = detector.getFocusX();
mFocusY = detector.getFocusY();
}
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
mScaleMatrix.setScale(mScaleFactor, mScaleFactor, mFocusX, mFocusY);
mScaleMatrix.invert(mScaleMatrixInverse);
invalidate();
requestLayout();
return true;
}
}
public void restoreView() {
mPosX = 0;
mPosY = 0;
mFocusX = 0;
mFocusY = 0;
mScaleFactor = 1;
mTranslateMatrix.setTranslate(0, 0);
mScaleMatrix.setScale(1, 1);
invalidate();
}
}
Zoom in/Out is working perfectly.The restoreView() fuction is used show View in original state and it works fine. But after restore in original state,the ImageView's click in View is not get perfectly click. It means color is not fill in whole image like half color is fill and half image is with original color.
What's wrong or changes to be require in my code?
Thanks in advance.
One thing that seems a bit suspicious is that you reset two of your matrices in restoreView, but not the other two. Shouldn't you reset your inverse matrices too? Since you call invalidate right away, and since that will call invalidateChildInParent, which then maps the points, I think that might be your problem.
It's cool code that you have here, but are you sure it's safe to override invalidateChildInParent? There is a comment that tells you not to do so. Are you sure there's not another way to transform child views? Sorry, I haven't done this type of code before, so I don't actually know the right way to do that. It sounds like you're almost there anyway. Good luck.

Pinch zoom not working properly in HorizontalScrollView in android

I am arranging my views inside HorizontalScrollView and my each view(DrawView.java) contains rectangle. When the activity only contain this view, pinch zoom functionality is working fine(See Code 1 and respective image 1) but when I am arranging multiple of these views in HorizontalScrollView, it's not working properly because touch events of this view are messing up with touch events of HorizontalScrollView(Code 2 and Image 2).
Someone please help me to fix this bug.
This is a code for activity in which pinch zoom is working fine.
public class MainActivity extends Activity {
DrawView drawView;
public class DrawView extends View {
Paint paint = new Paint();
public int recog=-1; // this variable will tell if onDraw is called for first time or is called by listener usinf invalidate()
boolean listener=false;
int data[] = new int[] {200,200,200,200,200,200,200,200,200,200,200,200};
private float MIN_ZOOM = 0.1f;
private float MAX_ZOOM = 10f;
private float mPosX;
private float mPosY;
boolean zoom=false;
private ScaleGestureDetector detector;
float width=200;
private float mLastTouchX;
private float mLastTouchY;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
public DrawView(Context context) {
this(context, null);
}
public DrawView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.GREEN);
canvas.save();
if(listener ==true)
mScaleFactor+=0.4;
Log.e("Ronak","Listener"+listener);
Log.e("Ronak","ScaleFactor"+mScaleFactor);
canvas.scale(mScaleFactor, 1);
canvas.drawRect(0.0f, 0.0f, 300.0f, 100.0f, paint);
makeLinesinRange(0,100,300,100,200, 5, canvas,100);
width=mScaleFactor*300;
canvas.restore();
requestLayout();
}
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
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 = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(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 = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
#Override protected void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
// int width = MeasureSpec.getSize(widthMeasureSpec);
//int height = (int)(width * 0.5f);
setMeasuredDimension((int)width, 350);
}
private void makeLinesinRange(int x1, int y1, int x2, int y2, int size, int divisions, Canvas canvas,int width)
{
paint.setStrokeWidth(6);
paint.setColor(Color.DKGRAY);
float kk=(x2-x1)/(divisions-1);
for(int i=0;i<divisions;i++)
{
canvas.drawLine(x1+i*kk, y1, x1+i*kk, y2+size, paint);
}
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
Log.e("Ronak","scale "+mScaleFactor);
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.3f, Math.min(mScaleFactor, 5.0f));
invalidate();
return true;
}
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawView = new DrawView(this);
drawView.setBackgroundColor(Color.WHITE);
setContentView(drawView);
}
}
DrawView.java. This is a code of single view. I am arranging multiple of these views in HorizontalScrollView
public class DrawView extends View {
Paint paint = new Paint();
public int recog=-1; // this variable will tell if onDraw is called for first time or is called by listener usinf invalidate()
boolean listener=false;
int view_number=0;
int data[] = new int[] {200,200,200,200,200,200,200,200,200,200,200,200};
int lines[] = new int[] {4,5,7,8,2,6,6,3,2,1,1,6};
String[] type=new String[]{"Song","Music","Magazine","Audible","Videos","Apps","Other"};
private static float MIN_ZOOM = 0.1f;
private static float MAX_ZOOM = 10f;
private float mPosX;
private float mPosY;
boolean zoom=false;
private ScaleGestureDetector detector;
float width=700;
float height=500;
private float mLastTouchX;
private float mLastTouchY;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
private static final int INVALID_POINTER_ID = -1;
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
public DrawView(Context context) {
this(context, null);
}
public DrawView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
#Override
public void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
canvas.save();
if(listener ==true)
mScaleFactor+=0.4;
Log.e("Ronak","Listener"+listener);
Log.e("Ronak","ScaleFactor"+mScaleFactor);
canvas.scale(mScaleFactor, 1);
canvas.drawRect(0.0f, 0.0f, 300.0f, 70.0f, paint);
makeLinesinRange(0,70,300,70,200, lines[view_number], canvas,100);
width=mScaleFactor*300;
height=mScaleFactor*100;
/*int start=0;
int temp=(int)width/lines[view_number];
for(int i=0;i<lines[view_number];i++)
{
canvas.drawText(type[i], 50, 100, paint);
start=temp;
temp+=temp;
}*/
canvas.restore();
requestLayout();
}
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
// invalidate();
}
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 = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(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 = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
public boolean onInterceptTouchEvent(MotionEvent event) {
/* switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mIsBeingDragged = false;
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
float xDelta = Math.abs(x - mLastX);
float yDelta = Math.abs(y - mLastY);
float yDeltaTotal = y - mStartY;
if (yDelta > xDelta && Math.abs(yDeltaTotal) > mTouchSlop) {
mIsBeingDragged = true;
mStartY = y;
return true;
}
break;
}*/
Log.e("Ronak","Here");
return false;
}
#Override protected void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
// int width = MeasureSpec.getSize(widthMeasureSpec);
//int height = (int)(width * 0.5f);
setMeasuredDimension((int)width, 350);
}
private void makeLinesinRange(int x1, int y1, int x2, int y2, int size, int total_events, Canvas canvas,int width)
{
paint.setStrokeWidth(6);
paint.setColor(Color.MAGENTA);
if(total_events<1)
{
return;
}
if(total_events==1)
{
canvas.drawLine(((x1+x2)/2), y1, (x1+x2)/2, y2+size, paint);
}
else if(total_events==2)
{
canvas.drawLine(((x1+x2)/3), y1, (x1+x2)/3, y2+size, paint);
canvas.drawLine((2*(x1+x2)/3), y1, 2*(x1+x2)/3, y2+size, paint);
}
else
{
paint.setStrokeWidth(6);
paint.setColor(Color.MAGENTA);
float kk=(x2-x1)/(total_events-1);
for(int i=0;i<total_events;i++)
{
canvas.drawLine(x1+i*kk, y1, x1+i*kk, y2+size, paint);
}
}
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
Log.e("Ronak","scale "+mScaleFactor);
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
invalidate();
return true;
}
}
}
I also have a class which is extending HorizontalScrollView and is calling the above class(DrawView.java) for fitting multiple of these view in horizontal scrolling. Is there ant need to override the onTouch function of this class?
First: YIKES! Don't call requestLayout() from onDraw() -- or you'll get 100% load, all it's ever going to do is relayout and redraw itself.
Second: Remove onInterceptTouchEvent() from DrawView. Since it extends View -- and Views don't have this method -- it'll not get called as part of the touch dispatch process anyway.
Third: which one's not working -- scrolling or scaling?
Read this thread, it's got some insights on how to handle multiple gesture-consuming components

Move/drag/zoom an imageview in Android

I am developing an app which takes a picture from camera and then applies an imageview on top of it.
Now, I need to move and resize (with pinch) the imageview above the captured picture.
First I've implemented a simple drag behavior which worked well (I cannot use the drag event since min sdk level), but problems have came when I tried to add a pinch-to-zoom action too.
Right now I've tried several solutions found on stackoverflow, but none of them has worked for my scenario.
Here is the custom view that I'm using (found after some searchs)
https://dl.dropboxusercontent.com/u/230145/PanZoomView.java
but it has a weird behavior since when I try to do a zoom or drag it, the object gets crazy on the screen.
Anyone has an idea or solution for this?
EDIT
Finally I've solved with the following code:
Code from Java Class:
private ImageView mOrologio;
private FrameLayout mPhotoBox;
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
...
...
private void bindViews(View rootView) {
...
mPhotoBox = (FrameLayout) rootView.findViewById(R.id.fotoBox);
mOrologio = (ImageView) rootView.findViewById(R.id.imgOrologio);
mOrologio.setOnTouchListener(this);
...
}
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) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
ImageView view = (ImageView) v;
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:
oldDist = spacing(event);
if (oldDist > 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.postTranslate(event.getX() - start.x,
event.getY() - start.y);
}
else if (mode == ZOOM) {
float newDist = spacing(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
view.setImageMatrix(matrix);
return true; // indicate event was handled
}
}
Code from XML Layout:
<FrameLayout
android:id="#+id/fotoBox"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/prev_list" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imgOrologio"
android:scaleType="matrix"
android:layout_gravity="right|center_vertical" />
</FrameLayout>
So basically I've learned this lesson:
FrameLayout is needed as rootView if you want to move/zoom your ImageView
If you want to move/zoom an ImageView like in my scenario you don't need to override the ImageView class but only handle the touch events.
Thank you all for replies and hope this solution will be usefull =)
You can use a custom image view above the current screen using a frame layout. You can use the custom class here will may help you
public class CustomZoomableImageView extends ImageView {
private Paint borderPaint = null;
private Paint backgroundPaint = null;
private float mPosX = 0f;
private float mPosY = 0f;
private float mLastTouchX;
private float mLastTouchY;
private static final int INVALID_POINTER_ID = -1;
private static final String LOG_TAG = "TouchImageView";
// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
public CustomZoomableImageView (Context context) {
this(context, null, 0);
}
public CustomZoomableImageView (Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
// Existing code ...
public CustomZoomableImageView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Create our ScaleGestureDetector
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
borderPaint = new Paint();
borderPaint.setARGB(255, 255, 128, 0);
borderPaint.setStyle(Paint.Style.STROKE);
borderPaint.setStrokeWidth(4);
backgroundPaint = new Paint();
backgroundPaint.setARGB(32, 255, 255, 255);
backgroundPaint.setStyle(Paint.Style.FILL);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
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 = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(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 = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
/*
* (non-Javadoc)
*
* #see android.view.View#draw(android.graphics.Canvas)
*/
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, borderPaint);
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, backgroundPaint);
if (this.getDrawable() != null) {
canvas.save();
canvas.translate(mPosX, mPosY);
Matrix matrix = new Matrix();
matrix.postScale(mScaleFactor, mScaleFactor, pivotPointX,
pivotPointY);
// canvas.setMatrix(matrix);
canvas.drawBitmap(
((BitmapDrawable) this.getDrawable()).getBitmap(), matrix,
null);
// this.getDrawable().draw(canvas);
canvas.restore();
}
}
/*
* (non-Javadoc)
*
* #see
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable
* )
*/
#Override
public void setImageDrawable(Drawable drawable) {
// Constrain to given size but keep aspect ratio
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
mLastTouchX = mPosX = 0;
mLastTouchY = mPosY = 0;
int borderWidth = (int) borderPaint.getStrokeWidth();
mScaleFactor = Math.min(((float) getLayoutParams().width - borderWidth)
/ width, ((float) getLayoutParams().height - borderWidth)
/ height);
pivotPointX = (((float) getLayoutParams().width - borderWidth) - (int) (width * mScaleFactor)) / 2;
pivotPointY = (((float) getLayoutParams().height - borderWidth) - (int) (height * mScaleFactor)) / 2;
super.setImageDrawable(drawable);
}
float pivotPointX = 0f;
float pivotPointY = 0f;
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
pivotPointX = detector.getFocusX();
pivotPointY = detector.getFocusY();
Log.d(LOG_TAG, "mScaleFactor " + mScaleFactor);
Log.d(LOG_TAG, "pivotPointY " + pivotPointY + ", pivotPointX= "
+ pivotPointX);
mScaleFactor = Math.max(0.05f, mScaleFactor);
invalidate();
return true;
}
}
And call the setImageDrawableMethod in the custom imageView
Are you trying to crop the image. I can not comment on your post but just answer. If so then let me know because you can use CROP intent to for what you are looking for. I have implemented it and it basically takes picture with camera... crops,zooms and drag .
Try this.
Something like below will do it.
#Override public boolean onTouch(View v,MotionEvent e)
{
tap=tap2=drag=pinch=none;
int mask=e.getActionMasked();
posx=e.getX();posy=e.getY();
float midx= img.getWidth()/2f;
float midy=img.getHeight()/2f;
int fingers=e.getPointerCount();
switch(mask)
{
case MotionEvent.ACTION_POINTER_UP:
tap2=1;break;
case MotionEvent.ACTION_UP:
tap=1;break;
case MotionEvent.ACTION_MOVE:
drag=1;
}
if(fingers==2){nowsp=Math.abs(e.getX(0)-e.getX(1));}
if((fingers==2)&&(drag==0)){ tap2=1;tap=0;drag=0;}
if((fingers==2)&&(drag==1)){ tap2=0;tap=0;drag=0;pinch=1;}
if(pinch==1)
{
if(nowsp>oldsp)scale+=0.1;
if(nowsp<oldsp)scale-=0.1;
tap2=tap=drag=0;
}
if(tap2==1)
{
scale-=0.1;
tap=0;drag=0;
}
if(tap==1)
{
tap2=0;drag=0;
scale+=0.1;
}
if(drag==1)
{
movx=posx-oldx;
movy=posy-oldy;
x+=movx;
y+=movy;
tap=0;tap2=0;
}
m.setTranslate(x,y);
m.postScale(scale,scale,midx,midy);
img.setImageMatrix(m);img.invalidate();
tap=tap2=drag=none;
oldx=posx;oldy=posy;
oldsp=nowsp;
return true;
}
public void onCreate(Bundle b)
{
super.onCreate(b);
img=new ImageView(this);
img.setScaleType(ImageView.ScaleType.MATRIX);
img.setOnTouchListener(this);
path=Environment.getExternalStorageDirectory().getPath();
path=path+"/DCIM"+"/behala.jpg";
byte[] bytes;
bytes=null;
try{
FileInputStream fis;
fis=new FileInputStream(path);
BufferedInputStream bis;
bis=new BufferedInputStream(fis);
bytes=new byte[bis.available()];
bis.read(bytes);
if(bis!=null)bis.close();
if(fis!=null)fis.close();
}
catch(Exception e)
{
ret="Nothing";
}
Bitmap bmp=BitmapFactory.decodeByteArray(bytes,0,bytes.length);
img.setImageBitmap(bmp);
setContentView(img);
}
For viewing complete program see here: Program to zoom image in android

Zoom and Pinch RelativeLayout

I am new to android development, sorry if I ask some stupid question please try to help me. I am trying to implement the Zoom and pinch in RelativeLayout. I want to make my own map view in which I'll get the image of floor map and draw the pins(ImageVIew) on it. I've tried it out but i am currently unable to click on the pins. I've done the code with the help of these posts
Extending RelativeLayout, and overriding dispatchDraw() to create a zoomable ViewGroup
and
Android - zoom in/out RelativeLayout with spread/pinch
My Code is
public class TempView extends RelativeLayout {
private static final int INVALID_POINTER_ID = -1;
private Drawable mIcon;
private float mPosX;
private float mPosY;
TempView temp;
private float mLastTouchX;
private float mLastTouchY;
private int mActivePointerId = INVALID_POINTER_ID;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
public TempView(Context context) {
this(context, null, 0);
temp = this;
}
public TempView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
temp = this;
}
public TempView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mIcon = context.getResources().getDrawable(R.drawable.ic_launcher);
mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());
temp = this;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
mLastTouchX = x;
mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
invalidate();
}
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 = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(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 = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
mActivePointerId = ev.getPointerId(newPointerIndex);
}
break;
}
}
return true;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
int count = getChildCount();
Log.d("onLayout", ""+count);
for(int i=0;i<count;i++){
View child = getChildAt(i);
if(child.getVisibility()!=GONE ){
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)child.getLayoutParams();
child.layout(
(int)(params.leftMargin * mScaleFactor),
(int)(params.topMargin * mScaleFactor),
(int)((params.leftMargin + child.getMeasuredWidth()) * mScaleFactor),
(int)((params.topMargin + child.getMeasuredHeight()) * mScaleFactor)
);
child.setLayoutParams(params);
}
}
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
Log.d("onDraw", ""+mScaleFactor);
int count = getChildCount();
for(int i=0;i<count;i++){
View child = getChildAt(i);
if(child.getVisibility()!=GONE){
child.draw(canvas);
Log.d("onDraw", ""+mScaleFactor);
}
}
canvas.restore();
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
super.dispatchDraw(canvas);
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 5.0f));
// Log.d("onScale", ""+mScaleFactor);
temp.invalidate();
invalidate();
return true;
}
}
}
Questions:
How to make Only Floor Map Image to zoom?
Keep Pins non-zoom but Move Relatively?
Get Accurate Click Event when clicked on a pin
Any Suggestions and Answers will be very much appriciated!
Thanks in Advance,
Qamar
An implementation of an HTML map like element in an Android View:
Supports images as drawable or bitmap in layout
Allows for a list of area tags in xml
Enables use of cut and paste HTML area tags to a resource xml (ie, the ability to take an HTML map - and image and use it with minimal editing)
Supports panning if the image is larger than the device screen
Supports pinch-zoom
Supports callbacks when an area is tapped.
Supports showing annotations as bubble text and provide callback if the bubble is tapped
see this link you will got your solution https://github.com/catchthecows/AndroidImageMap

Categories

Resources