Compose custom layouts with SwiftUI

RSS for tag

Discuss the WWDC22 Session Compose custom layouts with SwiftUI

Posts under wwdc2022-10056 tag

7 Posts

Post

Replies

Boosts

Views

Activity

MyEqualWidthHStack WWDC example not working for me
Hi I really liked the video by Paul Lettieri, creating a replacement for HStack that gives equal width to each, so I wrote one for my app. But the app doesn't compile for me. It gives me "Trailing closure passed to parameter of type 'HorizontalAlignment' that does not accept a closure" against the top VStack, not the place where the equal lengths HStack replacement appears. This is my version of his struct: extension LayoutSubviews {       func maxSize() -> CGSize {     let subviewSizes = map { $0.sizeThatFits(.unspecified) }     return subviewSizes.reduce(CGSize.zero) { CGSize(width: Swift.max($0.width, $1.width), height: Swift.max($0.height, $1.height)) }   }// maxSize()       func spacing() -> [Double] {     return indices.map { index in       guard index < count - 1 else { return 0.0 }       return self[index].spacing.distance(to: self[index + 1].spacing, along: .horizontal)     }   }// spacing()     }// extension LayoutSubviews struct EqualWidthHStack: Layout {       func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {     let maxsize = subviews.maxSize()     let totalSpacing = subviews.spacing().reduce(0) { $0 + $1 }     return CGSize(width: maxsize.width * Double(subviews.count) + totalSpacing, height: maxsize.height)   }// sizeThatFits       func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {     let maxsize = subviews.maxSize()     let spacing = subviews.spacing()     let sizeProposal = ProposedViewSize(width: maxsize.width, height: maxsize.height)     var x = bounds.minX + maxsize.width / 2     for index in subviews.indices {       subviews[index].place(at: CGPoint(x: x, y: bounds.midX), anchor: .center, proposal: sizeProposal)       x += maxsize.width + spacing[index]     }   }// placeSubviews     }// EqualWidthHStack I wrote this trivial View to test it: struct ContentView: View {   var body: some View {     VStack {       HStack {         Button("Hi") { print("Hi!") }         Button("Hello") { print("Hello!") }         Button("Good evening") { print("Good evening!") }       }       EqualWidthHStack {         Button("Hi") { print("Hi!") }         Button("Hello") { print("Hello!") }         Button("Good evening") { print("Good evening!") }       }       Image(systemName: "globe")         .imageScale(.large)         .foregroundColor(.accentColor)       Text("Hello, world!")     }   } } I'm using Version 14.0 beta 2 (14A5229c) of Xcode. I was having a problem with the exact same message in another app with a much more complex main view. I hope someone can tell me what to do or what is going on here. Regards, Mark
5
1
2.1k
Feb ’24
Subviews don't apply assigned size in custom EqualSizeZStack layout
I tried to modify CustomLayoutProject in order to create some kind of ZStack which resizes child views to size of the largest one and positions them one over another with some vertical offset. And I'm stuck. Setup is next: I've created EqualSizeZStack: Layout and put in instead of ButtonStack() in ContentView like this: EqualSizeZStack { Buttons() }.border(.blue) I've restricted buttons width by setting their text width .frame(width: 200) instead of .frame(maxWidth: .infinity). Updated Goldfish model text to be 4x longer, so related button can grow up in restricted width (and it does). Layout container gets requested height, and largest size is calculated and assigned correctly (this logic was not changed). But smaller buttons just refuse to apply largest button size no matter what I do. What did I miss? func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { guard !subviews.isEmpty else { return } let maxSize = maxSize(subviews: subviews) let placementProposal = ProposedViewSize(width: maxSize.width, height: maxSize.height) var nextY = bounds.minY for index in subviews.indices { subviews[index].place( at: CGPoint(x: bounds.midX, y: nextY), anchor: .top, proposal: placementProposal) nextY += vOffset } }
0
0
508
Apr ’23
Growing entries to natural width of column in SwiftUI Grid
The new Grid View looks like it brings us a simple way to get row-column layouts into our SwiftUI apps! I wonder if someone can help me with one aspect: I have a situation similar to the one described for the Pet Leaderboard App in the "Compose custom layouts with SwiftUI" video. But I want to save space by putting the Cat/Goldfish/Dog voting buttons in the leaderboard table itself, in the first column, instead of the labels. Here's the code for a simplified version of that table: import SwiftUI struct TableDemo: View { var body: some View { Grid(alignment: .leading) { GridRow { Button { // vote for Cat } label: { Text("Cat").fontWeight(.bold).foregroundColor(.white).padding().background(.green).cornerRadius(8) } Text("23").fontWeight(.bold).foregroundColor(.white).gridColumnAlignment(.trailing) } GridRow { Button { // vote for Goldfish } label: { Text("Goldfish").fontWeight(.bold).foregroundColor(.white).padding().background(.green).cornerRadius(8) } Text("3").fontWeight(.bold).foregroundColor(.white) } } .padding(20) .background(Color(red: 50.0/255, green: 85.0/255, blue: 125.0/255)) .cornerRadius(16) } } struct TableDemo_Previews: PreviewProvider { static var previews: some View { TableDemo() } } which looks like this: That result is visually unappealing because the buttons are inconsistent. It's nice that the Grid column is as wide as the widest button - that part is a big win from using the Grid View! But I'd like to get them to conform to the width of the widest button. The normal solution for some situations is to set an infinite maxWidth to the buttons. eg: Text("Cat").fontWeight(.bold).frame(maxWidth: .infinity).foregroundColor(.white).padding().background(.green).cornerRadius(8) But that results in the entire column expanding to take all available space: So what can we do, other than resorting to a PreferenceKey based approach, to solve this? Is there an official Grid-centric way of fixing this? This is the desired layout (I manually sized the buttons):
0
0
767
Oct ’22
.onContinueUserActivity not calling in case of deep linking(iOS 14).
After implementation of deep linking and when we click link in notes or email then it should call .onContinueUserActivity in Swiftui. But it's not happening. Can someone help me, how to do it.
Replies
1
Boosts
0
Views
906
Activity
Feb ’24
MyEqualWidthHStack WWDC example not working for me
Hi I really liked the video by Paul Lettieri, creating a replacement for HStack that gives equal width to each, so I wrote one for my app. But the app doesn't compile for me. It gives me "Trailing closure passed to parameter of type 'HorizontalAlignment' that does not accept a closure" against the top VStack, not the place where the equal lengths HStack replacement appears. This is my version of his struct: extension LayoutSubviews {       func maxSize() -> CGSize {     let subviewSizes = map { $0.sizeThatFits(.unspecified) }     return subviewSizes.reduce(CGSize.zero) { CGSize(width: Swift.max($0.width, $1.width), height: Swift.max($0.height, $1.height)) }   }// maxSize()       func spacing() -> [Double] {     return indices.map { index in       guard index < count - 1 else { return 0.0 }       return self[index].spacing.distance(to: self[index + 1].spacing, along: .horizontal)     }   }// spacing()     }// extension LayoutSubviews struct EqualWidthHStack: Layout {       func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {     let maxsize = subviews.maxSize()     let totalSpacing = subviews.spacing().reduce(0) { $0 + $1 }     return CGSize(width: maxsize.width * Double(subviews.count) + totalSpacing, height: maxsize.height)   }// sizeThatFits       func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {     let maxsize = subviews.maxSize()     let spacing = subviews.spacing()     let sizeProposal = ProposedViewSize(width: maxsize.width, height: maxsize.height)     var x = bounds.minX + maxsize.width / 2     for index in subviews.indices {       subviews[index].place(at: CGPoint(x: x, y: bounds.midX), anchor: .center, proposal: sizeProposal)       x += maxsize.width + spacing[index]     }   }// placeSubviews     }// EqualWidthHStack I wrote this trivial View to test it: struct ContentView: View {   var body: some View {     VStack {       HStack {         Button("Hi") { print("Hi!") }         Button("Hello") { print("Hello!") }         Button("Good evening") { print("Good evening!") }       }       EqualWidthHStack {         Button("Hi") { print("Hi!") }         Button("Hello") { print("Hello!") }         Button("Good evening") { print("Good evening!") }       }       Image(systemName: "globe")         .imageScale(.large)         .foregroundColor(.accentColor)       Text("Hello, world!")     }   } } I'm using Version 14.0 beta 2 (14A5229c) of Xcode. I was having a problem with the exact same message in another app with a much more complex main view. I hope someone can tell me what to do or what is going on here. Regards, Mark
Replies
5
Boosts
1
Views
2.1k
Activity
Feb ’24
SwiftUI: how to reproduce the old Dark Sky app design?
See attached screenshots. How can this design be reproduced in SwiftUI? The capsules are positioned to represent the values. But the calculation needs to take into account the labels width. I tried using a mix of Grid and custom Layout but I haven’t found a way… Any help would be appreciated! Thanks
Replies
0
Boosts
0
Views
834
Activity
May ’23
Subviews don't apply assigned size in custom EqualSizeZStack layout
I tried to modify CustomLayoutProject in order to create some kind of ZStack which resizes child views to size of the largest one and positions them one over another with some vertical offset. And I'm stuck. Setup is next: I've created EqualSizeZStack: Layout and put in instead of ButtonStack() in ContentView like this: EqualSizeZStack { Buttons() }.border(.blue) I've restricted buttons width by setting their text width .frame(width: 200) instead of .frame(maxWidth: .infinity). Updated Goldfish model text to be 4x longer, so related button can grow up in restricted width (and it does). Layout container gets requested height, and largest size is calculated and assigned correctly (this logic was not changed). But smaller buttons just refuse to apply largest button size no matter what I do. What did I miss? func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { guard !subviews.isEmpty else { return } let maxSize = maxSize(subviews: subviews) let placementProposal = ProposedViewSize(width: maxSize.width, height: maxSize.height) var nextY = bounds.minY for index in subviews.indices { subviews[index].place( at: CGPoint(x: bounds.midX, y: nextY), anchor: .top, proposal: placementProposal) nextY += vOffset } }
Replies
0
Boosts
0
Views
508
Activity
Apr ’23
Constraining column number with iOS 16 Grid
The Grid shrinks contained views as more columns are added. Is there a way to set a maximum number of columns/rows such that, instead of shrinking, the grid becomes scrollable?
Replies
1
Boosts
0
Views
562
Activity
Feb ’23
Growing entries to natural width of column in SwiftUI Grid
The new Grid View looks like it brings us a simple way to get row-column layouts into our SwiftUI apps! I wonder if someone can help me with one aspect: I have a situation similar to the one described for the Pet Leaderboard App in the "Compose custom layouts with SwiftUI" video. But I want to save space by putting the Cat/Goldfish/Dog voting buttons in the leaderboard table itself, in the first column, instead of the labels. Here's the code for a simplified version of that table: import SwiftUI struct TableDemo: View { var body: some View { Grid(alignment: .leading) { GridRow { Button { // vote for Cat } label: { Text("Cat").fontWeight(.bold).foregroundColor(.white).padding().background(.green).cornerRadius(8) } Text("23").fontWeight(.bold).foregroundColor(.white).gridColumnAlignment(.trailing) } GridRow { Button { // vote for Goldfish } label: { Text("Goldfish").fontWeight(.bold).foregroundColor(.white).padding().background(.green).cornerRadius(8) } Text("3").fontWeight(.bold).foregroundColor(.white) } } .padding(20) .background(Color(red: 50.0/255, green: 85.0/255, blue: 125.0/255)) .cornerRadius(16) } } struct TableDemo_Previews: PreviewProvider { static var previews: some View { TableDemo() } } which looks like this: That result is visually unappealing because the buttons are inconsistent. It's nice that the Grid column is as wide as the widest button - that part is a big win from using the Grid View! But I'd like to get them to conform to the width of the widest button. The normal solution for some situations is to set an infinite maxWidth to the buttons. eg: Text("Cat").fontWeight(.bold).frame(maxWidth: .infinity).foregroundColor(.white).padding().background(.green).cornerRadius(8) But that results in the entire column expanding to take all available space: So what can we do, other than resorting to a PreferenceKey based approach, to solve this? Is there an official Grid-centric way of fixing this? This is the desired layout (I manually sized the buttons):
Replies
0
Boosts
0
Views
767
Activity
Oct ’22
Can't find ViewLayout API
Using Xcode Version 14.0 beta and the iOS deployment target of 16.0 the compiler complains that ViewLayout cannot be found. It is in a different framework than SwiftUI or is it just not in the beta releases yet?
Replies
1
Boosts
1
Views
774
Activity
Jun ’22