Search code examples
c#iosmaui

CollectionView in iOS doesn't render properly in iOS and macOS


In my .NET8 MAUI project, I have a CollectionView to display some elements. This collection is working on Windows and Android.

<CollectionView
    Margin="{OnIdiom '20,0,20,0',
                        Desktop='20,0,20,0'}"
    HorizontalOptions="FillAndExpand"
    IsVisible="{Binding ShowArticles}"
    ItemsSource="{Binding NewestArticles}"
    SelectionChanged="CollectionView_SelectionChanged"
    SelectionMode="Single"
    VerticalOptions="FillAndExpand">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout ItemSpacing="10" Orientation="Horizontal" />
    </CollectionView.ItemsLayout>
    <CollectionView.ItemTemplate>
        <DataTemplate x:DataType="artModel:NewestArticle">
            <Grid
                Margin="5,5,5,5"
                ColumnSpacing="10"
                HorizontalOptions="FillAndExpand"
                VerticalOptions="FillAndExpand"
                WidthRequest="300">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>

                <Image
                    Grid.ColumnSpan="3"
                    Margin="0,0,0,15"
                    Aspect="AspectFill"
                    HeightRequest="200"
                    HorizontalOptions="FillAndExpand"
                    VerticalOptions="FillAndExpand"
                    WidthRequest="300">
                    <Image.Source>
                        <UriImageSource CacheValidity="10:00:00:00" Uri="{Binding FeaturedImage}" />
                    </Image.Source>
                    <Image.Clip>
                        <RoundRectangleGeometry CornerRadius="25" Rect="0,0,300,200" />
                    </Image.Clip>
                </Image>

                <VerticalStackLayout
                    Grid.Row="1"
                    HorizontalOptions="FillAndExpand"
                    VerticalOptions="FillAndExpand">
                    <components:LanguageLevelBadge
                        BgColor="{Binding BadgeColor}"
                        Text="{Binding BadgeText}"
                        VerticalOptions="StartAndExpand" />

                    <components:FlagBadge FlagUrl="{Binding FlagUrl}" />
                </VerticalStackLayout>

                <VerticalStackLayout
                    Grid.Row="1"
                    Grid.Column="1"
                    HorizontalOptions="FillAndExpand"
                    VerticalOptions="FillAndExpand">

                    <Label Style="{StaticResource PostTitle}" Text="{Binding Title}" />
                    <Label Style="{StaticResource PostExcerpt}" Text="{Binding Excerpt}" />
                    <Label Style="{StaticResource PostCategory}" Text="{Binding Category}" />
                </VerticalStackLayout>
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

The result for Windows and Android is like that

CollectionView render for Windows

When I run the project for iOS and macOS, the render is completely wrong and partial.

enter image description here

Do you know if there is any issue with the CollectionView for those platforms? How can I fix this issue?

Update/2

The LanguageLevelBadge and FlagBadge are two similar components. Here the LanguageLevelBadge

<?xml version="1.0" encoding="utf-8" ?>
<ContentView
    x:Class="LanguageInUse.Components.LanguageLevelBadge"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Name="llb">

    <HorizontalStackLayout BindingContext="{x:Reference llb}">
        <Label
            Margin="2"
            Padding="5,5"
            BackgroundColor="{Binding BgColor}"
            HorizontalOptions="Center"
            Text="{Binding Text}"
            TextColor="{Binding Color}"
            VerticalOptions="Center" />
    </HorizontalStackLayout>
</ContentView>

and the code behind

public partial class LanguageLevelBadge : ContentView
{
    public static readonly BindableProperty LevelProperty = BindableProperty.Create(nameof(Level), typeof(LanguageLevel), typeof(LanguageLevelBadge));
    public static readonly BindableProperty BgColorProperty = BindableProperty.Create(nameof(BgColor), typeof(string), typeof(LanguageLevelBadge));
    public static readonly BindableProperty ColorProperty = BindableProperty.Create(nameof(Color), typeof(string), typeof(LanguageLevelBadge), "#FFFFFF");
    public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(LanguageLevelBadge));

    public string BgColor
    {
        get => GetValue(BgColorProperty) as string;
        set => SetValue(BgColorProperty, value);
    }

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

    public string Text
    {
        get => GetValue(TextProperty) as string;
        set { 
            SetValue(TextProperty, value);
            BgColor = Level.GetColor();
        }
    }

    public LanguageLevel Level
    {
        get => (LanguageLevel)GetValue(LevelProperty);
        set => SetValue(LevelProperty, value);
    }

    public LanguageLevelBadge()
    {
        InitializeComponent();
    }
}

This is the code for FlagBadge

<?xml version="1.0" encoding="utf-8" ?>
<ContentView
    x:Class="LanguageInUse.Components.FlagBadge"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Name="fb">

    <Border
        Background="{Binding InternalFrameColor}"
        BindingContext="{x:Reference fb}"
        HorizontalOptions="FillAndExpand"
        MaximumHeightRequest="{Binding MaxHeight}"
        Stroke="{StaticResource Primary24}"
        StrokeShape="RoundRectangle 10"
        StrokeThickness="2"
        VerticalOptions="FillAndExpand">
        <Image
            x:Name="imageFlag"
            Aspect="AspectFill"
            MaximumHeightRequest="{Binding MaxHeight}"
            Source="{Binding FlagUrl}" />
    </Border>
</ContentView>

and the code is

public partial class FlagBadge : ContentView
{
    #region Bindable properties

    public static readonly BindableProperty MaxHeightProperty = BindableProperty.Create(nameof(MaxHeight), typeof(double), typeof(WordCheck), (double)28);
    public static readonly BindableProperty FlagUrlProperty = BindableProperty.Create(nameof(FlagUrl), typeof(string), typeof(WordCheck));

    /// <summary>
    /// Gets or sets the maximum height.
    /// </summary>
    /// <value>The maximum height.</value>
    public double MaxHeight
    {
        get => (double)GetValue(MaxHeightProperty);
        set => SetValue(MaxHeightProperty, value);
    }

    /// <summary>
    /// Gets or sets the flag URL.
    /// </summary>
    /// <value>The flag URL.</value>
    public string FlagUrl
    {
        get => GetValue(FlagUrlProperty) as string;
        set => SetValue(FlagUrlProperty, value);
    }

    #endregion
    public FlagBadge()
    {
        InitializeComponent();
    }
}

Update/3

Thank you Liqun Shen-MSFT for the solution although now I have a funny behaviour in the CollectionView. It becomes very long and I have to scroll the page a lot to find the next components.

enter image description here

and in the screenshot there is just a small part. Althoug I changed the VerticalOptions to Start or I remove it, the CollectionView is still very long. If I set the MaximumHeightRequest in the Grid, the CollevtionView doesn't change its height.

Is it better if I replace the CollectionView with a ListView like in this post?


Solution

  • I reproduce this question on iOS. There should be some render differences among different platforms. The FlagBadge component is the one which causes the color bar below the LanguageLevelBadge.

    As a workaround, in FlagBadge you may change Image.Aspect to AspectFit, which lets the entire image fits into the display area,

    <Image
        x:Name="imageFlag"
        Aspect="AspectFit"
        MaximumHeightRequest="28"
        Source="{Binding FlagUrl}" />
    

    For more info, please refer to Control image scaling.