Giter Site home page Giter Site logo

ericlewis / pagesheet Goto Github PK

View Code? Open in Web Editor NEW
55.0 2.0 7.0 56 KB

Customizable sheets using UISheetPresentationController in SwiftUI

License: MIT License

Swift 98.30% Ruby 1.70%
swiftui swift sheets presentation ios ios15 uikit modals popover bottomsheet

pagesheet's Introduction

PageSheet

Customizable sheet presentations in SwiftUI. Using UISheetPresentationController under the hood.

Features

  • Uses the default sheet API under the hood, ensuring maximum compatibility & stability.
  • Exposes the exact same API as the default SwiftUI sheet implementation.
  • No hacks, follows the best practices for creating representable views in SwiftUI.
  • Configurable using view modifiers, can configure UISheetPresentationController from any child views in the presented sheet's content view.
  • Works with the interactiveDismissDisabled(_:Bool) modifier.
  • Exposes all of the UISheetPresentationController configuration options.
  • Track the currently selected detent using an Environment value.
  • Well documented API, following a similar approach to the Developer Documentation.
  • Small footprint, ~44kB thin when installed via SwiftPM.

Table of Contents

Requirements

The codebase supports iOS and requires Xcode 12.0 or newer

Installation

Xcode

Open your project. Navigate to File > Swift Packages > Add Package Dependency. Enter the url https://github.com/ericlewis/PageSheet and tap Next. Select the PageSheet target and press Add Package.

Swift Package Manager

Add the following line to the dependencies in your Package.swift file:

.package(url: "https://github.com/ericlewis/PageSheet.git", .upToNextMajor(from: "1.0.0"))

Next, add PageSheet as a dependency for your targets:

.target(name: "AppTarget", dependencies: ["PageSheet"])

A completed example may look like this:

// swift-tools-version:5.5

import PackageDescription

let package = Package(
    name: "App",
    dependencies: [
        .package(
          url: "https://github.com/ericlewis/PageSheet.git", 
          .upToNextMajor(from: "1.0.0"))
    ],
    targets: [
        .target(
          name: "AppTarget", 
          dependencies: ["PageSheet"])
    ]
)

Examples

Example Project

If you are using Xcode 13.2.1 you can navigate to the Example folder and open the enclosed Swift App Playground to test various features (and see how they are implemented).

Presentation

PageSheet works similarly to a typical sheet view modifier.

import SwiftUI
import PageSheet

struct ContentView: View {
  @State
  private var sheetPresented = false
  
  var body: some View {
    Button("Open Sheet") {
      sheetPresented = true
    }
    .pageSheet(isPresented: $sheetPresented) {
      Text("Hello!")
    }
  }
}

PageSheet also supports presentation via conditional Identifiable objects.

import SwiftUI
import PageSheet

struct ContentView: View {
  @State
  private var string: String?
  
  var body: some View {
    Button("Open Sheet") {
      string = "Hello!"
    }
    .pageSheet(item: $string) { unwrappedString in
      Text(unwrappedString)
    }
  }
}

extension String: Identifiable {
  public var id: String { self }
}

Customization

PageSheet can also be customized using a collection of view modifiers applied to the sheet's content.

import SwiftUI
import PageSheet

struct ContentView: View {
  @State
  private var sheetPresented = false
  
  var body: some View {
    Button("Open Sheet") {
      sheetPresented = true
    }
    .pageSheet(isPresented: $sheetPresented) {
      Text("Hello!")
        .preferGrabberVisible(true)
    }
  }
}

Module Documentation

PageSheet

PageSheet is split into three different modules, with PageSheetCore handling implementation and PageSheetPlus providing a new modifier called sheetPreferences(_:). The namesake module is PageSheet, which combines PageSheetCore & PageSheetPlus into a single import.

If you want to only use PageSheet without the fancy extra modifier (and extra dependency), then use PageSheetCore.

License

PageSheet is released under the MIT license. See LICENSE for details.

pagesheet's People

Contributors

ericlewis avatar puls avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

pagesheet's Issues

Selected Detent using Binding

Hi, at first, thanks for this amazing library. It seems to be the best backward compatible SwiftUI implementation :)

I saw that your code internally uses @binding for the selected detent.
Is there a way to bind a value outside of your implementation to get informed if the user changes the selected detent by dragging.
Additionally, if I change the selected detent programmatically, it looks like the selected bottom sheet detent didn't change at all.

For that it would be amazing if you could implement a solution similar to the native apple interface where the selected detent is a Binding object.

Improve ergonomics

It's hard to remember all of the configuration methods. Sometimes they aren't so obvious in isolation (what is preferring a grabber visibility deep in this component hierarchy?). It's hard to discover the apis for quick configuration. I am leaning towards something similar to environment(_, _). Like this:

Text("hello")
  .sheet(\.prefersGrabberVisible, true)
  .sheet(\.detents, [.medium()])

The sheet method name makes sense, but other ideas should be considered as well:

  • .presentation(...)
  • .pageSheet(...)
  • .presentationPreference(...)
  • .sheetPreference(...)

There isn't really much prior art around organized interaction with Preferences aside from creating bespoke methods like environment interactions.

I will note that using preferences the KV way doesn't make it completely obvious that we are moving upwards like a typical preference setting might. Likely important to keep preference somewhere in the signature.

Another useful tool may be a property wrapper to be able to read from preferences:

@Preference(\.pref)
var pref 

This opens the potential for simplifying the entire configuration pipeline.

Food for though ๐ŸŽ

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.