A sliding Sheet from the bottom of the Screen with 3 States build with SwiftUI.

Overview

BottomSheet

SwiftPM compatible GitHub version CocoaPods compatible CocoaPods version License Issues

A sliding Sheet from the bottom of the Screen with 3 States build with SwiftUI.

Why

There have been many different attempts to recreate the BottomSheet from Apple Maps, Shortcuts and Apple Music, because Apple unfortunately does not provide it in their SDK.

However, all previous attempts share a common problem: The height does not change in the different states. Thus, the BottomSheet is always the same size (e.g. 800px) and thus remains 800px, even if you only see e.g. 400px - the rest is inaccessible unless you pull the BottomSheet up to the very top.

There are also many implementations out there that only have 2 states - not 3 like e.g. Apple Maps.

Features

  • Dynamic height (works with ScrollView and every other view)
  • Fully customizable States (any number of states at any height)
  • Many options for customization (backgroundBlur, tapToDismiss, swipeToDismiss, etc.)
  • Very easy to use
  • Support for SearchBar in the header
  • Flick through feature
  • Same behavior as Apple for the .bottom position
  • Beatuiful customizable animations

Requirements

  • iOS 13
  • Swift 5.3
  • Xcode 12

Installation

Swift Package Manager

The preferred way of installing BottomSheet is via the Swift Package Manager.

Xcode 11 integrates with libSwiftPM to provide support for iOS, watchOS, and tvOS platforms.

  1. In Xcode, open your project and navigate to FileSwift PackagesAdd Package Dependency...
  2. Paste the repository URL (https://github.com/LucasMucGH/BottomSheet) and click Next.
  3. For Rules, select Branch (with branch set to main).
  4. Click Finish.

CocoaPods

BottomSheet is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'BottomSheetSwiftUI'

Usage

WARNING: This is Sample Code for visualisation where and how to use, without a working initializer. Please see Examples for working code.

BottomSheet is similar to the built-in Sheet:

struct ContentView: View {

    @State var bottomSheetPosition: BottomSheetPosition = .middle //1
    
    var body: some View {
    
        Map() //2
            .bottomSheet() //3
    }
}

//1 The current State of the BottomSheet.

  • This is any enum that conforms to CGFloat and CaseIterable. For more information about custom enums see Custom States.
  • The following states are posible when using the predefinded BottomSheetPosition: .hidden, .bottom, .middle and .top.
  • If you don't want the state to be changed, you can use .constant(.middle) (with the .notResizeable or .noDragIndicator option).

//2 The view which the BottomSheet overlays.

//3 This is how you add the BottomSheet - easy right?

Parameters

Title as Header Content

.bottomSheet(
    bottomSheetPosition: Binding<BottomSheetPosition>,
    options: [BottomSheet.Options] = [],
    title: String? = nil,
    @ViewBuilder content: () -> mContent
)

bottomSheetPosition: A binding that saves the current state of the BottomSheet.

  • This can be any enum that conforms to CGFloat and CaseIterable. For more information about custom enums see Custom States.
  • The following states are posible when using the predefinded BottomSheetPosition: .hidden, .bottom, .middle and .top.
  • If you don't want the state to be changed, you can use .constant(.middle) for example (should be used with the .notResizeable or .noDragIndicator option).

options: An array that contains the settings / options for the BottomSheet. For more information about the possible options see Options.

title: A string that is used as the title for the BottomSheet.

  • Can be nil.
  • You can use a view that is used as header content for the BottomSheet instead.

content: A view that is used as main content for the BottomSheet.

Custom Header Content

.bottomSheet(
    bottomSheetPosition: Binding<BottomSheetPosition>,
    options: [BottomSheet.Options] = [],
    @ViewBuilder headerContent: () -> hContent?,
    @ViewBuilder mainContent: () -> mContent
)

bottomSheetPosition: A binding that saves the current state of the BottomSheet.

  • This can be any enum that conforms to CGFloat and CaseIterable. For more information about custom enums see Custom States.
  • The following states are posible when using the predefinded BottomSheetPosition: .hidden, .bottom, .middle and .top.
  • If you don't want the state to be changed, you can use .constant(.middle) for example (should be used with the .notResizeable or .noDragIndicator option).

options: An array that contains the settings / options for the BottomSheet. For more information about the possible options see Options.

headerContent: A view that is used as header content for the BottomSheet.

  • Can be nil.
  • You can use a string that is used as the title for the BottomSheet instead.
  • Any view is possible - this can lead to problems if the view is too large. A label, a small picture or text is recommended

mainContent: A view that is used as main content for the BottomSheet.

Options

.allowContentDrag Allows the BottomSheet to move when dragging the mainContent.

  • Do not use if the mainContent is packed into a ScrollView.

.animation(Animation) Sets the animation for opening and closing the BottomSheet.

.appleScrollBehavior The mainView is packed into a ScrollView, which can only scrolled at the .top position.

.background(AnyView) Changes the background of the BottomSheet.

  • Must be erased to AnyView.

.backgroundBlur(UIBlurEffect.Style = .systemThinMaterial) Enables and sets the blur effect of the background when pulling up the BottomSheet.

.cornerRadius(Double) Changes the corener radius of the BottomSheet.

.dragIndicatorColor(Color) Changes the color of the drag indicator.

.noBottomPosition Prevents the lowest value (above 0) from being the bottom position and hiding the mainContent.

.noDragIndicator Hides the drag indicator.

.notResizeable Hides the drag indicator and prevents the BottomSheet from being dragged.

.shadow(color: Color = Color(.sRGBLinear, white: 0, opacity: 0.33), radius: CGFloat = 10, x: CGFloat = 0, y: CGFloat = 0) Adds a shadow to the background of the BottomSheet.

.showCloseButton(action: () -> Void = {}) Shows a close button and declares an action to be performed when tapped.

  • If you tap on it, the BottomSheet and the keyboard always get dismissed.

  • If you want to do something extra, you have to declare it here.

.swipeToDismiss Dismisses the BottomSheet when swiped down.

.tapToDissmiss Dismisses the BottomSheet when the background is tapped.

Custom States

You can create your own custom BottomSheetPosition enum:

  • The enum must be conforming to CGFloat and CaseIterable
  • The case and enum name doesnt matter
  • The case/state with rawValue == 0 is hiding the BottomSheet
  • The value can be anythig between 0 and 1 (x <= 1, x >= 0)
  • The value is the height of the BottomSheet propotional to the screen height (1 == 100% == full screen)
  • The lowest value (greater than 0) automaticly gets the .bottom behavior. To prevent this please use the option .noBottomPosition
import SwiftUI

enum CustomBottomSheetPosition: CGFloat, CaseIterable {
    case top = 0.975, topMiddle = 0.7, middle = 0.4, middleBottom = 0.3, bottom = 0.125, hidden = 0
}

Examples

PLEASE NOTE: When installed via Cocoapods, please keep in mind that the pod is called BottomSheetSwiftUI and not BottomSheet; so please use import BottomSheetSwiftUI instead.

Book Detail View

This BottomSheet shows additional information about a book. You can close it by swiping it away, by tapping on the background or the close button. It also uses a custom enum for the states, since only the states .middle, .bottom and .hidden should exist.

import SwiftUI
import BottomSheet

//The custom BottomSheetPosition enum.
enum BookBottomSheetPosition: CGFloat, CaseIterable {
    case middle = 0.4, bottom = 0.125, hidden = 0
}

struct BookDetailView: View {
    
    @State private var bottomSheetPosition: BookBottomSheetPosition = .middle
    
    let backgroundColors: [Color] = [Color(red: 0.2, green: 0.85, blue: 0.7), Color(red: 0.13, green: 0.55, blue: 0.45)]
    let readMoreColors: [Color] = [Color(red: 0.70, green: 0.22, blue: 0.22), Color(red: 1, green: 0.32, blue: 0.32)]
    let bookmarkColors: [Color] = [Color(red: 0.28, green: 0.28, blue: 0.53), Color(red: 0.44, green: 0.44, blue: 0.83)]
    
    var body: some View {
        //A green gradient as a background that ignores the safe area.
        LinearGradient(gradient: Gradient(colors: self.backgroundColors), startPoint: .topLeading, endPoint: .bottomTrailing)
            .edgesIgnoringSafeArea(.all)
            
            .bottomSheet(bottomSheetPosition: self.$bottomSheetPosition, options: [.allowContentDrag, .showCloseButton(), .swipeToDismiss, .tapToDissmiss], headerContent: {
                //The name of the book as the heading and the author as the subtitle with a divider.
                VStack(alignment: .leading) {
                    Text("Wuthering Heights")
                        .font(.title).bold()
                    
                    Text("by Emily Brontë")
                        .font(.subheadline).foregroundColor(.secondary)
                    
                    Divider()
                        .padding(.trailing, -30)
                }
            }) {
                //A short introduction to the book, with a "Read More" button and a "Bookmark" button.
                VStack(spacing: 0) {
                    Text("This tumultuous tale of life in a bleak farmhouse on the Yorkshire moors is a popular set text for GCSE and A-level English study, but away from the demands of the classroom it’s easier to enjoy its drama and intensity. Populated largely by characters whose inability to control their own emotions...")
                        .fixedSize(horizontal: false, vertical: true)
                    
                    HStack {
                        Button(action: {}, label: {
                            Text("Read More")
                                .padding(.horizontal)
                        })
                        .buttonStyle(BookButton(colors: self.readMoreColors)).clipShape(Capsule())
                        
                        Spacer()
                        
                        Button(action: {}, label: {
                            Image(systemName: "bookmark")
                        })
                        .buttonStyle(BookButton(colors: self.bookmarkColors)).clipShape(Circle())
                    }
                    .padding(.top)
                    
                    Spacer(minLength: 0)
                }
                .padding([.horizontal, .top])
            }
    }
}

//The gradient ButtonStyle.
struct BookButton: ButtonStyle {
    
    let colors: [Color]
    
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .font(.headline)
            .foregroundColor(.white)
            .padding()
            .background(LinearGradient(gradient: Gradient(colors: self.colors), startPoint: .topLeading, endPoint: .bottomTrailing))
    }
}

Word Search View

This BottomSheet shows nouns which can be filtered by searching. It adopts the scrolling behavior of apple, so that you can only scroll the ScrollView in the .top position. The higher the BottomSheet is dragged, the more blurry the background becomes (with the BlurEffect .dark) to move the focus to the BottomSheet.

import SwiftUI
import BottomSheet

struct WordSearchView: View {
    
    @State private var bottomSheetPosition: BottomSheetPosition = .middle
    
    @State private var searchText: String = ""
    let backgroundColors: [Color] = [Color(red: 0.28, green: 0.28, blue: 0.53), Color(red: 1, green: 0.69, blue: 0.26)]
    let words: [String] = ["birthday", "pancake", "expansion", "brick", "bushes", "coal", "calendar", "home", "pig", "bath", "reading", "cellar", "knot", "year", "ink"]
    
    var body: some View {
        //A green gradient as a background that ignores the safe area.
        LinearGradient(gradient: Gradient(colors: self.backgroundColors), startPoint: .topLeading, endPoint: .bottomTrailing)
            .edgesIgnoringSafeArea(.all)
            
            .bottomSheet(bottomSheetPosition: self.$bottomSheetPosition, options: [.appleScrollBehavior, .backgroundBlur(effect: .dark)], headerContent: {
                //A SearchBar as headerContent.
                HStack {
                    Image(systemName: "magnifyingglass")
                    TextField("Search", text: self.$searchText)
                }
                .foregroundColor(Color(UIColor.secondaryLabel))
                .padding(.vertical, 8)
                .padding(.horizontal, 5)
                .background(RoundedRectangle(cornerRadius: 10).fill(Color(UIColor.quaternaryLabel)))
                .padding(.bottom)
                //When you tap the SearchBar, the BottomSheet moves to the .top position to make room for the keyboard.
                .onTapGesture {
                    self.bottomSheetPosition = .top
                }
            }) {
            //The list of nouns that will be filtered by the searchText.
                ForEach(self.words.filter({ $0.contains(self.searchText.lowercased()) || self.searchText.isEmpty}), id: \.self) { word in
                    Text(word)
                        .font(.title)
                        .padding([.leading, .bottom])
                        .frame(maxWidth: .infinity, alignment: .leading)
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                .transition(.opacity)
                .animation(.easeInOut)
                .padding(.top)
            }
    }
}

Artist Songs View

This BottomSheet shows the most popular songs by an artist. It has a custom animation and color for the drag indicator and the background, as well as it deactivates the bottom position behavior and uses an custom corner radius and shadow.

import SwiftUI
import BottomSheet

struct ArtistSongsView: View {
    
    @State private var bottomSheetPosition: BottomSheetPosition = .middle
    
    let backgroundColors: [Color] = [Color(red: 0.17, green: 0.17, blue: 0.33), Color(red: 0.80, green: 0.38, blue: 0.2)]
    let songs: [String] = ["One Dance (feat. Wizkid & Kyla)", "God's Plan", "SICKO MODE", "In My Feelings", "Work (feat. Drake)", "Nice For What", "Hotline Bling", "Too Good (feat. Rihanna)", "Life Is Good (feat. Drake)"]
    
    var body: some View {
        //A green gradient as a background that ignores the safe area.
        LinearGradient(gradient: Gradient(colors: self.backgroundColors), startPoint: .topLeading, endPoint: .bottomTrailing)
            .edgesIgnoringSafeArea(.all)
            
            .bottomSheet(bottomSheetPosition: self.$bottomSheetPosition, options: [.animation(.linear.speed(0.4)), .dragIndicatorColor(Color(red: 0.17, green: 0.17, blue: 0.33)), .background(AnyView(Color.black)), .noBottomPosition, .cornerRadius(30), .shadow(color: .white)], title: "Drake") {
                //The list of the most popular songs of the artist.
                ScrollView {
                    ForEach(self.songs, id: \.self) { song in
                        Text(song)
                            .frame(maxWidth: .infinity, alignment: .leading)
                            .padding([.leading, .bottom])
                    }
                }
            }
            .foregroundColor(.white)
    }
}

Contributing

BottomSheet welcomes contributions in the form of GitHub issues and pull-requests.

License

BottomSheet is available under the MIT license. See the LICENSE file for more information.

Credits

BottomSheet is a project of @LucasMucGH.

Comments
  • [README]`.appleScrollBehavior`: Buttons are disabled in position `.middle`

    [README]`.appleScrollBehavior`: Buttons are disabled in position `.middle`

    Hi,

    first of all, you did an amazing job with this project :)

    I implemented the bottom sheet on top of a map view without customising the positions and placed a some buttons on the bottom sheet. My problem is, that the buttons are disabled, when the bottom sheet is not in position .top:

    Bildschirmfoto 2021-07-14 um 21 24 45

    If the bottom sheet will be pulled up to the .top-position, the buttons will not be disabled anymore: Bildschirmfoto 2021-07-14 um 21 25 39

    Is this a feature (that can be customised) it or is it a bug?

    Best Regards, Christoph

    bug Thank You ❤️ 
    opened by jagodki 12
  • Xcode 13: Compiler-Error UIApplication.shared

    Xcode 13: Compiler-Error UIApplication.shared

    The method

    private func endEditing() -> Void { UIApplication.shared.windows.filter{$0.isKeyWindow}.first?.endEditing(true) }

    throws a compiler error using BottomSheet in Xcode 13 Beta 3 for an iOS project (Deployment Target 15) saying that UIApplication extensions are not available for iOS and you should rely on ViewController functionality.

    bug 
    opened by Feuerwerk 11
  • ToDo

    ToDo

    This is a collection of features that are on my To-Do list. Each feature is briefly explained and a possible solution is described.

    Any feedback for further features or comments on the features (whether they are redundant or ideas for implementation) are welcomed. No ETA is and will be provided.

    Decided

    • Add support for iPad, Mac and horizontally rotated iPhones (see #3)
      • If you have a look at how Apple Maps displays the BottomSheet on the iPad or the iPhone when it is horizontally rotated, you will get the idea. I want to add this "floating" implementation.
    • Add an option to make the BottomSheet height dynamic to its content size (see #17)

    Declined

    • Add threshold for swipeToDismiss (see #8).
      • The current implementation doesn't need a threshold, because it is dynamic. It uses the flick through feature to decide when it should get dismissed.
    • Make BottomSheet not go above 100% (see #8)
      • If the BottomSheet gets dragged above the full screen height(100%), it snaps back to the highest value in the BottomSheetPosition enum. And because no value should be above 1, it will never be unreachable.
    • Transition to OptionSet for BottomSheet.Options
      • OptionSet does not work with associated values, so it can't replace my current attempt.

    Other

    • The default values of BottomSheetPosition still do not match Apple's. I've tried countless ways, but unfortunately couldn't find out how apple calculates the height in the different states.
    • The sheetBackground modifier still needs the View to be erased to AnyView. I have no idea how to make it better as an enum cannot have a some View or a generic type.
    enhancement 
    opened by lucaszischka 10
  • BottomSheet v3

    BottomSheet v3

    The goals

    I have been recoding the project to achieve

    • full macOS support
    • full iPad support
    • true landscape support
    • a more SwiftUI like feeling of the project

    ViewModifiers

    First I dropped the options: [BottomSheet.Options] parameter and instead switched to ViewModifiers. For example:

    ...
        .bottomSheet(...)
        .showCloseButton(self.isCloseButtonShown)
        .enableAppleScrollBehaviour()
        .customBackground(
            // No need for AnyView and works just like .background from SwiftUI
            Color.red
        )
        .onDismiss {
            // Custom dismiss action
        }
    

    I think the concept is pretty self explanatory and after the readme is updated with a full list of modifiers all question regarding this should be resolved.

    BottomSheetPosition

    I also tried to make the BottomSheetPosition easier to use and to implement new features; instead of subclassing I switched to a predefined enum that represents all different possibilities:

    case hidden
    
    case dynamicBottom
    case relativeBottom(CGFloat)
    case absoluteBottom(CGFloat)
    
    case dynamicTop
    case relativeTop(CGFloat)
    case absoluteTop(CGFloat)
    
    case dynamic
    case relative(CGFloat)
    case absolute(CGFloat)
    

    New cases explanation

    ...Bottom represents the state where the main content is hidden and ...Top the state where the BottomSheet can be scrolled when using .enableAppleScrollBehaviour(true). The last new option is dynamic... which represents the state where the sheet has a "dynamic" height / wraps its content height.

    Consequences

    However this new BottomSheetPosition requires you to tell the BottomSheet which positions can be switched out / into (for example by swiping down/up or tapping the tap indicator). Therefore I added a switchablePositions: [BottomSheetPosition] parameter, where you can declare the cases you want to have. For example:

    ..., switchablePositions: [
        .relativeBottom(0.125),
        .relative(0.4),
        .absolute(600),
        .relative(0.8),
        .absoluteTop(800)
    ], ...
    

    As you may realize, this looks very similar to the BottomSheetPosition enum in v2. Converting to it should therefore be easy.

    Pros and Cons

    Pros of the new implementation:

    • dynamic height (#17, #11)
    • having a BottomSheetPosition with relative, absolute and dynamic positions mixed #48
    • differentiating the ...Bottom positions from the rest (#78 #73 #72)

    Cons of the new implementation:

    • the need to declare the switchablePositions: [BottomSheetPosition] makes it not clearer or easier to use

    What do you think?

    • Is the syntax worse than before?
    • Do you have any ideas how the syntax could be made clearer and easier to use?
    • Or do you even like the new syntax?
    • Are the new features for the BottomSheetPosition 'worth it'? It would be nice if you could provide feedback regarding this questions.

    Other new features

    • Added onDismiss modifier (you can now perform an action when the sheet is dismissed)
    • Added dragGesture listener #62
    • Changed customBackground to not rely on AnyView #11
    • Fixed onAppear only called once #65

    About macOS and iPad support

    appleScrollBehaviour on iPad and Mac now 'only' packs the view inside of a basic ScrollView. Why? Because the sheet is "up side down" so you are pulling it down. And it is in the top left not on the bottom. Therefore the appleScrollBehaviour behaviour of the iPhone doesn't make sense.

    enhancement 
    opened by lucaszischka 9
  • Strange scroll behavior after removing .appleScrollBehavior

    Strange scroll behavior after removing .appleScrollBehavior

    Using .appleScrollBehavior disabled my buttons in the sheet, no matter at which position it was. So, I removed this option. I am now able to tap buttons in the sheet, but look at how strangely this scrolls:

    https://user-images.githubusercontent.com/9455439/156595983-44a3783f-7d16-4da1-90f6-d9e4c57062a8.mp4

    It's almost as if I had extra springy animations set – which I don't.
    In the mainContent, I simply have a VStack that holds a ForEach of a bunch of buttons.

    Any idea what's wrong and what I can do about it?

    invalid 
    opened by LinusGeffarth 8
  • add background param as View .

    add background param as View .

    If you think about countless cases when people have diff designs with diff backgroundColors, it would be phenomenal to add backgroundColor parameter as View since (BlurView , Color , LinearColor , etc) all confirm to View, also the Drawer(Capsule() ) on the top ought to have a passed parameter ✌🏻😉.

    I also suggest removing isShwoingCancel param and add isShowingBottomView: Binding , since designers + developers want to create their own View.

    enhancement 
    opened by TariqAlmazyad 8
  • Push new version to Cocoapods

    Push new version to Cocoapods

    Hi @LucasMucGH , thanks a lot for a great lib!

    I just noticed that the latest two versions did not make it to Cocoapods (attached screenshot). Perhaps you've forgotten to push the tags to Cocoapods repo?

    image

    Thank You ❤️ 
    opened by svachmic 6
  • Bottom sheet blocks inner scroll/gestures

    Bottom sheet blocks inner scroll/gestures

    Hi @LucasMucGH, thanx for an awesome lib.

    But I have faced a major issue on the newest build, when trying to add horizontal scroll or drag at BS content.

    Sample code:

    struct Content: View {
        
        @State var bottomSheetPosition: BottomSheetPosition = .bottom
    
        var colors: [Color] = [
            .blue, .black, .gray, .green, .orange, .pink, .yellow
        ]
        
        var scrollContent: some View {
            ScrollView(.horizontal) {
                HStack {
                    ForEach(colors, id: \.self) {
                        $0.frame(width: 100)
                    }
                }
            }
            .frame(height: 300)
            .padding([.trailing, .leading], 20)
        }
        
        var body: some Scene {
                scrollContent
                    .bottomSheet(bottomSheetPosition: self.$bottomSheetPosition,
                                 options: [.appleScrollBehavior, .noBottomPosition]) {
                        scrollContent
                    }
        }
    }
    
    

    And video: https://drive.google.com/file/d/1wp2V94RMepHBi6uRKhEpWE1kaOiCS-17/view?usp=sharing

    On the prev version I have fixed it with just adding an option to use simultaneous gesture, but now it doesn't work.

    Thanx.

    bug Thank You ❤️ 
    opened by ValeriyJefimov 6
  • appleScrollBehavior doesn't work on iOS 14.5

    appleScrollBehavior doesn't work on iOS 14.5

    appleScrollBehavior works only once and then it is not possible to maximize the bottom sheet using the scroll gesture. It works fine on iOS 15 but on version 14.5 there is some problem. btw this is an amazing library.

    import SwiftUI
    import BottomSheet
    
    //The custom BottomSheetPosition enum with absolute values.
    enum BookBottomSheetPosition: CGFloat, CaseIterable {
        case middle = 300, bottom = 100, hidden = 0
    }
    
    struct ContentView: View {
        @State var bottomSheetPosition: BottomSheetPosition = .middle
            @State var searchText: String = ""
            
            let backgroundColors: [Color] = [Color(red: 0.28, green: 0.28, blue: 0.53), Color(red: 1, green: 0.69, blue: 0.26)]
            let words: [String] = ["birthday", "pancake", "expansion", "brick", "bushes", "coal", "calendar", "home", "pig", "bath", "reading", "cellar", "knot", "year", "ink"]
            
            var filteredWords: [String] {
                self.words.filter({ $0.contains(self.searchText.lowercased()) || self.searchText.isEmpty })
            }
            
            
            var body: some View {
                //A green gradient as a background that ignores the safe area.
                LinearGradient(gradient: Gradient(colors: self.backgroundColors), startPoint: .topLeading, endPoint: .bottomTrailing)
                    .edgesIgnoringSafeArea(.all)
                    
                    .bottomSheet(bottomSheetPosition: self.$bottomSheetPosition, options: [.appleScrollBehavior, .swipeToDismiss, .tapToDismiss, .backgroundBlur(effect: .dark)], headerContent: {
                        //A SearchBar as headerContent.
                        HStack {
                            Image(systemName: "magnifyingglass")
                            TextField("Search", text: self.$searchText)
                        }
                        .foregroundColor(Color(UIColor.secondaryLabel))
                        .padding(.vertical, 8)
                        .padding(.horizontal, 5)
                        .background(RoundedRectangle(cornerRadius: 10).fill(Color(UIColor.quaternaryLabel)))
                        .padding(.bottom)
                        //When you tap the SearchBar, the BottomSheet moves to the .top position to make room for the keyboard.
                        .onTapGesture {
                            self.bottomSheetPosition = .top
                        }
                    }) {
                    //The list of nouns that will be filtered by the searchText.
                        ForEach(self.filteredWords, id: \.self) { word in
                            Text(word)
                                .font(.title)
                                .padding([.leading, .bottom])
                                .frame(maxWidth: .infinity, alignment: .leading)
                        }
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .transition(.opacity)
                        .animation(.easeInOut, value: self.filteredWords)
                        .padding(.top)
                    }
            }
        }
    

    https://user-images.githubusercontent.com/11679222/150329294-f4481e05-3675-4f9b-950a-bbc5cf78a799.mov

    bug Thank You ❤️ 
    opened by jannyProjects 6
  • Weird blinking when trying to pull bottom sheet

    Weird blinking when trying to pull bottom sheet

    Hey, Lucas. Thanx for such an awesome lib)

    Had an issue after latest update when trying to pull down content. Code sample attached

    ...
        .bottomSheet(
            bottomSheetPosition: $position),
            options: [
                .appleScrollBehavior,
                .swipeToDismiss,
                .noBottomPosition,
                .dragIndicatorColor(.surface),
                .background(AnyView(Color.clear))
            ]) {
                BottomView(...)
            }
    ...
    
    

    Also video sample attached https://user-images.githubusercontent.com/19861161/147619151-88d482ef-e8de-48f9-97b2-5e52faf0b6fc.mov

    Thanx a lot)

    bug Thank You ❤️ 
    opened by ValeriyJefimov 6
  • iPad Bottom Sheet, but at the Bottom ✨

    iPad Bottom Sheet, but at the Bottom ✨

    Hi!

    I like this library, but it would be awesome if the bottom sheet could actually be at the bottom on an iPad. 😁

    So... that's where this PR is for! I've also added a modifier that enables you to override the sheet width, and a modifier that adds bottom padding to the main content if the keyboard is opened (which should fix this issue I believe: #97 ).


    iPad Demo

    View's Code

    VStack {
        Button("TESTING APP 🦆") {}
    }
    .bottomSheet(
        bottomSheetPosition: $position,
        switchablePositions: [.dynamicBottom, .absolute(400), .absolute(600), .relativeTop(1)],
        headerContent: { Text("Bottom Sheet Title").font(.title.bold()) },
        mainContent: {
            VStack {
                Divider().padding()
                TextEditor(text: $loremIpsum)
            }
        }
    )
    .iPadFloatingSheet(false)
    .relativeSheetWidth(1.0)
    .accountForKeyboardHeight()
    

    Without the keyboard auto adjust

    https://user-images.githubusercontent.com/103025931/188599117-40a26131-a6cd-4855-9239-16ec7067b475.mp4

    With the keyboard auto adjust

    https://user-images.githubusercontent.com/103025931/188599133-7fcad1ac-8700-44e0-a646-267ebd207f51.mp4


    I'm looking forward to your feedback! 😊

    enhancement Thank You ❤️ 
    opened by RobinPelNedap 5
  • Warning in Xcode 14.0.1 in the Extension BottomSheetView + KeyboardHeight

    Warning in Xcode 14.0.1 in the Extension BottomSheetView + KeyboardHeight

    Describe the bug When the App compiles it throws the warning "Publishing changes from within view updates is not allowed, this will cause undefined behavior." in Line 40 of BottomSheetView + KeyboardHeight

    Expected behavior There are no warnings.

    Screenshots image

    Target version

    • Environment: iOS
    • Version: 3.1.0
    bug 
    opened by timroeringDB 1
  • Unable click on button when embed it inside NavigationView

    Unable click on button when embed it inside NavigationView

    Hi,

    First of all, thank you for making an amazing BottomSheet library for SwiftUI.

    Today, I'm having an issue with content of NavigationView. Basically, I would like to add navigation bar inside bottom sheet content. However after that, I can not click on my button inside bottom sheet. I just go around and found this is something incorrect with the animation: .animation( self.configuration.animation, value: self.bottomSheetPosition )

    but I don't know how to fix it. Please help.

    Video demo issue: https://drive.google.com/file/d/1qb4hFmebuahjv7rCoMjUgz82bOy-bBqS/view?usp=sharing

    Sample project: https://drive.google.com/file/d/1jewR37DNvfv-EnodqJ9KI1ZjOdWiPeZO/view?usp=sharing

    Screen Shot 2022-10-03 at 12 44 15 AM bug Thank You ❤️ 
    opened by tuannguyenanh177 1
  • Bottom sheet close does not work at certain conditions

    Bottom sheet close does not work at certain conditions

    Describe the bug When Content View contains Large content ( for the whole view) or Spacer() the displayed Close circle does not dismiss the bottom sheet window

    Minimal reproduce-able code

    .bottomSheet( bottomSheetPosition: $bottomSheetPosition, switchablePositions: [.dynamic], headerContent: { VStack(alignment: .leading) { Text("chosenlocation") .font(.title) .bold() if bottomSheetPosition == .dynamicBottom { Text("50° 21°") .font(.subheadline) .foregroundColor(.secondary) }

                    Divider()
                        .padding(.trailing, -30)
                }
                .padding([.top, .leading])
            },
            mainContent: { WaypointInfo() }
            
        )
        .onDismiss {
            bottomSheetPosition = .hidden
        }
        .showCloseButton(true)
        .enableTapToDismiss(true)
    

    struct WaypointInfo: View {

    var body: some View {
        VStack(alignment: .center) {
            HStack {
                Image("symbol")
                    .resizable()
                    .frame(width: 48, height: 48, alignment: .center)
                    .padding()
                VStack {
    
                    HStack {
                        Text("Longitude")
                        Spacer()
                        Text("50°")
                    }
                    HStack {
                        Text("Latitude")
                        Spacer()
                        Text("21°")
                    }
                    HStack {
                        Text("Elevation")
                        Spacer()
                        Text("100m")
                    }
                }
                
            }
            HStack {
                Text("description")
                    .multilineTextAlignment(.leading)
                    .lineLimit(nil)
                    .fixedSize(horizontal: false, vertical: true)
                
                Spacer()
            }
        }
        .padding()
        .padding(.bottom, 30)
    

    // Bellow code will cause sheet to not be able to dismiss after pressing close button Spacer() } }

    Expected behavior I expect that window can be dismissed regardless of the content.

    Screenshots If applicable, add screenshots to help explain your problem.

    Target version

    • Environment: [please select: iOS ]
    • Version: [iOS 16, latest Xcode]

    Additional context Add any other context about the problem here.

    opened by MADRAFi 1
  • dragIndicator animation bug.

    dragIndicator animation bug.

    Describe the bug

    스크린샷 2022-09-20 오후 5 14 26

    Hello, I am developing the swiftui app using the bottom sheet library. Thank you for creating a good library.

    While using the library, I experienced the same phenomenon as in the video below, but when I drag the bottom sheet, the animation of the dragIndicator is applied strangely and I can't find the right location. Can I remove the application of these animations?

    Minimal reproduce-able code

                        .bottomSheet(bottomSheetPosition: $bottomSheetPosition, switchablePositions: [
                            .relative(0.4),
                            .relativeTop(0.9)
                        ]) {
                            listView
                        }
    

    Expected behavior The bottom sheet contains a scroll view. This is happening when you drag this bottom sheet up and down.

    Screenshots If applicable, add screenshots to help explain your problem.

    https://user-images.githubusercontent.com/48409434/191205162-2744819c-b995-4a8a-8976-9197ce13863d.mov

    Target version iOS:: 16.0 BottomSheet:: 3.0.2

    bug Thank You ❤️ 
    opened by dortus47 6
  • Weird bottom padding while presenting when default animation being used

    Weird bottom padding while presenting when default animation being used

    Hey, thanx for such an awesome lib!

    Describe the bug When present bottom sheet just as usual we can see weird padding at the bottom causing by damping animation

    Minimal reproduceable code

     MapView()
       .bottomSheet(...)
       .enableContentDrag()
    

    Screenshots

    https://user-images.githubusercontent.com/19861161/185764860-73837238-9786-477e-9a22-3187328fbe6b.mov

    Target version

    • Environment: [IOS]
    • Version: [3.0.2]
    bug Thank You ❤️ 
    opened by ValeriyJefimov 0
Releases(3.1.0)
  • 3.1.0(Sep 20, 2022)

    v3.1.0

    • Added the .enableAccountingForKeyboardHeight(Bool) modifier #97
    • Added the .enableFloatingIPadSheet(Bool) modifier
    • Added the .sheetWidth(BottomSheetWidth) modifier
    • Fix #94
    Source code(tar.gz)
    Source code(zip)
  • 3.0.2(Aug 12, 2022)

  • 3.0.1(Aug 9, 2022)

  • 3.0.0(Aug 7, 2022)

    v3.0.0

    • Recoded the project
    • Added iPhone landscape support
    • Added iPad support
    • Added MacOS support
    • Changed from options to view modifiers
    • Cleaned up the code (swiftLint and splitting it up)
    • Added dynamic size support
    • Added onDismiss modifier
    • Added dragIndicatorAction modifier
    • Added dragPositionSwitchAction modifier
    • Added dragGesture listener
    • Changed customBackground to not rely on AnyView
    • Fixed onAppear only called once #65
    Source code(tar.gz)
    Source code(zip)
  • 2.8.0(Jun 17, 2022)

  • 2.7.0(Mar 28, 2022)

    v2.7.0

    • Fix drag indicator not draggable #45
    • Fix content not responding to tap gestures #51
    • Reworked .appleScrollBehavior to fix #46, #47 (also closes #53)
    • Redo explicit animation #59, #55
    Source code(tar.gz)
    Source code(zip)
  • v2.6.0(Jan 19, 2022)

    v2.6.0

    • Fix critical bug with .appleScrollBehavior #40
    • Update codestyle
    • Remove not used file
    • Update Readme
    • Renamed tapToDissmiss option tapToDismiss #43
    Source code(tar.gz)
    Source code(zip)
  • v2.5.0(Dec 28, 2021)

    v2.5.0

    • Update Copyright
    • Update swift-tools-version
    • Update deprecated code (real fix for #19, replaces #20)
    • Add .absolutePositionValue option #37
    • Add BottomSheetPositionAbsolute
    • Use explicit animations #31
    • Hide examples in ReadMe
    • Update and fix .appleScrollBehavior #37
    • Code clean up
    Source code(tar.gz)
    Source code(zip)
  • 2.4.0(Aug 3, 2021)

  • v2.3.0(Jul 21, 2021)

  • v2.2.0(Jun 10, 2021)

  • v2.1.0(Jun 8, 2021)

  • v2.0.0(Jun 2, 2021)

    v2.0.0

    • Implementation of the "options" system
    • Add noDragIndicator option
    • Add swipeToDismiss option
    • Add tapToDissmiss option
    • Add backgroundBlur option
    • Add dragIndicatorColor(Color) option
    • Splitting the code in different files for better clarity (ViewExtension)
    • Reorganised Files
    • Design fixes
    • Update Documentation accordingly
    Source code(tar.gz)
    Source code(zip)
  • v1.0.7(Mar 8, 2021)

    v1.0.7

    • Added flick through feature
    • Fixed drag indicator button not working issue #2 (thx @dbarsamian)
    • Improved Preview (thx @dbarsamian)
    • Plenty README.md updates
    • Fixed Dependencies
    • Custom States feature #4, #5
    • Extended SearchBar support
    Source code(tar.gz)
    Source code(zip)
  • v1.0.6(Mar 4, 2021)

  • v1.0.5(Mar 4, 2021)

    v1.0.5

    • Made the BottomSheet easier to drag
    • Updated .top BottomSheetPosition to mimic Apple Maps
    • Search Bar enhancements
    • Fixed .bottom BottomSheetPosition (Issue #1)
    • Added Bottom Padding to the Title
    Source code(tar.gz)
    Source code(zip)
  • v1.0.4(Jan 29, 2021)

  • v1.0.3(Jan 22, 2021)

  • 1.0.2(Jan 14, 2021)

  • 1.0.1(Jan 10, 2021)

  • 1.0.0(Jan 5, 2021)

Owner
Lucas Zischka
I'm a 16 years old Student from Munich, who is programming in his free time. I mainly work with Swift and SwiftUI, but I also do Java, C++ and Html, Css and JS.
Lucas Zischka
SnackBar that responds to the keyboard and shows a message at the bottom of the screen.

DGSnackBar Requirements Installation Usage Properties DGSnackBar SnackBar that responds to the keyboard and shows a message at the bottom of the scree

donggyu 11 Aug 6, 2022
Reusable & customizable SwiftUI settings sheet as a Swift package

PackAPrefPane Reusable & customizable SwiftUI settings sheet as a Swift package Features Swift package 100% Swift 99% SwiftUI Simple design Lightweigh

W1W1-M 9 Nov 6, 2022
Experimental SwiftUI build of the iOS app switcher

SwiftUI - iOS App Switcher This project is an approximation of the iOS app switcher UI experience, built with SwiftUI. The following interactions are

Marcus Crafter 65 Dec 8, 2022
The Conway's Game of Life that build with SwiftUI.

SwiftUI-LifeGame The Conway's Game of Life that build with SwiftUI. iOS iPad macOS Requirements Xcode 12.2 (beta 2) macOS Catalina macOS Big Sur (beta

Yusuke Hosonuma 52 Dec 15, 2022
Social Media platform build with swiftUI and Firebase with google and apple account integration for Signing In Users

Social Media platform build with swiftUI and Firebase with google and apple account integration for Signing In Users . Providing Users availability to upload posts and images add caption allowing other users to comment , with Find section to explore new people , new stories , User Profile section to allow the user to take control of his account .

Devang Papinwar 2 Jul 11, 2022
Trello Clone iOS App build with SwiftUI

Trello Clone iOS App - SwiftUI A Trello Clone App for iOS built with SwiftUI. Features The app has several main features: Card, BoardList CRUD. Drag a

Alfian Losari 72 Oct 28, 2022
Build Jike App UI with SwiftUI

SwiftUI_Jike 中文版 SwiftUI is a common cross-platform framework for the Apple ecosystem, easy to get started, support for real-time previews, easy inter

null 103 Dec 12, 2022
SwiftUI mirroring of Instagram app Home screen

Instasoup Is a quick code excercise, where I wanted to do fast prototaping of the Instagram like home view screen in #SwiftUI Check the source code an

Robert Herdzik 11 Feb 27, 2022
A realistic reflective shimmer to SwiftUI Views that uses device orientation. Position any View relative to device orientation to appear as if through a window or reflected by the screen.

A 3d rotation effect that uses Core Motion to allow SwiftUI views to appear projected in a specific direction and distance relative to the device in r

Ryan Lintott 235 Dec 30, 2022
Food App Onboarding screen made with SwiftUI

OnBoardSwiftUI-Food Food App Onboarding screen made with SwiftUI. App Details Lottie Files are used for Animations. TabView is used for Screen selecti

Shreyas Bhike 12 Jan 2, 2023
AllAboutTheWord - A single screen iOS app developed using swiftUI

All-About-The-Word Introduction This is a single screen iOS app developed using

null 7 Dec 22, 2022
ToDo App Build With Swift And MVVM Architecture

To Do App Project Description This project is the result of what i learned during IB Tech iOS Mobile Development Bootcamp. This project includes view

null 0 Oct 28, 2021
Dogs - A fun exploration of using Clean Swift methodology (VIP) to build a simple app

Dogs A fun exploration of using Clean Swift methodology (VIP) to build a simple app Was following the directory structure and templates as described i

Yarden Eitan 2 Dec 30, 2022
Home Assistant uses Bundler, Homebrew and Cocoapods to manage build dependencies

Home Assistant for Apple Platforms Getting Started Home Assistant uses Bundler, Homebrew and Cocoapods to manage build dependencies. You'll need Xcode

Home Assistant 1.1k Jan 8, 2023
An experiment to use Firebase and React Native to build a wwdc.family app

wwdc.family This is an experiment to use Firebase and React Native to build a wwdc.family app. Don't use that source code as reference - I have no pri

WWDC Family 190 Feb 9, 2022
A simple To-do list app build for iPhone, iPad and Apple Watch in Swift

A simple To-do list app build for iPhone, iPad and Apple Watch in Swift

Radu Ursache 186 Dec 28, 2022
The movie detail screen of the TodoMovies application using Swift

Desafio Mobile2You - TodoMovies Este desafio consiste na criação de uma réplica da tela de detalhe dos filmes do aplicativo TodoMovies utilizando Swif

Rychillie 7 Feb 10, 2022
An iOS app demo to show list and detail screen of artworks.

Artworks iOS Demo Application Architecture MVP Clean Architecture (check Known Issues) Dependency Injection Features Localization Dark mode support Ba

Muhammad Adam 0 Dec 29, 2021
Red Torch is a very very (very) simple iOS app that allows you to have a red torch using your screen.

RED Torch Red Torch is a very very (very) simple iOS app that allows you to have a red torch using your screen. The App is based on storyboard, so the

Jakub 0 Jan 1, 2022