Maui icon indicating copy to clipboard operation
Maui copied to clipboard

[BUG] Popup layout is broken

Open WMLPB opened this issue 1 year ago • 1 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Did you read the "Reporting a bug" section on Contributing file?

  • [X] I have read the "Reporting a bug" section on Contributing file: https://github.com/CommunityToolkit/Maui/blob/main/CONTRIBUTING.md#reporting-a-bug

Current Behavior

First – I’m sorry, I can’t provide a repository. I’m not allowed to upload a repository by company policy, and I’ve created my Github account only to report bugs. But the steps to reproduce the layout problems of the Popup are very straight forward and I hope, you can fix this anyways: The layout of the Popup is broken.

Expected Behavior

The layout of the Popup should work.

Steps To Reproduce

This is, what I want to get:

Screenshot1

<StackLayout Padding="10" Spacing="6">
    <Button Text="Menüeintrag 1"/>
    <Button Text="Menüeintrag 2"/>
    <Button Text="Menüeintrag 3"/>
    <Button Text="Menüeintrag 4"/>
    <Button Text="Menüeintrag 5"/>
    <Button Text="Menüeintrag 6"/>
    <Button Text="Menüeintrag 7"/>
    <Button Text="Menüeintrag 8"/>
    <Button Text="Menüeintrag 9"/>
    <Button Text="Menüeintrag 10"/>
</StackLayout>

The Popup adjusts its Width to the content – because the Width can be different in different languages or situations. This works fine. But I also want to be able to scroll the items in landscape mode. So I put the StackLayout into a ScrollView:

Screenshot2

<ScrollView>
    <StackLayout Padding="10" Spacing="6">
        <Button Text="Menüeintrag 1"/>
        <Button Text="Menüeintrag 2"/>
        <Button Text="Menüeintrag 3"/>
        <Button Text="Menüeintrag 4"/>
        <Button Text="Menüeintrag 5"/>
        <Button Text="Menüeintrag 6"/>
        <Button Text="Menüeintrag 7"/>
        <Button Text="Menüeintrag 8"/>
        <Button Text="Menüeintrag 9"/>
        <Button Text="Menüeintrag 12"/>
    </StackLayout>
</ScrollView>

Now the layout is broken. I’ve reported this bug almost a year ago (https://github.com/CommunityToolkit/Maui/issues/1516), I’ve found a work around. Using DevExpress DXScrollView instead of ScrollView fixes the problem, too. But I think this should work with the MAUI standard controls, as well.

For the second layout issue I sadly don’t have a workaround:

Screenshot3

<StackLayout Padding="10" Spacing="6">
    <Button Text="Item 1"/>
    <Button Text="Item 2"/>
    <Button Text="This button has a very long text that is simply cut off in the middle."/>
</StackLayout>

The Popup can’t get wider than 320 Units anymore. The MaximumWidthRequest seems to be limited by this value – hard coded into the Popup control.

Link to public reproduction project repository

https://github.com/CommunityToolkit/Maui

Environment

- .NET MAUI CommunityToolkit: 9.1.0
- OS: Android 14
- .NET MAUI: 8.0.91

Anything else?

Thank you very much for help.

WMLPB avatar Sep 30 '24 13:09 WMLPB

Hi All,

based on this excellent blog post by Redth from the MAUI team, I now use the following PopupPage:

public class PopupPage : ContentPage
{
	private View _outerView = null;
	private View _innerView = null;

	public event EventHandler Closed;
	public event EventHandler Clicked;

	public static readonly BindableProperty ColorProperty =
		BindableProperty.Create(nameof(Color), typeof(Color), typeof(PopupPage), Colors.White);

	public static readonly BindableProperty BackdropProperty =
		BindableProperty.Create(nameof(Backdrop), typeof(Color), typeof(PopupPage), Colors.Transparent);

	public static readonly BindableProperty CanBeDismissedByTappingOutsideOfPopupProperty =
		BindableProperty.Create(nameof(CanBeDismissedByTappingOutsideOfPopup), typeof(bool), typeof(PopupPage), true);

	public static readonly BindableProperty VerticalOptionsProperty =
		BindableProperty.Create(nameof(VerticalOptions), typeof(LayoutOptions), typeof(PopupPage), LayoutOptions.Center);

	public static readonly BindableProperty HorizontalOptionsProperty =
		BindableProperty.Create(nameof(HorizontalOptions), typeof(LayoutOptions), typeof(PopupPage), LayoutOptions.Center);

	public static readonly BindableProperty IsAnimatedProperty =
		BindableProperty.Create(nameof(IsAnimated), typeof(bool), typeof(PopupPage), true);

	public Color Color
	{
		get => (Color)GetValue(ColorProperty);
		set => SetValue(ColorProperty, value);
	}

	public Color Backdrop
	{
		get => (Color)GetValue(BackdropProperty);
		set => SetValue(BackdropProperty, value);
	}

	public bool CanBeDismissedByTappingOutsideOfPopup
	{
		get => (bool)GetValue(CanBeDismissedByTappingOutsideOfPopupProperty);
		set => SetValue(CanBeDismissedByTappingOutsideOfPopupProperty, value);
	}

	public LayoutOptions VerticalOptions
	{
		get => (LayoutOptions)GetValue(VerticalOptionsProperty);
		set => SetValue(VerticalOptionsProperty, value);
	}

	public LayoutOptions HorizontalOptions
	{
		get => (LayoutOptions)GetValue(HorizontalOptionsProperty);
		set => SetValue(HorizontalOptionsProperty, value);
	}

	public bool IsAnimated
	{
		get => (bool)GetValue(IsAnimatedProperty);
		set => SetValue(IsAnimatedProperty, value);
	}

	public PopupPage() : base()
	{
		Opacity = 0;
		NavigatedTo += PopupPage_NavigatedTo;
	}

	protected override void OnApplyTemplate()
	{
		base.OnApplyTemplate();

		_outerView = (View)this.GetTemplateChild("Outer_Content");
		_innerView = (View)this.GetTemplateChild("Inner_Content");

		if (_outerView is object)
		{
			TapGestureRecognizer tap = new TapGestureRecognizer();
			tap.Command = new Command(OnClickedOutside);

			_outerView.GestureRecognizers.Add(tap);
		}

		if (_innerView is object)
		{
			if (IsAnimated)
				_innerView.IsVisible = false;

			TapGestureRecognizer tap = new TapGestureRecognizer();
			tap.Command = new Command(OnClicked);

			_innerView.GestureRecognizers.Add(tap);
		}
	}

	private async void PopupPage_NavigatedTo(object sender, NavigatedToEventArgs e)
	{
		NavigatedTo -= PopupPage_NavigatedTo;

		if (IsAnimated)
			await this.FadeTo(1, 250, Easing.Linear);

		Opacity = 1;

		if (_innerView is object)
			_innerView.IsVisible = true;
	}

	protected override bool OnBackButtonPressed()
	{
		Close();
		return true;
	}

	protected void OnClicked(object sender)
	{
		if (Clicked != null)
			this.Clicked(this, EventArgs.Empty);
	}

	protected void OnClickedOutside(object sender)
	{
		if (CanBeDismissedByTappingOutsideOfPopup)
			Close();
	}

	async Task CloseAsync()
	{
		if (IsAnimated)
		{
			if (_innerView is object)
				_innerView.IsVisible = false;

			await this.FadeTo(0, 250, Easing.Linear);
		}

		await Navigation.PopModalAsync(animated: false);
		Closed?.Invoke(this, EventArgs.Empty);
	}

	public async void Close()
	{
		await CloseAsync();
	}
}
<ControlTemplate x:Key="PopupPageTemplate">
    <ContentView x:Name="Outer_Content" BackgroundColor="{TemplateBinding Backdrop}">
        <ContentPresenter x:Name="Inner_Content" Content="{TemplateBinding Content}" BackgroundColor="{TemplateBinding Color}" HorizontalOptions="{TemplateBinding HorizontalOptions}" VerticalOptions="{TemplateBinding VerticalOptions}">
            <ContentPresenter.Shadow>
                <Shadow Brush="Black" Offset="0,0" Radius="20" Opacity="0.5" />
            </ContentPresenter.Shadow>
        </ContentPresenter>
    </ContentView>
</ControlTemplate>
<Style TargetType="e:PopupPage" ApplyToDerivedTypes="True">
    <Setter Property="ControlTemplate" Value="{StaticResource PopupPageTemplate}" />

    <Setter Property="Color" Value="White" />
    <Setter Property="Backdrop" Value="#40000000" />
    <Setter Property="BackgroundColor" Value="Transparent" />

    <Setter Property="HorizontalOptions" Value="Center" />
    <Setter Property="VerticalOptions" Value="Center" />
</Style>

WMLPB avatar Oct 02 '24 08:10 WMLPB