XAML 如何在.NET MAUI中平滑地移动框架?

6qqygrtg  于 2023-08-01  发布在  .NET
关注(0)|答案(1)|浏览(139)

我正在从Xamarin过渡到.NET MAUI,并为我的应用程序创建了一个底部表单,并希望有一个平滑的动画上升和下降。但是即使我使用的是Easing.SinIn,也没有平滑的过渡,只是突然上升和下降。此外,BottomSheet.TranslateTo(BottomSheet.X, finalTranslation, 450, Easing.SinIn);BottomSheet.TranslateTo(BottomSheet.X, finalTranslation, 450);做同样的事情,即使它们的行为不同。下面的代码是我为底部工作表的过渡而编写的,因此底部工作表的上下高度取决于底部工作表中上下文的高度。当我点击底部表单时,它会上下移动,因为底部表单的高度取决于上下文的高度,所以效果很好。我只是需要一个平稳的过渡,上下,但不知何故,它不工作。

private void MoveBottomSheet(bool close)
    {
        double initialTranslation = Microsoft.Maui.Devices.DeviceInfo.Idiom == Microsoft.Maui.Devices.DeviceIdiom.Phone ? -5.0 : -15.0;
        double maxContentHeight = ContextDescription.Height;
        double maxTranslation = maxContentHeight + 20.0;
        double finalTranslation;

        if (_isInitialOpen)
        {
            // set the initial position of the bottom sheet here
            finalTranslation = initialTranslation;
            _isInitialOpen = false;
        }
        else
        {
            finalTranslation = close ? initialTranslation : -maxTranslation;
        }
        Debug.WriteLine($"finalTranslation: {finalTranslation}");
        BottomSheet.TranslateTo(BottomSheet.X, finalTranslation, 450, Easing.SinIn);
    }

字符串

olhwl3o2

olhwl3o21#

这可能与过渡的持续时间有关。我写了一个自定义控件:可以平稳地上升和下降的BottomSheet。可以参考示例代码:
1.创建BottomSheetControl.cs

public partial class BottomSheetControl : ContentView
{
    public BottomSheetControl()
    {
        InitializeComponent();
    }
    protected override void OnBindingContextChanged()
    {
        try
        {
            base.OnBindingContextChanged();
            PanContainerRef.Content.TranslationY = SheetHeight + 60;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
    #region Properties

    public static BindableProperty SheetHeightProperty = BindableProperty.Create(
        nameof(SheetHeight),
        typeof(double),
        typeof(BottomSheetControl),
        defaultValue: default(double),
        defaultBindingMode: BindingMode.TwoWay);
    public double SheetHeight
    {
        get { return (double)GetValue(SheetHeightProperty); }
        set { SetValue(SheetHeightProperty, value); OnPropertyChanged(); }
    }

    public static BindableProperty SheetContentProperty = BindableProperty.Create(
        nameof(SheetContent),
        typeof(View),
        typeof(BottomSheetControl),
        defaultValue: default(View),
        defaultBindingMode: BindingMode.TwoWay);

    public View SheetContent
    {
        get { return (View)GetValue(SheetContentProperty); }
        set { SetValue(SheetContentProperty, value); OnPropertyChanged(); }
    }
    #endregion

    uint duration = 800;
    double openPosition = (Microsoft.Maui.Devices.DeviceInfo.Platform == DevicePlatform.Android) ? 20 : 60;
    double currentPosition = 0;

    public async void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)
    {
        try
        {
            if (e.StatusType == GestureStatus.Running)
            {
                currentPosition = e.TotalY;
                if (e.TotalY > 0)
                {
                    PanContainerRef.Content.TranslationY = openPosition + e.TotalY;
                }
            }
            else if (e.StatusType == GestureStatus.Completed)
            {
                var threshold = SheetHeight * 0.55;
                if (currentPosition < threshold)
                {
                    await OpenSheet();
                }
                else
                {
                    await CloseSheet();
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    public async Task OpenSheet()
    {
        try
        {
            await Task.WhenAll
            (
                Backdrop.FadeTo(0.4, length: duration),
                BottomSheet.TranslateTo(0, openPosition, length: duration, easing: Easing.SinIn)
            );
            BottomSheetRef.InputTransparent = Backdrop.InputTransparent = false;
        }

        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
    public async Task CloseSheet()
    {
        try
        {
            await Task.WhenAll
            (
                Backdrop.FadeTo(0, length: duration),
                PanContainerRef.Content.TranslateTo(x: 0, y: SheetHeight + 60, length: duration, easing: Easing.SinIn)
            );
            BottomSheetRef.InputTransparent = Backdrop.InputTransparent = true;
        }

        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

    }

    async void TapGestureRecognizer_Tapped(System.Object sender, System.EventArgs e)
    {
        try
        {
            await CloseSheet();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
}

字符串

XAML代码:

<Grid>
     <BoxView Color="Black"
                 Opacity="0"
                 InputTransparent="True"
                 x:Name="Backdrop">
          <BoxView.GestureRecognizers>
                <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
          </BoxView.GestureRecognizers>
     </BoxView>

    <controls:PanContainer x:Name="PanContainerRef"
                                   HeightRequest="{Binding SheetHeight, Source={x:Reference BottomSheetRef}}"
                                   VerticalOptions="End">
            <controls:PanContainer.GestureRecognizers>
                <PanGestureRecognizer PanUpdated="PanGestureRecognizer_PanUpdated"/>
            </controls:PanContainer.GestureRecognizers>

          <Frame x:Name="BottomSheet"
                   Content="{Binding SheetContent ,Source={x:Reference BottomSheetRef}}"
                   HeightRequest="{Binding SheetHeight, Source={x:Reference BottomSheetRef}}"
                   VerticalOptions="End"
                   BackgroundColor="White"
                   CornerRadius="5"
                   HasShadow="False">
         </Frame>
      </controls:PanContainer>
</Grid>


1.创建容器:PanContainer.cs

public class PanContainer : ContentView 
{
    public PanContainer()
    {
    }
}


1.然后在NewPage1中使用它。

<?xml version="1.0" encoding="utf-8" ?> 
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp2.NewPage1"
             xmlns:controls="clr-namespace:MauiApp2.Controls"
             Title="NewPage1">
    <Grid>
        <VerticalStackLayout HorizontalOptions="Center">
            <Button Text="Tap Open!" Clicked="Button_Open" VerticalOptions="Center"/>
            <Button Text="Tap Close!" Clicked="Button_Close" VerticalOptions="Center"/>
        </VerticalStackLayout>

        <controls:BottomSheetControl x:Name="Sheet"
                                         SheetHeight="300">
            <controls:BottomSheetControl.SheetContent>
                <VerticalStackLayout>

                    <Label HorizontalTextAlignment="Center"
                           Margin="0,20"
                           Text="Bottom Sheet Test"
                           FontSize="18"/>

                    <Image Source="dotnet_bot" HorizontalOptions="Center"/>
                </VerticalStackLayout>
            </controls:BottomSheetControl.SheetContent>
        </controls:BottomSheetControl>
    </Grid>
</ContentPage>

代码隐藏:

async void Button_Open(object sender, EventArgs e) 
{  
     await Sheet.OpenSheet();     
}

async void Button_Close(object sender, EventArgs e)
{
     await Sheet.CloseSheet();   
}

相关问题