No. at increased zoom

In my view, recycler layout for gallery app.

I want to enable the pinch touch event listener so that the column type is recycler no. increases or decreases by pich in and out.

I have seen this type of interface in many gallery applications.

What is the best way to achieve this so that the transition is smooth.

A small link to the video: - http://sendvid.com/s68fiqpd

I tried using the code below (as pointed out by @Yogesh Rathi), but the results are not what I want to achieve.

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; } } } 

thanks

+1
source share
2 answers

This is a way to pinch and leave, I already tested this in my example application that works correctly.

 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; } } } 
+3
source

To achieve this, you can use the scale gesture detector with layout managers in recycler mode. install on the touch listener on the screen of your recycler and transfer the touch event to an instance of the scale gesture sensor. In the onScale () function, you can switch layout managers to view your recycler based on a scale factor. I created a demo for this. You can find the code here.

0
source

All Articles