Skip to content

#20880 - added swipe gesture support for SplitView and enabled it by …#20881

Draft
gentledepp wants to merge 1 commit intoAvaloniaUI:masterfrom
gentledepp:feature/20880_splitviewswipegesture
Draft

#20880 - added swipe gesture support for SplitView and enabled it by …#20881
gentledepp wants to merge 1 commit intoAvaloniaUI:masterfrom
gentledepp:feature/20880_splitviewswipegesture

Conversation

@gentledepp
Copy link
Contributor

…default on mobile platforms

What does the pull request do?

Add built-in swipe gesture support to Avalonia's SplitView control, allowing users to open and close the pane by dragging from the pane edge. This is a common UX pattern on Android, iOS, and Windows for navigation drawers and side panels.

What is the current behavior?

Users have to click a button to open/close the splitview pane

What is the updated/expected behavior with this PR?

Now you can use a swipe gesture

How was the solution implemented (if it's not obvious)?

New properties on SplitView

  • IsSwipeToOpenEnabled (bool, default: false) — Opt-in property to enable swipe gesture handling. Consumers must explicitly set this to true.
  • IsSwipeGestureActive (bool, read-only) — Indicates whether a swipe gesture is currently in progress (dragging or snap-animating). External code (e.g. PaneClosing event handlers) can check this to avoid interfering with the gesture.

Swipe gesture behavior

Supports all four pane placements: Left, Right, Top, Bottom — including RTL layouts.

Placement Drag axis Open direction Edge zone
Left (LTR) Horizontal Rightward Left 1/3
Left (RTL) Horizontal Leftward Right 1/3
Right (LTR) Horizontal Leftward Right 1/3
Right (RTL) Horizontal Rightward Left 1/3
Top Vertical Downward Top 1/3
Bottom Vertical Upward Bottom 1/3

Swipe-to-open (pane closed):

  1. Touch/mouse press in edge zone (1/3 of the control along the pane axis)
  2. After 10px movement, direction is locked — must be more along primary axis than secondary, and moving toward open direction
  3. Pane panel's Width (or Height) is set directly as a local value, tracking the finger/pointer position
  4. On release: velocity-based snap — fast flick (>800px/s) opens immediately; otherwise opens if past 40% of target width

Swipe-to-close (pane open):

  1. Touch/mouse press anywhere on the control
  2. Direction lock: must be horizontal/vertical and moving toward close direction
  3. Pane tracks finger in reverse (shrinks as user drags toward closed)
  4. On release: closes if fast leftward flick or remaining width < 60% of target

Snap animation: 200ms with cubic ease-out easing.

Technical approach

  • Direct Width/Height manipulation: During drag, the pane panel (PART_PaneRoot) has its Width or Height set as a local value, which overrides the style-set value (local priority > style priority in Avalonia).
  • Programmatic transition suppression: Theme-defined DoubleTransition on Width/Height would fight the drag. On direction lock, an empty Transitions collection is set as a local value on the pane, suppressing animations. On finalize, this local value is cleared so the theme transitions resume.
  • Late pointer capture: Pointer is only captured when direction is locked (not on press), so regular button clicks and other interactions pass through normally.
  • Light-dismiss guard: The existing PointerReleasedOutside handler (which closes the pane when clicking outside in overlay mode) checks IsSwipeGestureActive and skips during gesture to prevent the pane from closing mid-swipe.
  • State commit: On snap completion, IsPaneOpen is set via SetCurrentValue so normal coercion, PaneClosing/PaneOpened events, and pseudo-class updates all fire as expected. The local Width/Height override is then cleared, handing control back to the style system.
  • No theme changes required: All transition suppression is done programmatically. No modifications to Fluent or Simple theme XAML files.

Compatibility

  • Targets all three TFMs: netstandard2.0, net6.0, net8.0
  • Avoids C# features not available in netstandard2.0 (no [^1] index, no TimeSpan / TimeSpan)
  • Accepts both PointerType.Touch and PointerType.Mouse input

Checklist

Breaking changes

Obsoletions / Deprecations

Fixed issues

Fixes #20880

@emmauss emmauss added enhancement needs-api-review The PR adds new public APIs that should be reviewed. labels Mar 12, 2026
@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0063317-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@cla-avalonia
Copy link
Collaborator

cla-avalonia commented Mar 12, 2026

@alexander.marek,

Please read the following Contributor License Agreement (CLA). If you agree with the CLA, please reply with the following:

@cla-avalonia agree
Contributor License Agreement

Contribution License Agreement

This Contribution License Agreement ( “Agreement” ) is agreed to by the party signing below ( “You” ),
and conveys certain license rights to the AvaloniaUI OÜ ( “AvaloniaUI OÜ” ) for Your contributions to
AvaloniaUI OÜ open source projects. This Agreement is effective as of the latest signature date below.

1. Definitions.

“Code” means the computer software code, whether in human-readable or machine-executable form,
that is delivered by You to AvaloniaUI OÜ under this Agreement.

“Project” means any of the projects owned or managed by AvaloniaUI OÜ and offered under a license
approved by the Open Source Initiative (www.opensource.org).

“Submit” is the act of uploading, submitting, transmitting, or distributing code or other content to any
Project, including but not limited to communication on electronic mailing lists, source code control
systems, and issue tracking systems that are managed by, or on behalf of, the Project for the purpose of
discussing and improving that Project, but excluding communication that is conspicuously marked or
otherwise designated in writing by You as “Not a Submission.”

“Submission” means the Code and any other copyrightable material Submitted by You, including any
associated comments and documentation.

2. Your Submission. You must agree to the terms of this Agreement before making a Submission to any
Project. This Agreement covers any and all Submissions that You, now or in the future (except as
described in Section 4 below), Submit to any Project.

3. Originality of Work. You represent that each of Your Submissions is entirely Your
original work. Should You wish to Submit materials that are not Your original work,
You may Submit them separately to the Project if You (a) retain all copyright and
license information that was in the materials as you received them, (b) in the
description accompanying your Submission, include the phrase "Submission
containing materials of a third party:" followed by the names of the third party and any
licenses or other restrictions of which You are aware, and (c) follow any other
instructions in the Project's written guidelines concerning Submissions.

4. Your Employer. References to “employer” in this Agreement include Your employer or anyone else
for whom You are acting in making Your Submission, e.g. as a contractor, vendor, or agent. If Your
Submission is made in the course of Your work for an employer or Your employer has intellectual
property rights in Your Submission by contract or applicable law, You must secure permission from Your
employer to make the Submission before signing this Agreement. In that case, the term “You” in this
Agreement will refer to You and the employer collectively. If You change employers in the future and
desire to Submit additional Submissions for the new employer, then You agree to sign a new Agreement
and secure permission from the new employer before Submitting those Submissions.

5. Licenses.

a. Copyright License. You grant AvaloniaUI OÜ, and those who receive the Submission directly
or indirectly from AvaloniaUI OÜ, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable
license in the Submission to reproduce, prepare derivative works of, publicly display, publicly perform,
and distribute the Submission and such derivative works, and to sublicense any or all of the foregoing
rights to third parties.

b. Patent License. You grant AvaloniaUI OÜ, and those who receive the Submission directly or
indirectly from AvaloniaUI OÜ, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license
under Your patent claims that are necessarily infringed by the Submission or the combination of the
Submission with the Project to which it was Submitted to make, have made, use, offer to sell, sell and
import or otherwise dispose of the Submission alone or with the Project.

c. Other Rights Reserved. Each party reserves all rights not expressly granted in this Agreement.
No additional licenses or rights whatsoever (including, without limitation, any implied licenses) are
granted by implication, exhaustion, estoppel or otherwise.

6. Representations and Warranties. You represent that You are legally entitled to grant the above
licenses. You represent that each of Your Submissions is entirely Your original work (except as You may
have disclosed under Section 3 ). You represent that You have secured permission from Your employer to
make the Submission in cases where Your Submission is made in the course of Your work for Your
employer or Your employer has intellectual property rights in Your Submission by contract or applicable
law. If You are signing this Agreement on behalf of Your employer, You represent and warrant that You
have the necessary authority to bind the listed employer to the obligations contained in this Agreement.
You are not expected to provide support for Your Submission, unless You choose to do so. UNLESS
REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, AND EXCEPT FOR THE WARRANTIES
EXPRESSLY STATED IN SECTIONS 3, 4, AND 6 , THE SUBMISSION PROVIDED UNDER THIS AGREEMENT IS
PROVIDED WITHOUT WARRANTY OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY OF
NONINFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.

7. Notice to AvaloniaUI OÜ. You agree to notify AvaloniaUI OÜ in writing of any facts or
circumstances of which You later become aware that would make Your representations in this
Agreement inaccurate in any respect.

8. Information about Submissions. You agree that contributions to Projects and information about
contributions may be maintained indefinitely and disclosed publicly, including Your name and other
information that You submit with Your Submission.

9. Governing Law/Jurisdiction. This Agreement is governed by the laws of the Republic of Estonia, and
the parties consent to exclusive jurisdiction and venue in the courts sitting in Talinn,
Estonia. The parties waive all defenses of lack of personal jurisdiction and forum non-conveniens.

10. Entire Agreement/Assignment. This Agreement is the entire agreement between the parties, and
supersedes any and all prior agreements, understandings or communications, written or oral, between
the parties relating to the subject matter hereof. This Agreement may be assigned by AvaloniaUI OÜ.

AvaloniaUI OÜ dedicates this Contribution License Agreement to the public domain according to the Creative Commons CC0 1.

alexander.marek doesn't seem to be a GitHub user.
Please add the emails used in your commits to your Github account accordingly.

@gentledepp
Copy link
Contributor Author

@cla-avalonia agree

@robloo
Copy link
Contributor

robloo commented Mar 12, 2026

This is a complete re-implementation of the "swipe" detection algorithm and a lot of special handling code. Instead, it should be using the existing swipe gesture which should simplify a lot and significantly improve maintainability. I suspect we can get the same functionality with just a few lines of code.

The idea is pretty good though. This is good functionality to have in the SplitView.

@gentledepp
Copy link
Contributor Author

gentledepp commented Mar 12, 2026

that would be awesome! Can you point me to the right direction?
The only documented one is here: https://docs.avaloniaui.net/docs/concepts/input/gestures

I was not aware that a swipe gesture already exists.
This PR is a work-in-progres and not functional atm.

@robloo
Copy link
Contributor

robloo commented Mar 12, 2026

Yea, the documents don't list all of them and several are brand-new including swipe:

https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Base/Input/GestureRecognizers/SwipeGestureRecognizer.cs

You should be able to search the code base for examples in the ControlCatalog for how its used as well.

@gentledepp
Copy link
Contributor Author

gentledepp commented Mar 17, 2026

No, this recognizer doesn't cover what I need. It's a one-shot swipe detector — it fires a single event once the threshold is crossed, then stops tracking.
What it does give me:

Edge-zone filtering (only start from the screen edge)
RTL awareness
Initial direction detection

What's missing for my use case:

No continuous drag updates. Once the threshold is met, it raises one SwipeGestureEvent and sets _tracking = null. I never get intermediate position deltas to translate my menu panel in real time. I need something like a GestureDelta / GestureUpdated event firing on every PointerMoved after recognition.
No gesture-end event. There's no event on PointerReleased that tells me "the user lifted their finger at this position with this velocity." Without that, I can't decide whether to snap open or snap closed.
No velocity / inertia tracking. There's zero timestamp or position history being kept, so I can't compute swipe speed. My "fast enough flick" requirement has nothing to work with.
No cross-axis cancellation during drag. The CrossAxisCancelThreshold property is declared but never actually checked in PointerMoved — it's dead code right now.

In essence I need a recognizer that transitions through phases — idle → detecting → dragging → ended — and raises three event types: something like SwipeDragStarted, SwipeDragDelta (on every move), and SwipeDragCompleted (on release, including velocity). Think of it as the horizontal equivalent of Avalonia's built-in PullGestureRecognizer / ScrollGestureRecognizer which already do exactly this pattern for scrolling.

Here's what I need my side menu gesture recognizer to do:

Drag the menu with my finger. As I swipe from the edge, the side menu should follow my finger in real time — not just detect a swipe and jump open. I need continuous position updates throughout the entire drag.
Snap open on sufficient distance. If I drag the menu far enough (say 80% of its width or fully open), it should animate to the fully open position when I release.
Snap open on fast flick (inertia). Even if I haven't dragged very far, a quick flick gesture should be enough to fling the menu open. So I need velocity tracking to detect that.
Animate to close if neither condition is met. If I release the menu without having dragged far enough and without enough speed, it should smoothly animate back to the closed position.
Edge-zone start only. The gesture should only begin when I touch near the screen edge, so it doesn't interfere with normal content interaction.
Cross-axis cancellation. If my finger drifts too far vertically (e.g. I'm actually trying to scroll), the gesture should cancel and let the scroll take over.

In short: touch near the edge → drag the menu with me → on release, decide based on distance or velocity whether to animate open or animate closed.

@MrJul
Copy link
Member

MrJul commented Mar 17, 2026

Note: the swipe detection will be improved with #20659, soon to be merged. It provides velocity tracking and a "swipe ended" gesture.

@zxbmmmmmmmmm
Copy link
Contributor

Compared to using the existing GestureRecognizer, I think implementing something like InteractionTracker in UWP/WinUI can create better manipulation experiences.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement needs-api-review The PR adds new public APIs that should be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SplitView - should allow "swipe gesture" to open and close the pane on mobile platforms

7 participants