Question

I am using a third party library. It makes images be draggable, and scale when you pinch, and rotate. I am trying to implement deletion of the image, and have made a method that does delete the image you place your finger on. Now I just need to call it. The only place I have successfully called it from is onDraw. Ideally I would call it on a doubleTap, because the user will longClick it to drag it. But longClick is apparently easier so i was testing that first. Here is my code. Scroll to the bottom to see my setOnClickListener. I will show you the class code before the setOnClickListener to give you some context:

public class PhotoSortrView extends View implements MultiTouchObjectCanvas<PhotoSortrView.Img> {

        private ArrayList<Integer> mDrawables = new ArrayList<Integer>();// { R.drawable.m74hubble, R.drawable.catarina, R.drawable.tahiti, R.drawable.sunset, R.drawable.lake };

        public void addDrawable(int drawable, Context context){
            Resources res = context.getResources();
            mDrawables.add(drawable);

            mImages.add(new Img(drawable, res));
            invalidate();
        }

        private ArrayList<Img> mImages = new ArrayList<Img>();
        private AppUser user;

        // --

        private MultiTouchController<Img> multiTouchController = new MultiTouchController<Img>(this);

        // --

        private PointInfo currTouchPoint = new PointInfo();

        private boolean mShowDebugInfo = true;

        private static final int UI_MODE_ROTATE = 1, UI_MODE_ANISOTROPIC_SCALE = 2;

        private int mUIMode = UI_MODE_ROTATE;

        // --

        private Paint mLinePaintTouchPointCircle = new Paint();

        // ---------------------------------------------------------------------------------------------------

        public PhotoSortrView(Context context) {
            this(context, null);
        }

        public PhotoSortrView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }

        public PhotoSortrView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init(context);
        }

        @SuppressWarnings("deprecation")
        private void init(Context context) {
            Resources res = context.getResources();
            for (int i = 0; i < mDrawables.size(); i++)
                mImages.add(new Img(mDrawables.get(i), res));

            mLinePaintTouchPointCircle.setColor(Color.YELLOW);
            mLinePaintTouchPointCircle.setStrokeWidth(5);
            mLinePaintTouchPointCircle.setStyle(Style.STROKE);
            mLinePaintTouchPointCircle.setAntiAlias(true);
            this.setLongClickable(true);

            this.setOnLongClickListener(new View.OnLongClickListener() {

                @Override
                public boolean onLongClick(View v) {
                    Toast.makeText(getContext(), "Long Clicked", Toast.LENGTH_SHORT).show();
                    Log.d("long clicking", "long clicking");
                    return true;
                }
            });
        }

I'm new to Android so maybe do not fully understand the context of this library class. I call this class in my activity like this:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dressing_room);
    photoSorter = new PhotoSortrView(this);
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            this.addContentView(photoSorter, params);

Its a view that gets added to this activity, but it has a canvas and can add lots of the draggable images. Thanks.

EDIT I changed it to

this.setOnTouchListener(new View.OnTouchListener() {

               // @Override
                //public boolean onLongClick(View v) {
                //  Toast.makeText(getContext(), "Long Clicked", Toast.LENGTH_SHORT).show();
                //  Log.d("long clicking", "long clicking");
                //    return true;
               // }

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    Toast.makeText(getContext(), "Long Clicked", Toast.LENGTH_SHORT).show();
                    Log.d("long clicking", "long clicking");
                    return false;
                }
            });
        }

And that works. Can we get from that to a doubleTap?

Was it helpful?

Solution

There is a built-in GestureDetector that is able to "catch" all common interactions between the device and the user, including double tap. However to set it up for a single View, or a selection of Views, you have to do a bit of grunt work. I'll post the code of my test activity now:

public class MainActivity extends Activity implements OnClickListener {
    private GestureDetector gd;
    View.OnTouchListener otl;

    class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            Toast.makeText(getApplicationContext(), "Test", Toast.LENGTH_SHORT).show();
            return true;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gd = new GestureDetector(this, new MyGestureDetector());
        otl = new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                return gd.onTouchEvent(event);
            }
        };
        LinearLayout cotainerView = (LinearLayout) findViewById(R.id.container);
        TextView tvNormal = new TextView(this);
        tvNormal.setText("Normal text view");
        tvNormal.setHeight(50);
        DoubleTapTextView tvDoubleTap = new DoubleTapTextView(this);
        tvDoubleTap.setText("Double tap text view");
        tvDoubleTap.setHeight(50);
        tvDoubleTap.setOnClickListener(this);
        tvDoubleTap.setOnTouchListener(otl);
        containerView.addView(tvNormal);
        containerView.addView(tvDoubleTap);
    }

    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub

    }

}

So the trick is to pass the onTouch event, as well as its argument (MotionEvent e) to your custom GestureListener. This way, every Gesture (Touch event) will be listened for, but your custom listener will execute onDoubleTap(MotionEvent e) method only in the case the gesture is double tap. Hopefully, you understand the idea behind this, and as a treat, I'm posting a screenshot of the app running in an emulator to show you that the event is actually caught :) Screenshot

EDIT: Here are the key points of the solution

  1. Activity implements OnClickListener
  2. Register the desired View for both OnClickLister and OnTouchListener

    tvDoubleTap.setOnClickListener(this); //Your activity implements OnClickListener
    tvDoubleTap.setOnTouchListener(otl); //The wrapper listener from which you call your custom one
    
  3. Inside the basic OnTouchListener, pass the argument to your custom GestureListener

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return gd.onTouchEvent(event);
    }
    
  4. Inside your custom GestureListener's onDoubleTap(MotionEvent e) method, implement your solution.

    class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            Toast.makeText(getApplicationContext(), "Test", Toast.LENGTH_SHORT).show();
            return true;
        }
    }
    

Credits: Thanks to gav, for his research on his question

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top