Net Maui how to get coordinats by pointergesture ?

Sami 966 Reputation points
2023-08-01T22:06:05.0066667+00:00

Net Maui how to get postion of coordinats by pointergesture or other way ? Android and Ios

I realized that pointergesture is not working on android..Any solution ?

Developer technologies | .NET | .NET MAUI
0 comments No comments
{count} votes

Accepted answer
  1. Anonymous
    2023-08-02T08:17:33.3533333+00:00

    Hello,

    Net Maui how to get postion of coordinats by pointergesture or other way ?

    You can implement a RouteEffect like Xamarin.Forms and can reuse effects in .NET MAUI - .NET MAUI | Microsoft Learn.

    For example, you can create a TouchEffect and implement android platform code about postion TouchAction like following code. As Note: I implement it for android platform, for iOS platform, you can refer to this GitHub demo

    #if ANDROID
    using Android.Views;
    using AndroidX.ConstraintLayout.Core.Widgets;
    
    #endif
    using Microsoft.Maui.Controls.Platform;
    using Microsoft.Maui.Platform;
    
    public enum TouchActionType
    {
        Entered,
        Pressed,
        Moved,
        Released,
        Exited,
        Cancelled
    }
    public class TouchActionEventArgs : EventArgs
    {
        public TouchActionEventArgs(long id, TouchActionType type, Point location, bool isInContact)
        {
            Id = id;
            Type = type;
            Location = location;
            IsInContact = isInContact;
        }
    
       public long Id { private set; get; }
    
       public TouchActionType Type { private set; get; }
    
       public Point Location { private set; get; }
    
       public bool IsInContact { private set; get; }
    }
    
    public delegate void TouchActionEventHandler(object sender, TouchActionEventArgs args);
    
    internal class TouchRoutingEffect : RoutingEffect
    {
        public event TouchActionEventHandler TouchAction;
    
    
       public TouchRoutingEffect()
        {
        }
    
       public bool Capture { set; get; }
    
       public void OnTouchAction(Element element, TouchActionEventArgs args)
        {
            TouchAction?.Invoke(element, args);
        }
    }
    
    
    #if ANDROID
    internal class TouchPlatformEffect : PlatformEffect
    {
        Android.Views.View view;
        Element formsElement;
        TouchRoutingEffect libTouchEffect;
        bool capture;
        Func<double, double> fromPixels;
        int[] twoIntArray = new int[2];
    
       static Dictionary<Android.Views.View, TouchPlatformEffect> viewDictionary =
            new Dictionary<Android.Views.View, TouchPlatformEffect>();
    
       static Dictionary<int, TouchPlatformEffect> idToEffectDictionary =
            new Dictionary<int, TouchPlatformEffect>();
        
        protected override void OnAttached()
        {
            // Get the Android View corresponding to the Element that the effect is attached to
            view = Control == null ? Container : Control;
    
    
           // Get access to the TouchEffect class in the .NET Standard library
            TouchRoutingEffect touchEffect =
                (TouchRoutingEffect)Element.Effects.
                    FirstOrDefault(e => e is TouchRoutingEffect);
    
           if (touchEffect != null && view != null)
            {
                viewDictionary.Add(view, this);
    
               formsElement = Element;
    
               libTouchEffect = touchEffect;
    
               // Save fromPixels function
                fromPixels = view.Context.FromPixels;
    
               // Set event handler on View
                view.Touch += OnTouch;
            }
        }
    
       protected override void OnDetached()
        {
            if (viewDictionary.ContainsKey(view))
            {
                viewDictionary.Remove(view);
                view.Touch -= OnTouch;
            }
        }
    
       void OnTouch(object sender, Android.Views.View.TouchEventArgs args)
        {
            // Two object common to all the events
            Android.Views.View senderView = sender as Android.Views.View;
            MotionEvent motionEvent = args.Event;
    
           // Get the pointer index
            int pointerIndex = motionEvent.ActionIndex;
    
           // Get the id that identifies a finger over the course of its progress
            int id = motionEvent.GetPointerId(pointerIndex);
            senderView.GetLocationOnScreen(twoIntArray);
            Point screenPointerCoords = new Point(twoIntArray[0] + motionEvent.GetX(pointerIndex),
                                                  twoIntArray[1] + motionEvent.GetY(pointerIndex));
    
    
            // Use ActionMasked here rather than Action to reduce the number of possibilities
            switch (args.Event.ActionMasked)
            {
                case MotionEventActions.Down:
                case MotionEventActions.PointerDown:
                    FireEvent(this, id, TouchActionType.Pressed, screenPointerCoords, true);
    
                   idToEffectDictionary.Add(id, this);
                   capture = libTouchEffect.Capture;
                    break;
               case MotionEventActions.Move:
                    // Multiple Move events are bundled, so handle them in a loop
                    for (pointerIndex = 0; pointerIndex < motionEvent.PointerCount; pointerIndex++)
                    {
                        id = motionEvent.GetPointerId(pointerIndex);
                       if (capture)
                        {
                            senderView.GetLocationOnScreen(twoIntArray);
                           screenPointerCoords = new Point(twoIntArray[0] + motionEvent.GetX(pointerIndex),
                                                            twoIntArray[1] + motionEvent.GetY(pointerIndex));
    
                           FireEvent(this, id, TouchActionType.Moved, screenPointerCoords, true);
                        }
                        else
                        {
                            CheckForBoundaryHop(id, screenPointerCoords);
    
    
    
    
                           if (idToEffectDictionary[id] != null)
                            {
                                FireEvent(idToEffectDictionary[id], id, TouchActionType.Moved, screenPointerCoords, true);
                            }
                        }
                    }
                    break;
    
               case MotionEventActions.Up:
                case MotionEventActions.Pointer1Up:
                    if (capture)
                    {
                        FireEvent(this, id, TouchActionType.Released, screenPointerCoords, false);
                    }
                    else
                    {
                        CheckForBoundaryHop(id, screenPointerCoords);
                       if (idToEffectDictionary[id] != null)
                        {
                            FireEvent(idToEffectDictionary[id], id, TouchActionType.Released, screenPointerCoords, false);
                        }
                    }
                    idToEffectDictionary.Remove(id);
                    break;
    
    
    
    
               case MotionEventActions.Cancel:
                    if (capture)
                    {
                        FireEvent(this, id, TouchActionType.Cancelled, screenPointerCoords, false);
                    }
                    else
                    {
                        if (idToEffectDictionary[id] != null)
                        {
                            FireEvent(idToEffectDictionary[id], id, TouchActionType.Cancelled, screenPointerCoords, false);
                        }
                    }
                    idToEffectDictionary.Remove(id);
                    break;
            }
        }
    
       void CheckForBoundaryHop(int id, Point pointerLocation)
        {
            TouchPlatformEffect touchEffectHit = null;
           foreach (Android.Views.View view in viewDictionary.Keys)
            {
                // Get the view rectangle
                try
                {
                    view.GetLocationOnScreen(twoIntArray);
                }
                catch // System.ObjectDisposedException: Cannot access a disposed object.
                {
                    continue;
                }
                Rectangle viewRect = new Rectangle();
                viewRect.SetBounds(twoIntArray[0], twoIntArray[1], view.Width, view.Height);
                if (viewRect.Contains((int)pointerLocation.X,(int)pointerLocation.Y))
                {
                    touchEffectHit = viewDictionary[view];
                }
            }
    
           if (touchEffectHit != idToEffectDictionary[id])
            {
                if (idToEffectDictionary[id] != null)
                {
                    FireEvent(idToEffectDictionary[id], id, TouchActionType.Exited, pointerLocation, true);
                }
                if (touchEffectHit != null)
                {
                    FireEvent(touchEffectHit, id, TouchActionType.Entered, pointerLocation, true);
                }
                idToEffectDictionary[id] = touchEffectHit;
            }
        }
    
       void FireEvent(TouchPlatformEffect touchEffect, int id, TouchActionType actionType, Point pointerLocation, bool isInContact)
        {
            // Get the method to call for firing events
            Action<Element, TouchActionEventArgs> onTouchAction = touchEffect.libTouchEffect.OnTouchAction;
    
           // Get the location of the pointer within the view
            touchEffect.view.GetLocationOnScreen(twoIntArray);
            double x = pointerLocation.X - twoIntArray[0];
            double y = pointerLocation.Y - twoIntArray[1];
            Point point = new Point(fromPixels(x), fromPixels(y));
    
           // Call the method
            onTouchAction(touchEffect.formsElement,
                new TouchActionEventArgs(id, actionType, point, isInContact));
        }
    }
    #elif IOS
    internal class TouchPlatformEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            // Customize the control here
        }
    
       protected override void OnDetached()
        {
            // Cleanup the control customization here
        }
    }
    #endif
    

    Then, Register this toucheffect in the MauiProgram.cs, I register it for android, that is same for iOS.

     public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
               .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                }).ConfigureEffects(effects =>
                {
    #if ANDROID
                    effects.Add<TouchRoutingEffect, TouchPlatformEffect>();
    #endif
                }
    

    In the end, you can use this toucheffect and get the touch position. I add this touchRoutingEffect to the outside stacklayout.

    
    
    <VerticalStackLayout  >
            <VerticalStackLayout.Effects>
                <local:TouchRoutingEffect TouchAction="TouchRoutingEffect_TouchAction"></local:TouchRoutingEffect>
            </VerticalStackLayout.Effects>
    

    Then We can get the position in the background code.

    private void TouchRoutingEffect_TouchAction(object sender, TouchActionEventArgs args)
        { 
            Point res=args.Location;
            Console.WriteLine(res.X+" ===="+res.Y.ToString());
        }
    

    Best Regards,

    Leon Lu


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


1 additional answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 77,926 Reputation points Volunteer Moderator
    2023-08-01T23:17:37.92+00:00

    android and iOS do not have a physical pointer (a pixel level selector). you probably want to use tap and swipe which is done with a finger.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.