View Pager + Imageview +Pinch Zoom + Rotation

View Pager + ImageView +Pinch Zoom + Rotation

EDIT 2: Example code has been pushed to the master branch of TouchImageView. Here is a link to the example activity and a link to the ExtendedViewPager.


EDIT: added code adapting the example link to TouchImageView. Note: you will need the latest code, which is currently in the dev branch. In the future, this will be included in v1.2.0. You know you have the latest code if TouchImageView overrides canScrollHorizontally.

Step 1: Extend ViewPager and override canScroll to call canScrollHorizontallyFroyo.

public class ExtendedViewPager extends ViewPager {

public ExtendedViewPager(Context context) {
super(context);
}

public ExtendedViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof TouchImageView) {
return ((TouchImageView) v).canScrollHorizontallyFroyo(-dx);
} else {
return super.canScroll(v, checkV, dx, x, y);
}
}

}

Step 2: Modify TouchImageView by adding canScrollHorizontallyFroyo:

public boolean canScrollHorizontallyFroyo(int direction) {
return canScrollHorizontally(direction);
}

Step 3: Your activity

public class TouchImageViewActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ExtendedViewPager mViewPager = (ExtendedViewPager) findViewById(R.id.view_pager);
setContentView(mViewPager);
mViewPager.setAdapter(new TouchImageAdapter());
}

static class TouchImageAdapter extends PagerAdapter {

private static int[] images = { R.drawable.img1, R.drawable.img2, R.drawable.img3 };

@Override
public int getCount() {
return images.length;
}

@Override
public View instantiateItem(ViewGroup container, int position) {
TouchImageView img = new TouchImageView(container.getContext());
img.setImageResource(images[position]);
container.addView(img, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
return img;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}

@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}

}
}

Step 4: main.xml

<com.example.touch.ExtendedViewPager 
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />

TouchImageView is actually my project. I currently have a fix in the dev branch for integration with ViewPagers, which will be pushed to master in an upcoming release. Unfortunately, this fix is only applicable for API 14 and greater since honeycomb and earlier do not call canScrollHorizontally. If you need to support older APIs, then you will need to implement a workaround in your ViewPager. Here is an example.

ViewPager & ImageView zooming issue

Yes I too had the same problem not with TouchImageView.

Too solved the problem what i did is disabled the ViewPager when my view is getting the focus.

public class EnableDisableViewPager extends ViewPager {

private boolean enabled = true;

public EnableDisableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
if(enabled)
return super.onInterceptTouchEvent(arg0);

return false;
}

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

so in TouchImageView implement your listener to trigger an event whether its zooming or dragging.

set listener to your view object in your Activity. So when those event occur just disable the view Pager.

Note: you will also need a mouse up event to enable the viewpager.

EDITED

This will work only for Zoom, so for ViewPager to swipe pages you should zoom back to original.

Add these code to your TouchImageView

    public class TouchImageView extends ImageView {

...
private TouchEventListener touchEventListener;

private void sharedConstructing(Context context) {
...

setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
...
case MotionEvent.ACTION_UP:
...
if(touchEventListener != null)
{
if(saveScale == 1.0)
touchEventListener.onZoomToOriginal();
else
touchEventListener.onZoom();
}
break;

...
}
...
}

});
}

...

public TouchEventListener getTouchEventListener() {
return touchEventListener;
}

public void setTouchEventListener(TouchEventListener touchEventListener) {
this.touchEventListener = touchEventListener;
}

public interface TouchEventListener
{
void onZoom();
void onZoomToOriginal();
}
}

BETTER SOLUTION

We could achieve this without extending ViewPager to a new Class by using the method given below.

requestDisallowInterceptTouchEvent(true);

And with this we could swipe without zooming out to original position as we see in Gallery and many other apps.

public class TouchImageView extends ImageView {

...
private void stopInterceptEvent()
{
getParent().requestDisallowInterceptTouchEvent(true);
}

private void startInterceptEvent()
{
getParent().requestDisallowInterceptTouchEvent(false);
}

private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);

setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);

matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
PointF curr = new PointF(event.getX(), event.getY());

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
stopInterceptEvent();
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
if (scaleWidth < width) {
deltaX = 0;
if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
} else if (scaleHeight < height) {
deltaY = 0;
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);
} else {
if (x + deltaX > 0)
deltaX = -x;
else if (x + deltaX < -right)
deltaX = -(x + right);

if (y + deltaY > 0)
deltaY = -y;
else if (y + deltaY < -bottom)
deltaY = -(y + bottom);
}

if(deltaX == 0)
startInterceptEvent();
else
stopInterceptEvent();

matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
}
break;

case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
startInterceptEvent();
break;

case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}

});
}
}

Pinch to Zoom ImageView inside a HorizontalPager (RealViewSwitcher) android

It's done, this way...
HorizontalPager will trap the onTouchEvent() first. It will pass the event to child view which is ImageViewTouch. If it handled the event (determined by boolean value returned by onTouchEvent()), It will also simply return from onTouchEvent() as handled. If child view (ImageViewTouch) did not handle event, it will handle this event by taking necessary action related to the event and return as handled.

Of course I have done some modifications to HorizontalPager and ImageViewTouch classes to co-ordinate this.

Zoom the ViewPager ImageView?

try this :

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<yourpackage_name.TouchViewPagerImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY" />
</RelativeLayout>

in your my_viewpager xml

also in your adapter class:

  @Override
public Object instantiateItem(ViewGroup container, int position) {
TouchViewPagerImageView imgDisplay;

mLayoutInflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = mLayoutInflater.inflate(R.layout.activity_pager_items, container,
false);

imgDisplay = (TouchViewPagerIMageView) itemView.findViewById(R.id.imageView);
imgDisplay.setImageResource(mResources(position));
((ViewPager) container).addView(itemView);
return itemView;
}

problem with your TouchViewPagerIMageView class

use this code:

    public class TouchViewPagerIMageView extends ImageView {

Matrix 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 last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 3f;
float[] m;

int viewWidth, viewHeight;
static final int CLICK = 3;
float saveScale = 1f;
protected float origWidth, origHeight;
int oldMeasuredWidth, oldMeasuredHeight;

ScaleGestureDetector mScaleDetector;

Context context;

public TouchImageView(Context context) {
super(context);
sharedConstructing(context);
}

public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
sharedConstructing(context);
}

private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix = new Matrix();
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);

setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
PointF curr = new PointF(event.getX(), event.getY());

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(curr);
start.set(last);
mode = DRAG;
break;

case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float fixTransX = getFixDragTrans(deltaX, viewWidth,
origWidth * saveScale);
float fixTransY = getFixDragTrans(deltaY, viewHeight,
origHeight * saveScale);
matrix.postTranslate(fixTransX, fixTransY);
fixTrans();
last.set(curr.x, curr.y);
}
break;

case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;

case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}

setImageMatrix(matrix);
invalidate();
return true; // indicate event was handled
}

});
}

public void setMaxZoom(float x) {
maxScale = x;
}

private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}

@Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = detector.getScaleFactor();
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}

if (origWidth * saveScale <= viewWidth
|| origHeight * saveScale <= viewHeight)
matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2,
viewHeight / 2);
else
matrix.postScale(mScaleFactor, mScaleFactor,
detector.getFocusX(), detector.getFocusY());

fixTrans();
return true;
}
}

void fixTrans() {
matrix.getValues(m);
float transX = m[Matrix.MTRANS_X];
float transY = m[Matrix.MTRANS_Y];

float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
float fixTransY = getFixTrans(transY, viewHeight, origHeight
* saveScale);

if (fixTransX != 0 || fixTransY != 0)
matrix.postTranslate(fixTransX, fixTransY);
}

float getFixTrans(float trans, float viewSize, float contentSize) {
float minTrans, maxTrans;

if (contentSize <= viewSize) {
minTrans = 0;
maxTrans = viewSize - contentSize;
} else {
minTrans = viewSize - contentSize;
maxTrans = 0;
}

if (trans < minTrans)
return -trans + minTrans;
if (trans > maxTrans)
return -trans + maxTrans;
return 0;
}

float getFixDragTrans(float delta, float viewSize, float contentSize) {
if (contentSize <= viewSize) {
return 0;
}
return delta;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = MeasureSpec.getSize(widthMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);

//
// Rescales image on rotation
//
if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
|| viewWidth == 0 || viewHeight == 0)
return;
oldMeasuredHeight = viewHeight;
oldMeasuredWidth = viewWidth;

if (saveScale == 1) {
// Fit to screen.
float scale;

Drawable drawable = getDrawable();
if (drawable == null || drawable.getIntrinsicWidth() == 0
|| drawable.getIntrinsicHeight() == 0)
return;
int bmWidth = drawable.getIntrinsicWidth();
int bmHeight = drawable.getIntrinsicHeight();

Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);

float scaleX = (float) viewWidth / (float) bmWidth;
float scaleY = (float) viewHeight / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);

//Center the image
float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;

matrix.postTranslate(redundantXSpace, redundantYSpace);

origWidth = viewWidth - 2 * redundantXSpace;
origHeight = viewHeight - 2 * redundantYSpace;
setImageMatrix(matrix);
}
fixTrans();
}
}

Touch Zoom under a ViewPager/FrameLayout

I was able to get this working, strangely, by implementing a reset method inside the TouchImageView class:

public void resetZoom() {
Matrix imageMatrix = getImageMatrix();
RectF drawableRect = new RectF(0, 0, bmWidth, bmHeight);
RectF viewRect = new RectF(0, 0, getWidth(), getHeight());

imageMatrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);

matrix = imageMatrix;
setImageMatrix(matrix);

fitAndCenterView();

invalidate();
}

This method resets the zoom on the image when called - and when we set up the image inside the framelayout calling this gets everything set up. Oddly, this is not required when the image is not inside a FrameLayout.

I'd of course appreciate any code cleanup and whatnot that we can do.

How to do pinching zoom and swipe on multiple imageview in android?

MainActivity

public class MainActivity extends Activity {
private AwesomePagerAdapter awesomeAdapter;
public static NonSwipeableViewPager awesomePager;
RelativeLayout v;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
awesomeAdapter = new AwesomePagerAdapter();
awesomePager = (NonSwipeableViewPager) findViewById(R.id.awesomepager);
awesomePager.setAdapter(awesomeAdapter);
}
public class AwesomePagerAdapter extends PagerAdapter{

private int NUM_VIEWS =2;
@Override
public int getCount() {
return NUM_VIEWS ;
}

@Override
public Object instantiateItem(View container, int position) {
if(position == 0){
TouchImageView.b = true;
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
v = (RelativeLayout) inflater.inflate(R.layout.item_gallery_image, null);
TouchImageView tm = (TouchImageView) v.findViewById(R.id.image);
Bitmap bm = BitmapFactory.decodeResource(getResources(),
R.drawable.swami);
tm.setImageBitmap(bm);
((ViewPager) container).addView(v, 0);
}else if(position == 1){
TouchImageView.b = true;
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
v = (RelativeLayout) inflater.inflate(R.layout.item_gallery_image, null);
TouchImageView tm = (TouchImageView) v.findViewById(R.id.image);
Bitmap bm = BitmapFactory.decodeResource(getResources(),
R.drawable.swami);
tm.setImageBitmap(bm);
((ViewPager) container).addView(v, 0);
}
return v;
}
@Override
public void destroyItem(View container, int position, Object view) {
View v = (View) view;
((ViewPager) container).removeView(v);
TouchImageView.b = true;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == ((View) object);
}

}
}

swiper

public class NonSwipeableViewPager extends ViewPager {

private boolean enabled = true;

public NonSwipeableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
if (TouchImageView.b) {
return super.onTouchEvent(event);
}
return false;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (TouchImageView.b) {

try {
enabled = super.onInterceptTouchEvent(event);
} catch (Exception e) {
}
return enabled;
}
return false;
}

public void setPagingEnabled(boolean enabled) {
this.enabled = enabled;
}

}

TouchImageView

public class TouchImageView extends ImageView {
Matrix matrix = 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;
static NonSwipeableViewPager PagerLeft;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 3f;
float[] m;
static boolean b =false, c= false;
float redundantXSpace, redundantYSpace;

float width, height;
static final int CLICK = 3;
float saveScale = 1f;
float right, bottom, origWidth, origHeight, bmWidth, bmHeight;

ScaleGestureDetector mScaleDetector;

Context context;
ViewGroup vp;

public TouchImageView(Context context) {
super(context);
sharedConstructing(context);
}

public TouchImageView(Context context, AttributeSet attrs) {
super(context, attrs);
sharedConstructing(context);
}

public void setChild(ViewGroup vp) {
this.vp = vp;
}

private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix.setTranslate(1f, 1f);
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
/*Log.v("log_tag", event.getX()+" matrix "
+ x);*/
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
TouchImageView.b = false;
Log.v("event","ACTION_DOWN");
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
if (scaleWidth < width) {
deltaX = 0;
if (y + deltaY > 0){
TouchImageView.b = true;
Log.v("event","ACTION_MOVE scaleWidth < width y + deltaY > 0");
deltaY = -y;
}
else if (y + deltaY < -bottom){
TouchImageView.b = false;
Log.v("event","else ACTION_MOVE scaleWidth < width y + deltaY < -bottom");
deltaY = -(y + bottom);
}else{
TouchImageView.b = false;
}
} else if (scaleHeight < height) {
deltaY = 0;
if (x + deltaX > 0){
TouchImageView.b = true;
Log.v("event","ACTION_MOVE scaleWidth < height x + deltaX > 0");
deltaX = -x;
}
else if (x + deltaX < -right){
TouchImageView.b = true;
Log.v("event","ACTION_MOVE scaleWidth < height x + deltaX < -right");
deltaX = -(x + right);
}else{
TouchImageView.b = false;
}
}else {
if (x + deltaX > 0){
TouchImageView.b = true;
Log.v("event","scaleWidth > width");
deltaX = -x;
}
else if (x + deltaX < -right){
TouchImageView.b = true;
Log.v("event","else scaleWidth > width");
deltaX = -(x + right);
}
else{
TouchImageView.b = true;
}
if (y + deltaY > 0){
TouchImageView.b = true;
Log.v("event","y + deltaY");
deltaY = -y;
}
else if (y + deltaY < -bottom){
TouchImageView.b = true;
Log.v("event","y + deltaY < -bottom");
deltaY = -(y + bottom);
}else{
TouchImageView.b = false;
}
}
/*Log.v("log_tag",height + " matrix "
+ (int) getHeightFromMatrix(matrix, TouchImageView.this));*/
matrix.postTranslate(deltaX, deltaY);
last.set(curr.x, curr.y);
}
break;

case MotionEvent.ACTION_UP:
Log.v("event","ACTION_UP");
TouchImageView.b = true;
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK){
Log.v("event","ACTION_UP xDiff < CLICK && yDiff < CLICK");
performClick();
}
break;

case MotionEvent.ACTION_POINTER_UP:
//TouchImageView.b = false;
Log.v("event","ACTION_POINTER_UP");
mode = NONE;
break;
case MotionEvent.ACTION_POINTER_3_DOWN:
Log.v("event","ACTION_HOVER_MOVE");
break;
}
/*getLayoutParams().height = (int) getWidthFromMatrix(matrix,
TouchImageView.this);
getLayoutParams().width = (int) getHeightFromMatrix(matrix,
TouchImageView.this);*/
setImageMatrix(matrix);
invalidate();
return true;
}
});
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
if (bm != null) {
bmWidth = bm.getWidth();
bmHeight = bm.getHeight();
}
}

public void setMaxZoom(float x) {
maxScale = x;
}

private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
mode = ZOOM;
return true;
}

@SuppressLint("NewApi")
}


Related Topics



Leave a reply



Submit