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.24k stars 1.76k forks source link

Span LineHeight Wrong on Android #19592

Closed bradencohen closed 7 months ago

bradencohen commented 10 months ago

Description

When using a generic Label with a Span, the LineHeight seems to be exponentially applied or something on Android.

I understand that there are platform differences, but this behavior simply doesn't work and isn't usable. Is there something I'm misunderstanding or missing?

<?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="MauiApp1.MainPage">
    <Grid x:Name="contentGrid">
        <Label LineBreakMode="WordWrap">
            <Label.FormattedText>
                <FormattedString>
                    <Span LineHeight="1.15">Outside, the church's garden was a haven of tranquility, where nature and spirituality intertwined harmoniously. Flowers bloomed in vibrant hues, each petal seemingly capturing a prayer or hope of the visitors who walked among them. The garden, lovingly tended by members of the congregation, reflected the church's commitment to nurturing not just the soul, but also the beauty of the world around it. It was a place where people of all walks of life could find solace, inspiration, and a sense of belonging within the embrace of the church's community.</Span>
                </FormattedString>
            </Label.FormattedText>
        </Label>
    </Grid>
</ContentPage>

image

When the LineHeight is removed: image

Xamarin

In Xamarin, this works as intended: image

Steps to Reproduce

  1. Pull the reproduction project
  2. Run and see

Or

  1. Paste the following XAML into a new MAUI project:
    <?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="MauiApp1.MainPage">
    <Grid x:Name="contentGrid">
        <Label LineBreakMode="WordWrap">
            <Label.FormattedText>
                <FormattedString>
                    <Span LineHeight="1.15">Outside, the church's garden was a haven of tranquility, where nature and spirituality intertwined harmoniously. Flowers bloomed in vibrant hues, each petal seemingly capturing a prayer or hope of the visitors who walked among them. The garden, lovingly tended by members of the congregation, reflected the church's commitment to nurturing not just the soul, but also the beauty of the world around it. It was a place where people of all walks of life could find solace, inspiration, and a sense of belonging within the embrace of the church's community.</Span>
                </FormattedString>
            </Label.FormattedText>
        </Label>
    </Grid>
    </ContentPage>

Link to public reproduction project repository

https://github.com/bradencohen/MauiRepros

Version with bug

8.0.3

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

No response

Did you find any workaround?

Nope, but any ideas would be super appreciated.

Relevant log output

No response

bradencohen commented 10 months ago

This only seems to apply to Android 33+

The ChooseHeight method seems to be getting called with a different "Top" value, which doesn't happen on Android 31.

image

bradencohen commented 10 months ago

Pretty ugly workaround to remove the LineHeight from the Span and put it on the outer Label:

private static void ConfigureLabelSpanLineHeightFix()
{
    //
    // This is a fix for labels that have spans with a LineHeight > 0.
    // This tracks issue: https://github.com/dotnet/maui/issues/19592
    //
    Microsoft.Maui.Handlers.LabelHandler.Mapper.AppendToMapping( "FixFirstLevelSpans", ( handler, label ) =>
    {
        if ( label is Label rockLabel )
        {
            var spansWithLineHeight = rockLabel.FormattedText?.Spans?.Where( s => s.LineHeight > 0 );
            var lineHeightBacking = 1d;

            if ( spansWithLineHeight == null )
            {
                return;
            }

            foreach ( var span in spansWithLineHeight )
            {
                if ( span.LineHeight > lineHeightBacking )
                {
                    lineHeightBacking = span.LineHeight;
                }

                span.LineHeight = 1;
            }

            rockLabel.LineHeight = lineHeightBacking;
        }
    } );
}
XamlTest commented 9 months ago

Verified this on Visual Studio Enterprise 17.9.0 Preview 3(8.0.3 and 7.0.101). Repro on Android 14.0-API34, not repro on Windows 11, iOS 17.0 and MacCatalyst with below Project: MauiRepros.zip