0

Suppose there is an ImageView (iv) and I set iv.SetOnTouchListener(this) while creating a new GestureDetector (gs) gs = new GestureDetector(this.Context, listener), how could I tack the finger's location (x,y) in each 0.01 seconds (as an example)?

Which function should I use? OnFling? OnLongPress?

I'm not talking only about the code, but I'd also like to get an idea of how to implement this desire of getting the finger's position in each 0.01 seconds. Any ideas?

Robert Bruce
  • 1,088
  • 1
  • 13
  • 17
Daniel Reyhanian
  • 579
  • 4
  • 26

1 Answers1

1

You can implement the View.IOnTouchListener interface and apply it as a listener to your View (ImageView in this case):

View.IOnTouchListener implementation:

Note: Using Java.Lang.Object as the base class in this example, but you can use any Java.Lang.Object-based class (Activity, etc...)

public class MyTouch : Java.Lang.Object, View.IOnTouchListener
{
    TimeSpan Milli10 = TimeSpan.FromMilliseconds(10);
    DateTime oldTime;
    public bool OnTouch(View v, MotionEvent e)
    {
        switch (e.Action)
        {
            case MotionEventActions.Down:
                oldTime = DateTime.Now;
                break;
            case MotionEventActions.Move:
                if (DateTime.Now.Subtract(oldTime) > Milli10)
                {
                    Console.WriteLine($"Touch {e.RawX} : {e.RawY} : tD: {DateTime.Now.Subtract(oldTime)}");
                    oldTime = DateTime.Now;
                }
                break;
            default:
                break;
        }
        return true;
    }
}

Then just instance the listener, if needed, and apply it as a the OnTouchListener:

imageView = FindViewById<ImageView>(Resource.Id.background);
touch = new MyTouch();
imageView.SetOnTouchListener(touch);

Update:

Need to add LongPress, DoubleTap, etc..., subclass GestureDetector.SimpleOnGestureListener and add it as an inner class to your View.IOnTouchListener implementation (this is just one way...)

View.IOnTouchListener PLUS SimpleOnGestureListener:

public class MyTouchPlusGestures : Java.Lang.Object, View.IOnTouchListener
{
    readonly MyGestures myGestures = new MyGestures();
    readonly TimeSpan Milli10 = TimeSpan.FromMilliseconds(10);
    readonly GestureDetector gestureDetector;
    DateTime oldTime = DateTime.Now;

    internal class MyGestures : GestureDetector.SimpleOnGestureListener
    {
        public override void OnLongPress(MotionEvent e)
        {
            // do something with press
            base.OnLongPress(e);
        }

        public override bool OnDoubleTap(MotionEvent e)
        {
            // do something with tap
            return base.OnDoubleTap(e);
        }
    }

    public MyTouchPlusGestures(View view)
    {
        gestureDetector = new GestureDetector(view.Context, myGestures);
        view.SetOnTouchListener(this);
    }

    public bool OnTouch(View v, MotionEvent e)
    {
        if (!gestureDetector.OnTouchEvent(e))
        {
            // If the event is not handled in one of your gestures, 
            // fall through to the MotionEventActions switch.
            switch (e.Action)
            {
                case MotionEventActions.Down:
                    oldTime = DateTime.Now;
                    break;
                case MotionEventActions.Move:
                    if (DateTime.Now.Subtract(oldTime) > Milli10)
                    {
                        Console.WriteLine($"Touch {e.RawX} : {e.RawY} : tD: {DateTime.Now.Subtract(oldTime)}");
                        oldTime = DateTime.Now;
                    }
                    break;
                default:
                    break;
            }
        }
        return true;
    }
}

Now just pass the View to your MyTouchPlusGestures instance and the gesture and touch listener are assigned for you...

imageView = FindViewById<ImageView>(Resource.Id.background);
touch = new MyTouchPlusGestures(imageView);
SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • Thanks a lot SushiHangover, knew you won't let me down. Several more things please: 1. Why does tD not hold the same value every 0.01 seconds? because of the if statement? 2. How can I detect directions between each calculation so I could know where to place the PC's cursor? 3. How can I detect double taps and long presses in this code? 4. Why aren't the values of the `RawX` and `RawY` rounded? – Daniel Reyhanian Apr 29 '19 at 19:29
  • Again, thanks a lot. You have a big part of my project and I really appreciate your honest work. – Daniel Reyhanian Apr 29 '19 at 19:30
  • By the way, instead of getting the direction in each time, maybe I could get the PC's screens' resolution and divide it in a constant ratio, in such a way that each postion (X,Y) on the Android's screen will fit to the PC's screen. What is your opinion? – Daniel Reyhanian Apr 29 '19 at 19:34
  • 1
    @DanielReyhanian Check out my update for the gestures.... 1) the freq. of the callback is based upon the device as it is dependent upon the touch scanner on the display (some devices have 30hz displays, but 60, 90, 120hz devices are available now (or coming soon)... and their touch scanners are sync'd to that speed, other not). 2) Store the last x/y and compare w/ new values if you need a motion vector 3) See updated answer 4) RawX|Y is to the same is X|Y, one is display based and the other is view based (use the one that you need for your needs) – SushiHangover Apr 29 '19 at 20:35
  • So if the ImageButton is simulated to the PC's screen, I should use `GetX` and `GetY` (as mentioned [here](https://stackoverflow.com/questions/20636163/difference-between-motionevent-getrawx-and-motionevent-getx))? Please correct me if I am wrong. – Daniel Reyhanian Apr 29 '19 at 21:04
  • 1
    @DanielReyhanian If you need coords relative to the View itself and not the screen, yes, GetX|Y is what you want. Happy coding – SushiHangover Apr 29 '19 at 21:07
  • A few more things please: 1. why doesn't `OnLongPress` return any value? 2. How can I detect a singe tap? Simply add `OnSingleTapUp()`? 3. Also, seems like `RawX` and `GetX` return the same value.. Thanks again for your precious time. – Daniel Reyhanian Apr 29 '19 at 21:35
  • 1
    1) It is a long press event, what "value" are you looking for 2) Use `OnSingleTapConfirmed` 3) not sure, would have to look at it again... – SushiHangover Apr 29 '19 at 21:39
  • I thought that if `OnDoubleTap` returns a bool than `OnLongPress` would too. It's just that I don't get what `base.OnDoubleTap(e);` really returns. – Daniel Reyhanian Apr 29 '19 at 21:41
  • 1
    @DanielReyhanian It is returning a true|false to determine if you have handed that event, otherwise it is passed on to the next event listener. "`true if the OnGestureListener consumed the event, else false.`" Long presses are a "contrived" event and thus has no analog in the View's event chain and thus it does not propagate to the event chain, thus it has a `void` return. – SushiHangover Apr 29 '19 at 21:52
  • Hello Sushi, the code works perfectly. I was wondering, is there any way to implement `ScaleGestureDetecor` in the above code, so I could listen to "pinch to zoom" gestures? – Daniel Reyhanian Apr 30 '19 at 18:34