Palmy.Maui.PullToRefresh 1.1.0

dotnet add package Palmy.Maui.PullToRefresh --version 1.1.0
                    
NuGet\Install-Package Palmy.Maui.PullToRefresh -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Palmy.Maui.PullToRefresh" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Palmy.Maui.PullToRefresh" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Palmy.Maui.PullToRefresh" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Palmy.Maui.PullToRefresh --version 1.1.0
                    
#r "nuget: Palmy.Maui.PullToRefresh, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Palmy.Maui.PullToRefresh@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Palmy.Maui.PullToRefresh&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Palmy.Maui.PullToRefresh&version=1.1.0
                    
Install as a Cake Tool

Palmy.Maui.PullToRefresh NuGet

A highly customizable pull-to-refresh control for .NET MAUI that allows developers to replace the default refresh indicator with custom animated views.

Car Demo Shop Demo Weather Demo Tickets Demo
Car Shop Weather Tickets

Features

  • Custom refresh indicator — use any MAUI View (Lottie animations, images, custom layouts)
  • Two display modes: Normal (pushes content down) and Overlay (floats above content)
  • Fine-grained pull state tracking via the Pulling event
  • Configurable pull distance, refresh height, and animation easing
  • MVVM-friendly with bindable RefreshCommand and IsRefreshing properties
  • Supports Android and iOS

Installation

dotnet add package Palmy.Maui.PullToRefresh

Quick Start

1. Add the namespace

xmlns:pullToRefresh="clr-namespace:Palmy.Maui.PullToRefresh;assembly=Palmy.Maui.PullToRefresh"

2. Basic usage (Normal mode)

Wrap your scrollable content with PullToRefreshView and provide a custom RefreshView:

<pullToRefresh:PullToRefreshView IsRefreshing="{Binding IsRefreshing}"
                                 RefreshCommand="{Binding RefreshCommand}"
                                 MaxPullDistance="160"
                                 RefreshHeight="80"
                                 Type="Normal">

    
    <pullToRefresh:PullToRefreshView.RefreshView>
        <Border BackgroundColor="#6200EE"
                HeightRequest="80"
                StrokeThickness="0">
            <ActivityIndicator IsRunning="True"
                               Color="White"
                               HorizontalOptions="Center"
                               VerticalOptions="Center" />
        </Border>
    </pullToRefresh:PullToRefreshView.RefreshView>

    
    <ScrollView>
        <VerticalStackLayout Padding="16" Spacing="12">
            <Label Text="Pull down to refresh!" FontSize="18" />
            
        </VerticalStackLayout>
    </ScrollView>

</pullToRefresh:PullToRefreshView>

3. Overlay mode

Use Type="Overlay" to display the refresh indicator floating above your content:

<pullToRefresh:PullToRefreshView IsRefreshing="{Binding IsRefreshing}"
                                 RefreshCommand="{Binding RefreshCommand}"
                                 MaxPullDistance="420"
                                 RefreshHeight="120"
                                 Type="Overlay"
                                 AnimationTransition="{x:Static Easing.CubicInOut}">

    <pullToRefresh:PullToRefreshView.RefreshView>
        <Grid HeightRequest="120" IsClippedToBounds="True">
            <Border Padding="0"
                    BackgroundColor="White"
                    HeightRequest="60"
                    HorizontalOptions="Center"
                    StrokeShape="RoundRectangle 30,30,30,30"
                    StrokeThickness="0"
                    VerticalOptions="Center"
                    WidthRequest="60">
                <ActivityIndicator IsRunning="True"
                                   Color="#6200EE"
                                   HeightRequest="40"
                                   WidthRequest="40" />
            </Border>
        </Grid>
    </pullToRefresh:PullToRefreshView.RefreshView>

    <CollectionView ItemsSource="{Binding Items}">
        
    </CollectionView>

</pullToRefresh:PullToRefreshView>

4. LoadingView — full-screen loading overlay

Use LoadingView to display a full-area view while data is being fetched. It fades in automatically when the refresh starts and fades out when IsRefreshing returns to false:

<pullToRefresh:PullToRefreshView IsRefreshing="{Binding IsRefreshing}"
                                 RefreshCommand="{Binding RefreshCommand}"
                                 MaxPullDistance="500"
                                 RefreshHeight="150"
                                 Type="Overlay">

    <pullToRefresh:PullToRefreshView.LoadingView>
        <Grid BackgroundColor="#CC000000">
            <ActivityIndicator IsRunning="True"
                               Color="White"
                               HorizontalOptions="Center"
                               VerticalOptions="Center" />
        </Grid>
    </pullToRefresh:PullToRefreshView.LoadingView>

    <pullToRefresh:PullToRefreshView.RefreshView>
        
    </pullToRefresh:PullToRefreshView.RefreshView>

    <CollectionView ItemsSource="{Binding Items}" />

</pullToRefresh:PullToRefreshView>

LoadingView works with both Normal and Overlay strategies. When set, the RefreshView hides and the LoadingView fades in simultaneously as soon as the user releases.

5. ViewModel

public class MyViewModel : INotifyPropertyChanged
{
    private bool _isRefreshing;

    public bool IsRefreshing
    {
        get => _isRefreshing;
        set { _isRefreshing = value; OnPropertyChanged(); }
    }

    public ICommand RefreshCommand { get; }

    public MyViewModel()
    {
        RefreshCommand = new Command(async () => await OnRefreshAsync());
    }

    private async Task OnRefreshAsync()
    {
        IsRefreshing = true;

        // Load your data
        await Task.Delay(2000);

        IsRefreshing = false;
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string? name = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

6. Handling pull states with the Pulling event

Subscribe to Pulling to react to each phase of the gesture — useful for driving custom animations:

<pullToRefresh:PullToRefreshView Pulling="OnPulling" ...>
private void OnPulling(object sender, PullToRefreshEventArgs e)
{
    switch (e.State)
    {
        case PullToRefreshState.Pulling:
            // User is dragging — e.Progress tracks how far (0–100+)
            AnimationView.Progress = (float)e.Progress / 100;
            break;
        case PullToRefreshState.ReleaseToRefresh:
            // Passed the threshold — user can release to trigger refresh
            break;
        case PullToRefreshState.Refreshing:
            // Refresh started — play a looping animation
            AnimationView.Play();
            break;
        case PullToRefreshState.Finished:
        case PullToRefreshState.Canceled:
            // Done or canceled — stop animation
            AnimationView.Stop();
            break;
    }
}

API Reference

Property Type Default Description
IsRefreshing bool false Controls whether the refresh is active. Set to false to complete.
RefreshCommand ICommand null Command executed when pull threshold is reached.
RefreshView View null Custom view displayed as the refresh indicator.
LoadingView View null Full-area view shown (fade-in) when refresh starts and hidden (fade-out) when it ends.
Type PullToRefreshType Normal Normal pushes content down; Overlay floats above content.
MaxPullDistance double 200 Maximum distance (in pixels) the user can pull.
RefreshHeight double 100 Height of the refresh indicator area.
AnimationTransition Easing Easing.Default Easing function for state transition animations.
State PullToRefreshState — (Read-only) Current state of the pull gesture.
Event Args Description
Pulling PullToRefreshEventArgs Fired during the pull gesture with State and Progress.

PullToRefreshState values

State Meaning
Pulling User is dragging down
ReleaseToRefresh Pulled past the threshold — releasing will trigger refresh
Released User released the gesture
Refreshing Refresh operation in progress
Canceled Pull was canceled (didn't reach threshold)
Finished Refresh completed

Platforms

Platform Minimum Version
Android 21 (Lollipop)
iOS 15.0

License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0-android36.0 is compatible.  net10.0-ios26.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 141 3/18/2026
1.0.0 129 2/15/2026
0.1.2-alpha 124 1/16/2026
0.1.1-alpha 122 1/11/2026
0.1.0-alpha 123 1/11/2026