Solving the .NET MAUI RefreshView Limitation on macOS: building a MAUI CustomRefreshView from scratch for all platforms
The built-in RefreshView control in .NET MAUI enables pull-to-refresh functionality for scrollable content. However, as of .NET MAUI 9, RefreshView is not supported on macOS. Attempting to use it will result in runtime errors or simply no refresh gesture support.
- The underlying gesture and native control implementation for RefreshView is missing on macOS.
- The official documentation and GitHub issues confirm this limitation.
- macOS users cannot trigger refresh actions via pull gestures.
- UI consistency and user experience are affected.
Here some Microsoft documentation about it:
- Specify the UI idiom for your Mac Catalyst app - .NET MAUI | Microsoft Learn
- RefreshView Class (Microsoft.Maui.Controls) | Microsoft Learn
- Customize UI appearance based on the platform and device idiom - .NET MAUI | Microsoft Learn
UIStepper, UIPickerView, and UIRefreshControl aren't supported in the Mac user interface idiom by Apple. This means that the .NET MAUI controls that consume these native controls (Stepper, Picker and RefreshView) can't be used in the Mac user interface idiom. Attempting to do so will throw a macOS exception.
In addition, the following constraints apply in the Mac user interface idiom:
- UISwitch throws a macOS exception when it's title is set in a non-Mac idiom view.
- UIButton throws a macOS exception when AddGestureRecognizer is called, or when SetTitle or SetImage are called for any state except
UIControlStateNormal.Normal
. - UISlider throws a macOS exception when the SetThumbImage, SetMinTrackImage, SetMaxTrackImage methods are called and when the ThumbTintColor, MinimumTrackTintColor, MaximumTrackTintColor, MinValueImage, MaxValueImage properties are set.
Here an example of how to use the component
<components:CustomRefreshView
IndicatorBackground="{StaticResource Gray100}"
IndicatorPosition="Top"
IndicatorText="Loading data..."
IndicatorTextColor="{StaticResource OffBlack}"
IsRefreshing="{Binding IsRefreshing}"
RefreshColor="{AppThemeBinding Light={StaticResource Primary10},
Dark={StaticResource Primary10}}"
RefreshCommand="{Binding RefreshCommand}">
<components:CustomRefreshView.RefreshContent>
</components:CustomRefreshView.RefreshContent>
</components:CustomRefreshView>