Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android swipe card with pinch to zoom imageview using SwipeFlingAdapterView library

I am implementing swipe card with pinch to zoom functionality using this library and when I use only image view then it working fine means swipe work properly but I want swipe functionality like library as well as pinch to zoom so I added TouchImageView class in which only pinch to zoom work but swipe functionality is not working. So could you please help me to solve this problem or suggest me any alternative library in which swipe card and pinch to zoom is possible. Below is my activity

    public class MainActivity extends AppCompatActivity{

    private SwipeFlingAdapterView flingContainer;
    public static ArrayList<SwipModel> al;
    public SwipViewAdapter swipViewAdapter;
    private SwipModel swipModel;
    private Uri uri;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        getId();
        setSwipeCard();

    }

    private void getId() {
        flingContainer = (SwipeFlingAdapterView) findViewById(R.id.frame);
    }

    private void setSwipeCard() {

        uri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/drawable/picture1");

        swipModel = new SwipModel();

        al = new ArrayList<>();
        swipModel.setCardImageDrawable(uri);
        al.add(swipModel);


        swipViewAdapter = new SwipViewAdapter(getApplicationContext(), al);

        flingContainer.setAdapter(swipViewAdapter);
        flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener() {
            @Override
            public void removeFirstObjectInAdapter() {
                // this is the simplest way to delete an object from the Adapter (/AdapterView)
                Log.d("LIST", "removed object!");
//                al.remove(0);
//                swipViewAdapter.notifyDataSetChanged();
            }

            @Override
            public void onLeftCardExit(Object dataObject) {
                //Do something on the left!
                //You also have access to the original object.
                //If you want to use it just cast it (String) dataObject
//                makeToast(MainActivity.this, "Left!");
            }

            @Override
            public void onRightCardExit(Object dataObject) {
//                makeToast(MainActivity.this, "Right!");
            }

            @Override
            public void onAdapterAboutToEmpty(int itemsInAdapter) {
                // Ask for more data here
//                al = new ArrayList<>();
//                swipModel.setCardImageDrawable(uri);
//                al.add(swipModel);
            }

            @Override
            public void onScroll(float scrollProgressPercent) {
                View view = flingContainer.getSelectedView();
            }
        });


        // Optionally add an OnItemClickListener.
        flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener() {
            @Override
            public void onItemClicked(int itemPosition, Object dataObject) {

            }
        });
    }    
}

here is activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context="com.example.android.swipecardtesting.MainActivity">

    <com.lorentzos.flingswipe.SwipeFlingAdapterView
        android:id="@+id/frame"
        android:background="#ffeee9e2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:rotation_degrees="15.5"
        tools:context=".MyActivity"
        android:layout_centerInParent="true"
        />

</RelativeLayout>

Here is my Adapter

    public class SwipViewAdapter extends BaseAdapter {

    public static ArrayList<SwipModel> list;
    Context context;
    private LayoutInflater l_Inflater;
    public static ViewHolder holder;

    public SwipViewAdapter(Context mContext, ArrayList<SwipModel> al) {
        this.context = mContext;
        list = al;
        l_Inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return i;
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if (view == null) {
            holder = new ViewHolder();

            l_Inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = l_Inflater.inflate(R.layout.swip_item, viewGroup, false);


            holder.ivZoomable = (TouchImageView) view.findViewById(R.id.ivZoomable);

            view.setTag(holder);
        }



        holder.ivZoomable.setImageURI(list.get(i).getCardImageDrawable());


        return view;
    }

    public static class ViewHolder {
        public static TouchImageView ivZoomable;
    }
}

and my TouchImageView class

public class TouchImageView 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;
    public static 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<1)
            {
                Log.e("saveScale is ","executing =====> "+saveScale);
                SwipViewAdapter.ViewHolder.imageView.setVisibility(VISIBLE);
                SwipViewAdapter.ViewHolder.ivZoomable.setVisibility(GONE);
            }
            else
            {
                Log.e("saveScale is ","executing =====> "+saveScale);
                SwipViewAdapter.ViewHolder.imageView.setVisibility(GONE);
                SwipViewAdapter.ViewHolder.ivZoomable.setVisibility(VISIBLE);
            }



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

}
like image 958
Mohd Sakib Syed Avatar asked Sep 03 '16 05:09

Mohd Sakib Syed


1 Answers

Return false in the OnTouchListener.onTouch() in the TouchImageView class when only one pointer is down like so:

@Override
public boolean onTouch(View v, MotionEvent event) {

    // Touch logic here

    return event.getPointerCount() > 1;
}

This way pinch-to-zoom will only consume the touch event when two pointers are present (necessary to perform a pinch with).

Update:

Extend the SwipeFlingAdapterView class and override the onInterceptTouchEvent() method like it's done here: Using onInterceptTouchEvent

Then you could intercept the touch event directed to the image view like this:

public void onInterceptTouchEvent(MotionEvent event) {
    if(event.getPointerCount() == 1) {
        onTouchEvent(event);
    }
    return false;
}

More documentation about touch intercepts here: https://developer.android.com/training/gestures/viewgroup.html

Hope it helps!

like image 101
whitebrow Avatar answered Oct 15 '22 04:10

whitebrow