{"id":13691914,"url":"https://github.com/the49ltd/The49.Maui.BottomSheet","last_synced_at":"2025-05-02T16:30:43.518Z","repository":{"id":65335805,"uuid":"588522848","full_name":"the49ltd/The49.Maui.BottomSheet","owner":"the49ltd","description":".NET MAUI library used to display pages as Bottom Sheets","archived":false,"fork":false,"pushed_at":"2024-06-17T07:27:30.000Z","size":901,"stargazers_count":325,"open_issues_count":60,"forks_count":31,"subscribers_count":11,"default_branch":"main","last_synced_at":"2024-11-12T12:54:28.755Z","etag":null,"topics":["bottomsheet","dotnet","maui"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/the49ltd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-01-13T10:24:40.000Z","updated_at":"2024-10-31T16:50:49.000Z","dependencies_parsed_at":"2023-11-28T10:28:15.202Z","dependency_job_id":"9e5934b1-c74c-49b3-b6cd-4fc55200ded4","html_url":"https://github.com/the49ltd/The49.Maui.BottomSheet","commit_stats":null,"previous_names":["the49ltd/the49.maui.bottomsheet","the49code/the49.maui.bottomsheet"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the49ltd%2FThe49.Maui.BottomSheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the49ltd%2FThe49.Maui.BottomSheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the49ltd%2FThe49.Maui.BottomSheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the49ltd%2FThe49.Maui.BottomSheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/the49ltd","download_url":"https://codeload.github.com/the49ltd/The49.Maui.BottomSheet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224319434,"owners_count":17291843,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bottomsheet","dotnet","maui"],"created_at":"2024-08-02T17:00:51.563Z","updated_at":"2024-11-12T17:32:20.004Z","avatar_url":"https://github.com/the49ltd.png","language":"C#","funding_links":[],"categories":["UI"],"sub_categories":[],"readme":"# \u003cimg src=\"./The49.Maui.BottomSheet.icon.svg?raw=true\" height=\"24\" alt=\"The49.Maui.BottomSheet icon\" /\u003e The49.Maui.BottomSheet\n\n[![NuGet Version](https://img.shields.io/nuget/v/The49.Maui.BottomSheet)](https://www.nuget.org/packages/The49.Maui.BottomSheet)\n\n\u003e **NOTE**: Coming from Gerald Versluis' video? Make sure to check the section on [what changed since the video was made](#changes-since-gerald-versluis-video)\n\n\n\n\n## What is Maui.BottomSheet?\n\nMaui.BottomSheet is a .NET MAUI library used to display pages as Bottom Sheets.\n\nAndroid        |  iOS\n:-------------------------:|:-------------------------:\n\u003cimg src=\"screenshots/android.png?raw=true\" height=\"480\" /\u003e|\u003cimg src=\"screenshots/ios.png?raw=true\" height=\"480\" /\u003e\n\n\n## Setup\n\nEnable this plugin by calling `UseBottomSheet()` in your `MauiProgram.cs`\n\n\n```cs\nusing Maui.Insets;\n\npublic static class MauiProgram\n{\n\tpublic static MauiApp CreateMauiApp()\n\t{\n\t\tvar builder = MauiApp.CreateBuilder();\n\t\t\n\t\t// Initialise the plugin\n\t\tbuilder\n                    .UseMauiApp\u003cApp\u003e()\n                    .UseBottomSheet();\n\n\t\t// the rest of your logic...\n\t}\n}\n```\n\n### XAML usage\n\nIn order to make use of the plugin within XAML you can use this namespace:\n\n```xml\nxmlns:the49=\"https://schemas.the49.com/dotnet/2023/maui\"\n```\n\n### Quick usage\n\nSimply create a `ContentView`. Replace the extended class with `BottomSheet` in code-behind and in XAML:\n\n```cs\nusing The49.Maui.BottomSheet;\n\npublic class MySheet : BottomSheet\n{\n    public MySheetPage()\n    {\n        InitializeComponent();\n    }\n}\n```\n\n\n```xml\n\u003cthe49:BottomSheet xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\n             xmlns:the49=\"https://schemas.the49.com/dotnet/2023/maui\"\n             x:Class=\"MyApp.MySheet\"\n             Title=\"MySheet\"\u003e\n            \u003c!-- ... --\u003e\n\u003c/the49:BottomSheet\u003e\n```\n\nThe sheet can be opened by calling the `ShowAsync()` method of the page. It can be closed using `DismissAsync()`:\n\n```cs\n\nconst sheet = new MySheet();\n\n// Show the sheet\nsheet.ShowAsync();\n\n// Alternatively, pass the window in which the sheet should show. Usually accessible from any other page of the app.\nsheet.ShowAsync(Window);\n\n// Call to programatically close the sheet\nsheet.DismissAsync();\n\n```\n\nAn extra parameter can be passed to both `ShowAsync` and `DismissAsync` to enable/disable the animations.\n\nOn Android, make sure your application's theme extends the Material3 theme. This mean you need a `Platforms/Android/Resources/values/styles.xml` file with the following content:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\" ?\u003e\n\u003cresources\u003e\n\t\u003cstyle name=\"Maui.MainTheme\" parent=\"Theme.Material3.DayNight\"\u003e\u003c/style\u003e\n\u003c/resources\u003e\n```\n\nIf you already have this file, just make sure the `Maui.MainTheme` style inherits the `Theme.Material3.DayNight` parent.\n\n## API\n\nThis library offers a `BottomSheet`, an extension of the `ContentView` with extra functionality\n\n### Properties\n\nThe following properties are available to use:\n\nName          |  Type | Default value | Description | Android | iOS |\n:-------------------------|:-------------------------|---|:----|---|---|\n`HasBackdrop` | `bool` | `false` | Displays the sheet as modal. This has no effect on whether or not the sheet can be dismissed using gestures. | ✅ | ✅* |\n`HasHandle` | `bool` | `false` | If `true`, display a drag handle at the top of the sheet | ✅ | ✅ |\n`HandleColor` | `Color` | `null` | Sets the color of the sheet's handle is `HasHandle` is true | ✅ | ❌** |\n`CornerRadius` | `double` | `-1` | Sets the sheet's corner radius | ✅*** | ✅ |\n`IsCancelable` | `bool` | `true` | If `false`, prevents the dismissal of the sheet with user gestures | ✅ | ✅ |\n`Detents` | `DetentsCollection` | `new DetentsCollection() { new ContentDetent() })` | A collection of detents where the sheet will snap to when dragged. (See the Detents section for more info) | ✅ | ✅ |\n`SelectedDetent` | `Detent` | `null` | A two way property defining which detent is currently selected. Changes as the user slides, and updates the sheet's position when changed | ✅ | ✅* |\n\n\\* iOS doesn't support the property `largestUndimmedDetentIdentifier` or `selectedDetentIdentifer` for custom detents as of right now. Se iOS documentation for [largestUndimmedDetentIdentifier](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller/3858107-largestundimmeddetentidentifier) and [selectedDetentIdentifer](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller/3801908-selecteddetentidentifier)\nOnly when the `FullscreenDetent` and/or `MediumDetent` are used those properties will work.\n\n\\*\\* iOS doesn't give any access to the grabber view\n\n\\*\\*\\* On Android, setting a custom corner radius will prevent the radius animation when the sheet hits the top of the screen\n\n### Detents:\n\nDetents are snap point at which the sheet will stop when a drag gesture is released [See iOS definition](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller/detent).\n\nOn Android only 3 detents are supported (See implemenation section for more info).\n\nOn iOS, detents are only fully supported for iOS 16 and up. On iOS 15, medium and large detents are used instead [See iOS documentation](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller/detent).\n\n### Available detents\n\nName          |  Parameter | Description |\n:-------------------------|:-------------------------|:----|\n`FullscreenDetent` |  | Full height of the screen |\n`ContentDetent` |  | Calculates the height of the page's content |\n`AnchorDetent` | `Anchor` | `Anchor` expects a `View` and will set its height to the Y position of that view. This is used to peek some content, then reveal more when the sheet is dragged up |\n`HeightDetent` | `Height` | Use a dp value to specify the detent height |\n`RatioDetent` | `Ratio` | Use a ratio of the full screen height |\n`MediumDetent` |  | A detent at the halfway point of the screen |\n\nExample:\n\n```xml\n\u003cthe49:BottomSheet xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\n             xmlns:the49=\"https://schemas.the49.com/dotnet/2023/maui\"\n             x:Class=\"MyApp.SheetPage\"\n             Title=\"SheetPage\"\u003e\n    \u003cthe49:BottomSheet.Detents\u003e\n        \u003c!-- Stop at the height of the screen --\u003e\n        \u003cthe49:FullscreenDetent /\u003e\n        \u003c!-- Stop at the height of the page content --\u003e\n        \u003cthe49:ContentDetent /\u003e\n        \u003c!-- Stop at 120dp --\u003e\n        \u003cthe49:HeightDetent Height=\"120\" /\u003e\n        \u003c!-- Stop at 45% of the screen height --\u003e\n        \u003cthe49:RatioDetent Ratio=\"0.45\" /\u003e\n        \u003c!-- Stop at the height of the divider view --\u003e\n        \u003cthe49:AnchorDetent Anchor=\"{x:Reference divider}\" /\u003e\n    \u003c/the49:BottomSheet.Detents\u003e\n    \u003cVerticalStackLayout Spacing=\"16\"\u003e\n        \u003cVerticalStackLayout\u003e\n            \u003c!-- some content --\u003e\n        \u003c/VerticalStackLayout\u003e\n        \u003cBoxView x:Name=\"divider\" /\u003e\n        \u003cVerticalStackLayout\u003e\n            \u003c!-- more content --\u003e\n        \u003c/VerticalStackLayout\u003e\n    \u003c/VerticalStackLayout\u003e\n\u003c/the49:BottomSheetPage\u003e\n```\n\n### Custom detent\n\nYou can create a custom detent by extending the default `Detent` class and implementing its `GetHeight` abstract method\n\n### Events\n\nThe following events are available to use:\n\nName          |  EventArg | Description | Android | iOS |\n:-------------------------|:-------------------------|:----|---|---|\n`Dismissed` | `DismissOrigin` | Invoked when the sheet is dismissed. The EventArgs will either be `DismissOrigin.Gesture` when the user dragged it down or `DismissOrigin.Programmatic` when `Dismiss` is called. | ✅ | ✅ |\n`Showing` | `EventArg.Emtpy` | Called when the sheet is about to animate in. This is the best time to configure the behavior of the sheet for specific platforms (See [Platform specifics](#platform-specifics)) | ✅ | ✅ |\n`Shown` | `EventArg.Emtpy` | Called when the sheet finished animating in. | ✅ | ✅ |\n\n\n## Platform specifics\n\nOn Android, the `Google.Android.Material.BottomSheet.BottomSheetBehavior` is made available under `sheet.Controller.Behavior`, to ensure the property is set, access it when the `Showing` event is fired. Learn more about it here: [BottomSheetBehavior  |  Android Developers](https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior)\n\nOn iOS, the `UIKit.UISheetPresentationController` is made available under `sheet.Controller.SheetPresentationController`, to ensure the property is set, access it when the `Showing` event is fired. Learn more about it here: [UISheetPresentationController | Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller)\n\n## Common questions\n\n### How can I remove the backdrop on iOS\n\nA sheet without backdrop works on iOS only if using `MediumDetent` and `FullscreenDetent`. Using the `OnPlatform` tool replace the detent on iOS to only use those and it will work.\n\n\u003e Note: In the future, iOS might allow custom detents to support the largestUndimmableDetentIdentifier. If that happens, this plugin will be updated to support it\n\nHere is how you can use the detents you need on Android, and use the detents compatible with `HasBackdrop` and `SelectedDetent`:\n\nA `IsDefault` property can be used to select the detent that will be shown when calling `ShowAsync`. Otherwise the smallest detent is used.\n\n```xml\n\u003cthe49:BottomSheet xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\n             xmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\n             xmlns:the49=\"https://schemas.the49.com/dotnet/2023/maui\"\n             x:Class=\"MyApp.SheetPage\"\n             Title=\"SheetPage\"\u003e\n    \u003cthe49:BottomSheet.Detents\u003e\n        \u003cOnPlatform\u003e\n            \u003cOn Platform=\"Android\"\u003e\n                \u003cthe49:FullscreenDetent /\u003e\n                \u003cthe49:ContentDetent /\u003e\n                \u003cthe49:AnchorDetent Anchor=\"{x:Reference divider}\" /\u003e\n            \u003c/On\u003e\n            \u003cOn Platform=\"iOS\"\u003e\n                \u003cthe49:FullscreenDetent /\u003e\n                \u003cthe49:MediumDetent /\u003e\n            \u003c/On\u003e\n        \u003c/OnPlatform\u003e\n    \u003c/the49:BottomSheet.Detents\u003e\n    \u003cVerticalStackLayout Spacing=\"16\"\u003e\n        \u003cVerticalStackLayout\u003e\n            \u003c!-- some content --\u003e\n        \u003c/VerticalStackLayout\u003e\n        \u003cBoxView x:Name=\"divider\" /\u003e\n        \u003cVerticalStackLayout\u003e\n            \u003c!-- more content --\u003e\n        \u003c/VerticalStackLayout\u003e\n    \u003c/VerticalStackLayout\u003e\n\u003c/the49:BottomSheetPage\u003e\n```\n\n### How do I prevent the rounded corner to animate on Android?\n\n```cs\nvar sheet = new MySheet();\nsheet.Showing += (s, e) =\u003e\n{\n    page.Controller.Behavior.DisableShapeAnimations();\n};\nsheet.ShowAsync(Window);\n```\n### How can I change the detent used when showing the sheet\n\nYou can either add `IsDefault=\"True\"` to the detent or set `SelectedDetent` to one of your detents before calling `ShowAsync`.\n\n### How do I change the corner radius?\n\nUse the `CornerRadius` property.\n\n## Implementation details\n\n### iOS\n\nThe bottom sheet on iOS is presented using the `UIViewController`'s `PresentViewController` and configuring the sheet with [UISheetPresentationController](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller/detent).\n\nDetents are created using the [custom](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller/detent/3976719-custom) method\n\n\n### Android\n\nThe Material library's bottom sheet is used.\n\nA xml layout contains a Frame, CoordinatorLayout and another Frame with the `com.google.android.material.bottomsheet.BottomSheetBehavior` behavior. The layout is inflated and added to the `DrawerLayout` is using `AppShell` or `CoordinatorLayout` is using `NavigationPage`\n\nA backdrop is added and animated when requested\n\nDetents are created using a combination of [expandedOffset](https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior#setExpandedOffset(int)), [halfExpandedRatio](https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior#setHalfExpandedRatio(float)) and [peekHeight](https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior#setPeekHeight(int,%20boolean)). These are the only configurable stop points for the bottom sheets, and that is why this library only supports up to 3 detents on Android.\n\n\n## Changes since Gerald Versluis' video\n\nIf you're coming from [Gerald Versluis' video](https://www.youtube.com/watch?v=JJUm58avADo), a few things have changed. Here is what you need to know:\n\n - Property names have been updated to be more consistent, discoverable and aligned with standard MAUI properties:\n   - `ShowHandle` is now `HasHandle`\n   - `Cancelable` is now `IsCancelable`\n   - `IsModal` is now `HasBackdrop`\n\n - 2 new properties have been added:\n   - `HandleColor`\n   - `SelectedDetent`\n - Methods have been renamed\n   - `Show` is now `ShowAsync` and completes when the animation of the sheet finishes. It also accepts a boolean to turn off animations\n   - `Dismiss` is now `DismissAsync` and completes when the animation of the sheet finishes. It also accepts a boolean to turn off animations\n\n\n---\n\n\n\u003cimg src=\"https://the49.com/logo.svg\" height=\"64\" /\u003e\n\nMade within The49\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthe49ltd%2FThe49.Maui.BottomSheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthe49ltd%2FThe49.Maui.BottomSheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthe49ltd%2FThe49.Maui.BottomSheet/lists"}