Skip to content

Instantly share code, notes, and snippets.

@carlynorama
Created September 3, 2022 13:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carlynorama/6b70884d35e5a46833e7d36247d9ff55 to your computer and use it in GitHub Desktop.
Save carlynorama/6b70884d35e5a46833e7d36247d9ff55 to your computer and use it in GitHub Desktop.
Picker will reserve the requested amount of space embedded in a form or popover. Uses the Layout Protocol
//
// ReservingSpaceLayout.swift
// LayoutTests
//
// Created by carlynorama on 8/28/22.
//
import SwiftUI
struct SpaceReservingViewResults: View {
var items:[Result]
@Binding var showingResults:Bool
var body: some View {
ReservingSpaceWithView() {
//Will be used only as place holder.
//If not opaque will be smack dab in the middle of the view.
ResultRow(result: Result.example).opacity(0)
//Could be written inline as long as all in one container.
whatToActuallyDisplay()
}
}
@ViewBuilder func whatToActuallyDisplay() -> some View {
ZStack {
PlacehoderView().opacity(showingResults ? 0:1)
if showingResults {
ScrollView() {
VStack(alignment: .trailing) {
ForEach(items) { item in
ResultRow(result: item)
}
}.frame(maxWidth: .infinity, alignment: .trailing)
.padding(.trailing)
.opacity(showingResults ? 1:0)
.transition(resultReveal)
}
}
}
}
struct PlacehoderView:View {
var body: some View {
Rectangle().foregroundColor(Color(uiColor: .tertiarySystemFill))
.border(.secondary)
}
}
}
//MARK: - Space Reserving View
fileprivate struct ReservingSpaceWithView:Layout {
let count = 6.0
let widthComfort = 1.3
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
let sizeLimiter = subviews[0].sizeThatFits(.unspecified)
let suggestedSize = proposal.replacingUnspecifiedDimensions()
let size = CGSize(width: max(sizeLimiter.width * widthComfort, suggestedSize.width).rounded(), height: max(sizeLimiter.height * count, suggestedSize.height))
return size
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
guard subviews.count == 2 else {
print("This a container for 2 right now.")
fatalError("This a container for 2 right now.")
}
//Putting the resrving view out side of bounds messes up surrounding layout in some cases.
//Not placing it at all, like this does, means it gets placed in the center of the view.
// subviews[0].place(
// at: CGPoint(x: -1000, y: -1000),
// proposal: proposal
// )
subviews[1].place(
at: bounds.origin,
proposal: proposal
)
}
}
//MARK: - Result Data Structure and Row
struct Result:Identifiable, Hashable {
let value:Double
let id:UUID
static var example:Result {
Result(value: 43, id: UUID(uuidString:"F1A85EA3-E12F-46D7-9336-AA26A4E007C5")!)
}
}
extension Result {
init(value:Double) {
self.value = value
self.id = UUID()
}
}
struct ResultRow:View {
let result:Result
var body: some View {
HStack {
//Image(systemName: "globe")
VStack() {
//Text("Value:\(result.value.pretty)").font(.title)
//Text("\(result.id)").font(.caption)
Text("Value:\(result.value.pretty)")
.multilineTextAlignment(.leading)
//.allowsTightening(true)
Text("\(result.id)")
.font(.caption)
.multilineTextAlignment(.leading)
//.allowsTightening(true)
}
}
}
}
//MARK: - Optional Modifiers
var resultReveal:AnyTransition {
//AnyTransition.scale(scale: 2, anchor: UnitPoint(x: 1, y: 0))
AnyTransition.opacity.combined(with: .move(edge: .top)).combined(with: verticalClipTransition)
}
struct VerticalClipEffect:ViewModifier {
var value: CGFloat
func body(content: Content) -> some View {
content
.clipShape(Rectangle().scale(x: 1, y: value, anchor: .top))
}
}
var verticalClipTransition:AnyTransition {
.modifier(
active: VerticalClipEffect(value: 0),
identity: VerticalClipEffect(value: 1)
)
}
//
// FormView.swift
// LayoutTests
//
// Created by carlynorama on 8/28/22.
//
import SwiftUI
struct FormView: View {
@State var value:Double = 57
@State var now:Date = Date()
var body: some View {
Form {
PickerView(value: $value)
PickerPopoverView(value: $value, isEmbeded: true)
DatePicker("Date", selection: $now)
}
}
}
struct FormView_Previews: PreviewProvider {
static var previews: some View {
FormView()
}
}
//
// ChooserView.swift
// LayoutTests
//
// Created by carlynorama on 8/28/22.
//
import SwiftUI
struct PickerPopoverView: View {
@Environment(\.presentationMode) var presentationMode
@Environment(\.dynamicTypeSize) var typeSize
@Binding var value:Double
@State var buffer:Double = 0
@State var previousValues:[Result] = []
@State var showingResults = false
var isEmbeded = false
var body: some View {
VStack(alignment:.leading, spacing: 10.0) {
//The "Toolbar"
if !isEmbeded {
HStack {
//Button("Update") { updateLocation() }
Spacer()
Button("Close") { close() }
}
Spacer()
}
Stepper("\(value.pretty)", value: $value).onChange(of: value) { newValue in
previousValues.append(Result(value: buffer))
buffer = newValue
withAnimation {
showingResults = true
}
}
Spacer()
SpaceReservingViewResults(items: previousValues, showingResults: $showingResults)
}.padding()
.onAppear() {
buffer = value
}
}
func close() {
presentationMode.wrappedValue.dismiss()
print(UUID())
}
}
struct ChooserView_Previews: PreviewProvider {
static var previews: some View {
PickerPopoverView(value:Binding.mock(34.5))
}
}
//
// PickerView.swift
// LayoutTests
//
// Created by carlynorama on 8/28/22.
//
import SwiftUI
struct PickerView: View {
@State private var showingPopover = false
@Binding var value:Double
var body: some View {
HStack {
Text("Hello, World! I am the value: ")
LaunchPickerButton
}.popover(isPresented: $showingPopover) {
PickerPopoverView(value: $value)
}
}
@ViewBuilder var LaunchPickerButton:some View {
Button(
action: { showingPopover.toggle() },
label: {
Text("\(value.pretty)")
}).buttonStyle(.borderedProminent).frame(width: 100)
}
}
struct PickerView_Previews: PreviewProvider {
static var previews: some View {
PickerView(value: Binding.mock(34.5))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment