xamarin.formsmaui

Move control freely inside AbsoluteLayout in .Net Maui


I'm trying to make a layout that allow me to move controls inside it freely, I found a working solution but it has a very strange behavior, when I try to move the label, the movement is very laggy and sometimis it has an effect like it duplicate the label.

I implemented the movement with a PanGestureRecognizer adding labels inside an AbsoluteLayout programatically with a button event

This is the XAML, with the empty AbsoluteLayout and the button at the end to add de label

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Views.MoveControlsView"
             Title="MoveControlsView">
    <StackLayout>
        <AbsoluteLayout
            x:Name="ParentLayout"
            VerticalOptions="FillAndExpand"
            HorizontalOptions="FillAndExpand">
        </AbsoluteLayout>
        
        <StackLayout
            HorizontalOptions="FillAndExpand"
            VerticalOptions="End">
            <Button
                x:Name="AddLabel"
                Text="Add label"
                Clicked="AddLabel_Clicked"/>
        </StackLayout>
    </StackLayout>
</ContentPage>

This is the code behind, I generate a Label when the button is clicked and add to it the PanGestureRecognizer that I also suscribed it to the PanUpdated event.

public partial class MoveControlsView : ContentPage
{
    public MoveControlsView()
    {
        InitializeComponent();
    }

    private void AddLabel_Clicked(object sender, EventArgs e)
    {
        var label = new Label() 
        { 
            Text = "This is a label", 
            BackgroundColor = Colors.LightGray, 
            Padding = 10
        }; 
        
        var panGesture = new PanGestureRecognizer();
        panGesture.PanUpdated += PanGestureRecognizer_PanUpdated;

        label.GestureRecognizers.Add(panGesture);

        ParentLayout.Children.Add(label);
    }
    private void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)
    {
        var label = sender as Label;
        switch (e.StatusType)
        {
            case GestureStatus.Running:
                label.TranslationX = e.TotalX;
                label.TranslationY = e.TotalY;
                break;
            case GestureStatus.Completed:
                label.TranslateTo(label.TranslationX, label.TranslationY);
                break;
        }
    }
}

Solution

  • You could make changes to the code in PanGestureRecognizer_PanUpdated event handler. Try the following code:

        double tempx = 0;
        double tempy = 0;
        private void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)
        {
            var label = sender as Label;
            switch (e.StatusType)
            {
                case GestureStatus.Started:
                    if(Device.RuntimePlatform == Device.iOS)
                    {
                        tempx = label.TranslationX;
                        tempy = label.TranslationY;
                    }
    
                    break;
    
                case GestureStatus.Running:
                    if (Device.RuntimePlatform  == Device.iOS)
                    {
                        label.TranslationX = e.TotalX + tempx;
                        label.TranslationY = e.TotalY + tempy;
                    }
                    else if (Device.RuntimePlatform == Device.Android)
                    {
                        label.TranslationX += e.TotalX;
                        label.TranslationY += e.TotalY;
                    }
    
                    break;
                case GestureStatus.Completed:
                    tempx = label.TranslationX;                  
                    tempy = label.TranslationY;
    
                    break;
            }
        }
    

    For more information, you could refer to Xamarin.Forms AbsoluteLayout and Add a pan gesture recognizer

    Hope it works for you.