dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.22k stars 1.75k forks source link

Drag page to Dismiss #7355

Open L10Messi10 opened 2 years ago

L10Messi10 commented 2 years ago

Description

I would love to have a feature that drags the page and dismiss the page, this feature is common to Facebook app

Public API Changes

Page.DragToDismiss();

Intended Use-Case

In my app, I have a modal page that I want to drag to dismiss. With this feature, the user can still see the content of the page while dragging to close the page. This feature is useful while reviewing the content of the page.

VladislavAntonyuk commented 2 years ago

Do you mean something like this: https://github.com/grendio/XBottomSheet

L10Messi10 commented 2 years ago

Do you mean something like this: https://github.com/grendio/XBottomSheet

Yeah, something like that. Have you tried it with .Net MAUI?

VladislavAntonyuk commented 2 years ago

Do you mean something like this: https://github.com/grendio/XBottomSheet

Yeah, something like that. Have you tried it with .Net MAUI?

I haven't tried exactly this package. I remember I found Xamarin.Forms package. It worked fine on iOS because it was a native control, but it wasn't fluent on Android.

L10Messi10 commented 2 years ago

Do you mean something like this: https://github.com/grendio/XBottomSheet

Yeah, something like that. Have you tried it with .Net MAUI?

I haven't tried exactly this package. I remember I found Xamarin.Forms package. It worked fine on iOS because it was a native control, but it wasn't fluent on Android.

I hope the team will look into this, this is a very helpful feature..

ghost commented 1 year ago

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

Alex-stewart1 commented 8 months ago

The code to write it yourself isn't actually that bad. I wrote a simple "DismissibleBorder" in an hour or two. It allows a border to be dragged down to some threshold which triggers a "DismissThresholdReached" event allowing the developer to close the page/popup/whatever however they like. For anyone interested I have attached the code

public class DismissibleBorder : Border
{
    private readonly WeakEventManager _eventManager = new();

    public event EventHandler<EventArgs> DismissThresholdReached
    {
        add => _eventManager.AddEventHandler(value);
        remove => _eventManager.RemoveEventHandler(value);
    }
    public event EventHandler<EventArgs> DismissThresholdNotReached
    {
        add => _eventManager.AddEventHandler(value);
        remove => _eventManager.RemoveEventHandler(value);
    }

    public static readonly BindableProperty DismissThresholdProperty = BindableProperty.Create(
        nameof(DismissThreshold),
        typeof(double),
        typeof(DismissibleBorder),
        defaultValue: 0.5);

    public double DismissThreshold
    {
        get => (double)GetValue(DismissThresholdProperty);
        set
        {
            if (value <= 0 || value >= 1)
            {
                throw new ArgumentOutOfRangeException(nameof(DismissThreshold), "DismissThreshold must be between 0 and 1");
            }
            SetValue(DismissThresholdProperty, value);
        }
    }

    public DismissibleBorder()
    {
        var panGesture = new PanGestureRecognizer();
        panGesture.PanUpdated += PanGesture_PanUpdated;
        GestureRecognizers.Add(panGesture);
    }

    private double panY = 0;
    private void PanGesture_PanUpdated(object? sender, PanUpdatedEventArgs e)
    {
        switch (e.StatusType)
        {
            case GestureStatus.Running:
                panY = Math.Max(panY + e.TotalY, 0);
                TranslationY = panY;
                break;

            case GestureStatus.Completed:
                // Store the translation applied during the pan
                if (panY > DismissThreshold * Height)
                {
                    //Dismiss
                    TranslationY = Height - 5;
                    panY = TranslationY;
                    _eventManager.HandleEvent(this, EventArgs.Empty, nameof(DismissThresholdReached));
                }
                else
                {
                    //Don't Dismiss
                    TranslationY = 0;
                    panY = TranslationY;
                    _eventManager.HandleEvent(this, EventArgs.Empty, nameof(DismissThresholdNotReached));
                }

                break;
        }
    }
}

Example usage within a popup page

 <controls:DismissibleBorder
     x:Name="DismissibleBorder"
     DismissThresholdReached="DismissibleBorder_DismissThresholdReached"
     HeightRequest="500"
     DismissThreshold="0.8"
     HorizontalOptions="Fill"
     VerticalOptions="End">
     <Border.StrokeShape>
         <RoundRectangle CornerRadius="25,25,0,0" />
     </Border.StrokeShape>
     <Grid RowDefinitions="15,*">
         <Rectangle
             BackgroundColor="LightGrey"
             HeightRequest="5"
             WidthRequest="20" />
         <ContentView Grid.Row="1" />
     </Grid>
 </controls:DismissibleBorder>

Result with mopups (not laggy, thats just the gif)

qemu-system-x86_64_qpfrruaqxG