{"id":24177695,"url":"https://github.com/emrearmagan/modalkit","last_synced_at":"2025-10-13T11:16:45.956Z","repository":{"id":270667758,"uuid":"909885848","full_name":"emrearmagan/ModalKit","owner":"emrearmagan","description":"ModalKit is a simple and flexible framework for managing modal view presentations in iOS.","archived":false,"fork":false,"pushed_at":"2025-05-01T19:40:33.000Z","size":35072,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-13T11:16:44.130Z","etag":null,"topics":["animator","ios","modal","overlay","presentation","scrollview","sheet","swift","transition","uikit","viewcontroller"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/emrearmagan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-12-30T01:24:50.000Z","updated_at":"2025-05-01T19:40:38.000Z","dependencies_parsed_at":"2025-05-01T20:37:28.025Z","dependency_job_id":null,"html_url":"https://github.com/emrearmagan/ModalKit","commit_stats":null,"previous_names":["emrearmagan/modalkit"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/emrearmagan/ModalKit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emrearmagan%2FModalKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emrearmagan%2FModalKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emrearmagan%2FModalKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emrearmagan%2FModalKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emrearmagan","download_url":"https://codeload.github.com/emrearmagan/ModalKit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emrearmagan%2FModalKit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279014761,"owners_count":26085593,"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","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["animator","ios","modal","overlay","presentation","scrollview","sheet","swift","transition","uikit","viewcontroller"],"created_at":"2025-01-13T04:15:39.078Z","updated_at":"2025-10-13T11:16:45.942Z","avatar_url":"https://github.com/emrearmagan.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ModalKit\n\n![Platform](https://img.shields.io/badge/platform-ios-lightgray.svg)\n![Swift 5.0](https://img.shields.io/badge/Swift-5.0-orange.svg)\n![iOS 13.0+](https://img.shields.io/badge/iOS-13.0%2B-blue.svg)\n[![SwiftPM](https://img.shields.io/badge/SPM-supported-DE5C43.svg?style=flat)](https://swift.org/package-manager/)\n![MIT](https://img.shields.io/github/license/mashape/apistatus.svg)\n\n**ModalKit** is a simple and flexible framework for managing modal view presentations in iOS. With support for custom animations, configurable presentation sizes, and interactive gestures. ModalKit simplifies the process of creating dynamic and user-friendly modal interfaces.\n\n[📖 Documentation](https://emrearmagan.github.io/ModalKit/)\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"./Example/Supporting Files/Preview/TableView.gif\" width=\"24%\"\u003e\n  \u003cimg src=\"./Example/Supporting Files/Preview/Default.gif\" width=\"24%\"\u003e\n  \u003cimg src=\"./Example/Supporting Files/Preview/Textfield.gif\" width=\"24%\"\u003e\n  \u003cimg src=\"./Example/Supporting Files/Preview/TabBar.gif\" width=\"24%\"\u003e\n\u003c/div\u003e\n\n\u003e **⚠️ Important**  \n\u003e The current version is still in development. There can and will be breaking changes in version updates until version 1.0.\n\n## Features\n- `Multiple Sticky Points`: Transition between predefined modal heights, such as small, medium, and large.\n- `Scroll View Integration`: Seamlessly handle scroll views, enabling smooth transitions between scrolling and dragging.\n- `Dynamic Resizing`: Adapt the modal's size programmatically or based on content changes.\n\n## Usage\n\n#### Basic Usage\nTo present a view controller with ModalKit:\n\n##### Using the `presentModal` Extension\n```swift\nimport ModalKit\n\nlet viewControllerToPresent = MyViewController()\npresentModal(viewControllerToPresent)\n```\n\n##### Directly Setting Up ModalKit\n```swift\nimport ModalKit\n\nlet viewControllerToPresent = MyViewController()\nviewControllerToPresent.modalPresentationStyle = .custom\nviewControllerToPresent.transitioningDelegate = MKPresentationManager()\npresent(viewControllerToPresent, animated: true)\n```\n\n##### Dismissing the Modal\nTo dismiss the modal programmatically:\n```swift\nself.dismiss(animated: true, completion: nil)\n```\n\n## Presentation Sizes\nModalKit supports a variety of presentation sizes, which can be defined using the `MKPresentationSize` enum:\n\n- `.large`: Full-screen presentation.\n- `.medium`: Half-screen presentation.\n- `.small`: Quarter-screen presentation.\n- `.contentHeight(CGFloat)`: Fixed height.\n- `.intrinsicHeight`: Automatically adjusts based on content size.\n- `.additionalHeight(MKPresentationSize, CGFloat)`: Allows specifying an additional offset height relative to another presentation size.\n\nYou can provide multiple options in preferredPresentationSize. The modal can snap to whichever is appropriate.\n\nExample:\n```swift\nclass MyViewController: MKPresentable {\n    var preferredPresentationSize: [MKPresentationSize] {\n        return [.small, .intrinsicHeight, .large]\n}\n```\n\n\u003cimg src=\"./Example/Supporting Files/Preview/Sizes.gif\" width=\"30%\"\u003e\n\n#### Transition to a New Presentation Size\nYou also can programmatically transition the modal to a different size:\n```swift\nself.transition(to: .medium)\n```\nThis method animates the modal to the new size while respecting the constraints defined by `MKPresentationSize`. This is particularly useful for modals that need to adapt dynamically to user interactions or content changes.\n\n## MKPresentable\nView controllers can conform to the MKPresentable protocol to customize how they are presented. This protocol gives you fine-grained control over:\n- Preferred Presentation Sizes\n- Scroll View Integration\n- Gesture \u0026 Transition Control\n- Configuration Settings\n\nBelow is an example of a **basic conformance** that also demonstrates optional methods you can override to fully control the modal’s behavior, including transitions and scrolling behavior:\n\n```swift\nextension MyViewController: MKPresentable {\n\n    // Defines the possible sizes for the presented view controller (e.g., medium \u0026 large).\n    var preferredPresentationSize: [MKPresentationSize] {\n        return [.medium, .large]\n    }\n\n    // If your view contains a scroll view (like a UITableView), provide it here.\n    // ModalKit will observe its offset to seamlessly hand off between scrolling and dragging the modal.\n    var scrollView: UIScrollView? {\n        return myTableView\n    }\n\n    // Called once before the modal is presented. Use this to configure drag indicators,\n    // corner radius, and other presentation options.\n    func configure(_ configuration: inout MKPresentableConfiguration) {\n        configuration.showDragIndicator = true\n        configuration.hasRoundedCorners = true\n    }\n\n    // Called when the dimming view is tapped.\n    // By default, this dismisses the modal. Override for custom behavior.\n    func onDimmingViewTap() {\n        dismiss(animated: true)\n    }\n    \n    // Return false if you want to disallow certain drag gestures (e.g., under some conditions).\n    // By default, this returns true, letting the modal's pan gesture proceed.\n    func shouldContinue(with gestureRecognizer: UIPanGestureRecognizer) -\u003e Bool {\n        return true\n    }\n\n    // Called right before the modal tries to switch to a new size (e.g., from .small to .medium).\n    // Return false to block that transition. By default, this returns true.\n    func shouldTransition(to size: MKPresentationSize) -\u003e Bool {\n        return true\n    }\n\n    // Called immediately before the modal begins resizing to the new size.\n    // Use this to update your UI (e.g., hiding certain subviews).\n    func willTransition(to size: MKPresentationSize) {\n        // e.g., hide a toolbar\n    }\n\n    // Called after the modal has finished transitioning to the new size.\n    // Use this to finalize any layout changes or re-display elements.\n    func didTransition(to size: MKPresentationSize) {\n        // e.g., show the toolbar again\n    }\n}\n```\n\n## Dynamic Layout Updates\nModalKit provides methods to handle layout changes during runtime, ensuring modals adjust properly when their content or constraints change.\nThis is especially useful for dynamic content, such as updated text, added views, or changes in size requirements.\n\n### Force Layout Updates\nIf the layout of the modal is affected by content changes or external updates, you can manually trigger a recalculation to ensure the modal adjusts to its new size. By calling the `presentationLayoutIfNeeded()` method, the modal updates its layout and animates to the correct position based on the `preferredPresentationSize` or other defined size configurations:\n\n```swift\nself.updateUI()\nself.presentationLayoutIfNeeded()\n```\n\u003cdiv align=\"center\"\u003e\n    \u003cimg src=\"./Example/Supporting Files/Preview/Layout1.gif\" width=\"35%\"\u003e\n    \u003cimg src=\"./Example/Supporting Files/Preview/Layout2.gif\" width=\"35%\"\u003e\n\u003c/div\u003e\n\n\n## MKPresentableConfiguration\nThe MKPresentableConfiguration provides a variety of options:\n\n| Option                   | Description                                                                                              |\n|--------------------------|----------------------------------------------------------------------------------------------------------|\n| `showDragIndicator`      | Indicates whether a drag indicator should be displayed at the top of the modal. Default: `false`.         |\n| `dragIndicatorColor`     | The color of the drag indicator, if enabled. Default: `.label`.                                           |\n| `dragIndicatorSize`      | The size of the drag indicator, if shown. Default: `CGSize(width: 40, height: 5)`.                        |\n| `dismissibleScale`       | Scale at which the vc will be automatically dismissed. Default: `0.6`.                                    |\n| `isDismissable`          | Determines whether the modal can be dismissed by dragging. Default: `true`.                              |\n| `dragResistance`         | Specifies how resistant the modal is to drag gestures, ranging from `0.0` (no resistance) to `1.0` (full resistance). Default: `0`. |\n| `hasRoundedCorners`      | Indicates whether the modal should have rounded corners. Default: `false`.                               |\n\n## Scroll View Integration\nModalKit provides built-in support for `UIScrollView` and its subclasses, such as `UITableView` and `UICollectionView`, allowing seamless interaction between scrolling and modal gestures. `ModalKit` ensures smooth transitions when scrolling content overlaps with dragging gestures to resize or dismiss the modal.\n\n### Example\nTo enable scroll view integration, implement the `MKPresentable` protocol and return your scroll view in the `scrollView` property:\n```swift\nclass MyViewController: MKPresentable {\n    var scrollView: UIScrollView? {\n        return myTableView\n    }\n}\n```\n\u003cimg src=\"./Example/Supporting Files/Preview/ScrollViewExample.gif\" width=\"30%\"\u003e\n\nHandoff Between Scroll and Drag: When the scroll view is at the top or bottom of its content, dragging gestures transition seamlessly to resizing or dismissing the modal.\nModalKit observes the scroll view's content offset to determine when to allow dragging or maintain scrolling behavior.\n\nIf you need to customize the interaction between the scroll view and the modal, you can override the shouldContinue(with:) method in the MKPresentable protocol:\n```swift\nclass MyViewController: MKPresentable {\n    var scrollView: UIScrollView? {\n        return myTableView\n    }\n\n    func shouldContinue(with gestureRecognizer: UIPanGestureRecognizer) -\u003e Bool {\n        // Custom logic to determine if dragging should continue\n        return true\n    }\n}\n```\n\n## TabBar Integration\n`ModalKit works also great with `UITabBarController`, ensuring that modals are presented above the tab bar without interfering with its functionality. `ModalKit` automatically handles the safe area insets and adjusts the modal's layout to avoid overlapping with the tab bar.\n\n### Example\n```swift\nclass MyTabBarViewController: UITabBarController, MKPresentable {\n    /// The preferred presentation size for the currently selected view controller.\n    var preferredPresentationSize: [MKPresentationSize] {\n        if let vc = selectedViewController as? MKPresentable {\n            return vc.preferredPresentationSize\n        }\n        return [.large]\n    }\n}\n```\n\u003cimg src=\"./Example/Supporting Files/Preview/TabBarExample.gif\" width=\"30%\"\u003e\n\n## Navigation Controller Integration\n`ModalKit` is fully compatible with UINavigationController, allowing modals to be presented within navigation stacks. It also supports smooth transitions between pushed view controllers and modally presented views.\n\n### Example\n\n```swift\nclass MyNavigationViewController: UINavigationController, UINavigationControllerDelegate, MKPresentable {\n    /// Returns the preferred presentation size of the top view controller if it conforms to `MKPresentable`,\n    /// otherwise defaults to `.large`.\n    var preferredPresentationSize: [MKPresentationSize] {\n        if let vc = topViewController as? MKPresentable {\n            return vc.preferredPresentationSize\n        }\n        return [.large]\n    }\n\n    override var preferredStatusBarStyle: UIStatusBarStyle { .lightContent }\n\n    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {\n        guard !navigationController.isBeingPresented else { return }\n        /// Ensures the presentation layout is updated when transitioning between view controllers.\n        presentationLayoutIfNeeded()\n    }\n}\n```\n\u003cimg src=\"./Example/Supporting Files/Preview/NavigationExample.gif\" width=\"30%\"\u003e\n\n## Examples\nThe `ModalKitExample` project provides a variety of usage examples. These examples showcase how to implement and customize ModalKit for different use cases. Explore the `ModalKitExample` project for more details.\n\n## Requirements\n- iOS 13.0+\n- Xcode 12+\n- Swift 5.0+\n\n## Installation\n\n### Swift Package Manager\nTo integrate `ModalKit` into your project using Swift Package Manager, add the following to your `Package.swift` file:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/emrearmagan/ModalKit.git\")\n]\n```\n\n### Manual Installation\n1. Download ModalKit.zip from the latest release and extract its content in your project's folder.\n2. From the Xcode project, choose **Add Files to ...** from the File menu and add the extracted files.\n\n## Contributing\nContributions are welcome! If you’d like to contribute, please open a pull request or issue on GitHub.\n\n## License\n`ModalKit` is available under the MIT license. See the LICENSE file for more information.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femrearmagan%2Fmodalkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femrearmagan%2Fmodalkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femrearmagan%2Fmodalkit/lists"}