A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
I have built a custom test environment to replicate your SwipeableListView scenario on iOS.
As suspected, the root cause is the IsVisible="False" property on your external <Label> and <Grid>. While Android sometimes overrides this when assigning an EmptyView, the iOS rendering engine strictly obeys the IsVisible="False" command and refuses to render the views.
I recommend removing the IsVisible="False" property and define your layouts inline directly inside the <ctrl:SwipeableListView.EmptyView> tags, rather than using an external x:Reference.
You can refer to my following code example:
Controls/SwipeableListView.cs:
using System.Collections;
using System.Windows.Input;
namespace _5930711.Controls
{
public class SwipeableListView : ContentView
{
private CollectionView _innerList;
public SwipeableListView()
{
_innerList = new CollectionView();
Content = _innerList;
}
public static readonly BindableProperty ItemsProperty = BindableProperty.Create(nameof(Items), typeof(IEnumerable), typeof(SwipeableListView), propertyChanged: OnItemsChanged);
public IEnumerable Items { get => (IEnumerable)GetValue(ItemsProperty); set => SetValue(ItemsProperty, value); }
private static void OnItemsChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is SwipeableListView view) view._innerList.ItemsSource = (IEnumerable)newValue;
}
public static readonly BindableProperty EmptyViewProperty = BindableProperty.Create(nameof(EmptyView), typeof(object), typeof(SwipeableListView), propertyChanged: OnEmptyViewChanged);
public object EmptyView { get => GetValue(EmptyViewProperty); set => SetValue(EmptyViewProperty, value); }
private static void OnEmptyViewChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is SwipeableListView view) view._innerList.EmptyView = newValue;
}
public static readonly BindableProperty LeftButtonCommandProperty = BindableProperty.Create(nameof(LeftButtonCommand), typeof(ICommand), typeof(SwipeableListView));
public ICommand LeftButtonCommand { get => (ICommand)GetValue(LeftButtonCommandProperty); set => SetValue(LeftButtonCommandProperty, value); }
public static readonly BindableProperty RightButtonCommandProperty = BindableProperty.Create(nameof(RightButtonCommand), typeof(ICommand), typeof(SwipeableListView));
public ICommand RightButtonCommand { get => (ICommand)GetValue(RightButtonCommandProperty); set => SetValue(RightButtonCommandProperty, value); }
public static readonly BindableProperty SelectedItemCommandProperty = BindableProperty.Create(nameof(SelectedItemCommand), typeof(ICommand), typeof(SwipeableListView));
public ICommand SelectedItemCommand { get => (ICommand)GetValue(SelectedItemCommandProperty); set => SetValue(SelectedItemCommandProperty, value); }
public bool LeftButtonEnabled { get; set; }
public bool RightButtonEnabled { get; set; }
}
}
ViewModels/MainViewModel.cs:
using System.Collections.ObjectModel;
namespace _5930711.ViewModels
{
public class MainViewModel
{
public ObservableCollection<string> ArchivedNotifications { get; set; } = new ObservableCollection<string>();
public ObservableCollection<string> Notifications { get; set; } = new ObservableCollection<string>();
public bool HasNoAlerts => true;
public string NoAlertsTitle { get; set; } = "You're all caught up!";
public string NoAlertsDescription { get; set; } = "No new alerts at this time.";
}
}
MainPage.xaml:
<?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"
xmlns:ctrl="clr-namespace:_5930711.Controls"
x:Class="_5930711.MainPage">
<VerticalStackLayout Spacing="20" Margin="10">
<Label Text="iOS EmptyView Fix Sandbox" FontSize="20" HorizontalOptions="Center" FontAttributes="Bold"/>
<ctrl:SwipeableListView
HeightRequest="150"
AutomationProperties.IsInAccessibleTree="False"
SelectedItemCommand="{Binding SelectedItemCommand, Mode=TwoWay}"
VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
LeftButtonEnabled="false"
RightButtonEnabled="true"
RightButtonCommand="{Binding UnarchiveCommand}"
Items="{Binding ArchivedNotifications}">
<ctrl:SwipeableListView.EmptyView>
<Label Text="No Alerts Archived (Fixed)"
AutomationProperties.IsInAccessibleTree="{Binding HasNoAlerts}" FontSize="Large"
VerticalTextAlignment="Center" HorizontalTextAlignment="Center" TextColor="Black"/>
</ctrl:SwipeableListView.EmptyView>
</ctrl:SwipeableListView>
<BoxView HeightRequest="2" Color="Gray" />
<ctrl:SwipeableListView
HeightRequest="300"
VerticalOptions="Fill" HorizontalOptions="Fill"
SelectedItemCommand="{Binding SelectedItemCommand, Mode=TwoWay}"
LeftButtonCommand="{Binding ReadCommand}"
LeftButtonEnabled="true"
RightButtonEnabled="true"
RightButtonCommand="{Binding ArchiveCommand}"
Items="{Binding Notifications}"
AutomationProperties.IsInAccessibleTree="False">
<ctrl:SwipeableListView.EmptyView>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60*" />
<RowDefinition Height="40*" />
</Grid.RowDefinitions>
<Image
Grid.Row="0" Margin="0,20,0,0" Aspect="AspectFill"
AutomationProperties.IsInAccessibleTree="False"
Source="dotnet_bot.png"
VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" />
<StackLayout
Grid.Row="1" VerticalOptions="Center" HorizontalOptions="Center">
<Label Text="{Binding NoAlertsTitle}" HorizontalTextAlignment="Center" FontSize="22" />
<Label Text="{Binding NoAlertsDescription}" HorizontalTextAlignment="Center" FontSize="17" />
</StackLayout>
</Grid>
</ctrl:SwipeableListView.EmptyView>
</ctrl:SwipeableListView>
</VerticalStackLayout>
</ContentPage>
MainPage.xaml.cs:
using _5930711.ViewModels;
namespace _5930711
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainViewModel();
}
}
}
Hope this helps. I would be happy to investigate further if needed. Thank you for your patience.