-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #992 from adevinta/component/bottomsheet
Component/bottomsheet
- Loading branch information
Showing
14 changed files
with
751 additions
and
0 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
core/Sources/Components/BottomSheet/SwiftUI/View-Height.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// | ||
// BottomSheetDetentViewModifier.swift | ||
// SparkCore | ||
// | ||
// Created by Michael Zimmermann on 17.05.24. | ||
// Copyright © 2024 Adevinta. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct ViewHeightPreferenceKey: PreferenceKey { | ||
static var defaultValue: CGFloat? | ||
|
||
static func reduce(value: inout CGFloat?, nextValue: () -> CGFloat?) { | ||
guard let nextValue = nextValue() else { return } | ||
value = nextValue | ||
} | ||
} | ||
|
||
struct ViewHeightModifier: ViewModifier { | ||
let height: Binding<CGFloat> | ||
func body(content: Content) -> some View { | ||
content | ||
.fixedSize(horizontal: true, vertical: true) | ||
.background( | ||
GeometryReader{ geometry in | ||
Color.clear | ||
.preference(key: ViewHeightPreferenceKey.self, value: geometry.size.height) | ||
} | ||
) | ||
.onPreferenceChange(ViewHeightPreferenceKey.self) { viewHeight in | ||
if let viewHeight { | ||
height.wrappedValue = viewHeight | ||
} | ||
} | ||
} | ||
} | ||
|
||
public extension View { | ||
/// A view modifier for reading the height of a view. The height will be set in the given binding. | ||
func readHeight(_ height: Binding<CGFloat>) -> some View { | ||
self | ||
.modifier(ViewHeightModifier(height: height)) | ||
} | ||
|
||
} |
61 changes: 61 additions & 0 deletions
61
...urces/Components/BottomSheet/UIKit/UISheetPresentationController-customHeightDetent.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// | ||
// UISheetPresentationController-customHeightDetent.swift | ||
// SparkCore | ||
// | ||
// Created by Michael Zimmermann on 14.05.24. | ||
// Copyright © 2024 Adevinta. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
|
||
public extension UISheetPresentationController.Detent { | ||
/// Return a custom sheet detent with the view height fitting the expanded size as the custom height. | ||
/// ``` | ||
/// let controller = ExampleBottomSheetViewController() | ||
/// if #available(iOS 16.0, *) { | ||
/// if let sheet = controller.sheetPresentationController { | ||
/// sheet.detents = [.medium(), .large(), .expandedHeight(of: controller.view)] | ||
/// } | ||
/// } | ||
/// present(controller, animated: true) | ||
/// ``` | ||
@available(iOS 16.0, *) | ||
static func expandedHeight(of view: UIView) -> UISheetPresentationController.Detent { | ||
return .custom { context in | ||
let height = min( | ||
view.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize).height, | ||
context.maximumDetentValue - 1) | ||
|
||
return height | ||
} | ||
} | ||
|
||
/// Return a custom sheet detent with the view height fitting the compressed size as the custom height. | ||
/// ``` | ||
/// let controller = ExampleBottomSheetViewController() | ||
/// if #available(iOS 16.0, *) { | ||
/// if let sheet = controller.sheetPresentationController { | ||
/// sheet.detents = [.medium(), .large(), .compressedHeight(of: controller.view)] | ||
/// } | ||
/// } | ||
/// present(controller, animated: true) | ||
/// ``` | ||
@available(iOS 16.0, *) | ||
static func compressedHeight(of view: UIView) -> UISheetPresentationController.Detent { | ||
return .custom { context in | ||
let height = min( | ||
view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height, | ||
context.maximumDetentValue - 1) | ||
|
||
return height | ||
} | ||
} | ||
|
||
@available(iOS 16.0, *) | ||
/// A custom detent which is almos the size of the large detent but avoids that the background is scaled. | ||
static func maxHeight() -> UISheetPresentationController.Detent { | ||
return .custom { context in | ||
return context.maximumDetentValue - 1 | ||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions
21
spark/Demo/Assets.xcassets/BottomSheet.imageset/Contents.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"images" : [ | ||
{ | ||
"idiom" : "universal", | ||
"scale" : "1x" | ||
}, | ||
{ | ||
"filename" : "BottomSheet.png", | ||
"idiom" : "universal", | ||
"scale" : "2x" | ||
}, | ||
{ | ||
"idiom" : "universal", | ||
"scale" : "3x" | ||
} | ||
], | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
spark/Demo/Classes/View/Components/BottomSheet/SwiftUI/BottomSheetPresentedView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// | ||
// BottomSheetPresentedView.swift | ||
// SparkDemo | ||
// | ||
// Created by Michael Zimmermann on 17.05.24. | ||
// Copyright © 2024 Adevinta. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct BottomSheetPresentedView: View { | ||
var description: String = """ | ||
Sample of a SwiftUI bottom sheet with little text. | ||
🧡💙 | ||
""" | ||
var dismiss: () -> Void | ||
|
||
var body: some View { | ||
VStack(spacing: 40) { | ||
Text("Bottom Sheet").font(.title) | ||
Text(description) | ||
.font(.body) | ||
.multilineTextAlignment(.center) | ||
.padding() | ||
Button { | ||
self.dismiss() | ||
} label: { | ||
Text("Dismiss") | ||
} | ||
.buttonStyle(.borderedProminent) | ||
} | ||
.frame(maxWidth: .infinity) | ||
.background(alignment: .top) { | ||
Image("BottomSheet") | ||
} | ||
} | ||
} |
166 changes: 166 additions & 0 deletions
166
spark/Demo/Classes/View/Components/BottomSheet/SwiftUI/BottomSheetPresentingView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// | ||
// BottomSheetExampleView.swift | ||
// SparkDemo | ||
// | ||
// Created by Michael Zimmermann on 17.05.24. | ||
// Copyright © 2024 Adevinta. All rights reserved. | ||
// | ||
|
||
import SwiftUI | ||
|
||
private let longDescription: String = """ | ||
Sample of a SwiftUI bottom sheet with a scroll view. | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
""" | ||
private let mediumDescription: String = """ | ||
Sample of a SwiftUI bottom sheet with a long text. | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
💙 | ||
🧡 | ||
""" | ||
struct BottomSheetPresentingView: View { | ||
var body: some View { | ||
if #available(iOS 16.4, *) { | ||
BottomSheetPresentingViewWithHeightDetent() | ||
} else { | ||
BottomSheetPresentingViewWithoutHeightDetent() | ||
} | ||
} | ||
} | ||
|
||
@available(iOS 16.4, *) | ||
struct BottomSheetPresentingViewWithHeightDetent: View { | ||
@State private var showingShortSheet = false | ||
@State private var showingMediumSheet = false | ||
@State private var showingLongSheet = false | ||
@State private var shortHeight: CGFloat = 100 | ||
@State private var mediumHeight: CGFloat = 100 | ||
|
||
var body: some View { | ||
VStack { | ||
Button("Show bottom sheet with little text") { | ||
self.showingShortSheet.toggle() | ||
} | ||
.sheet(isPresented: $showingShortSheet) { | ||
BottomSheetPresentedView() { | ||
self.showingShortSheet.toggle() | ||
} | ||
.readHeight(self.$shortHeight) | ||
.presentationDetents([.height(self.shortHeight), .large]) | ||
} | ||
.buttonStyle(.borderedProminent) | ||
|
||
Button("Show bottom sheet with longer text") { | ||
self.showingMediumSheet.toggle() | ||
} | ||
.sheet(isPresented: $showingMediumSheet) { | ||
BottomSheetPresentedView(description: mediumDescription) { | ||
self.showingMediumSheet.toggle() | ||
} | ||
.readHeight(self.$mediumHeight) | ||
.presentationDetents([.height(self.mediumHeight), .large]) | ||
} | ||
.buttonStyle(.borderedProminent) | ||
|
||
Button("Show bottom sheet with scroll view") { | ||
self.showingLongSheet.toggle() | ||
} | ||
.sheet(isPresented: $showingLongSheet) { | ||
ScrollView { | ||
BottomSheetPresentedView(description: longDescription) { | ||
self.showingLongSheet.toggle() | ||
} | ||
} | ||
.scrollIndicators(.visible) | ||
.presentationDetents([.medium, .large]) | ||
} | ||
.buttonStyle(.borderedProminent) | ||
} | ||
} | ||
} | ||
|
||
struct BottomSheetPresentingViewWithoutHeightDetent: View { | ||
@State private var showingShortText = false | ||
@State private var showingLongText = false | ||
|
||
var body: some View { | ||
VStack { | ||
Button("Show bottom sheet") { | ||
self.showingShortText.toggle() | ||
} | ||
.sheet(isPresented: $showingShortText) { | ||
BottomSheetPresentedView() { | ||
self.showingShortText.toggle() | ||
} | ||
} | ||
.buttonStyle(.bordered) | ||
|
||
Button("Show bottom sheet with Scroll view") { | ||
self.showingLongText.toggle() | ||
} | ||
.sheet(isPresented: $showingLongText) { | ||
ScrollView(showsIndicators: false) { | ||
BottomSheetPresentedView(description: longDescription) { | ||
self.showingLongText.toggle() | ||
} | ||
} | ||
} | ||
.buttonStyle(.bordered) | ||
} | ||
} | ||
} |
Oops, something went wrong.