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.