We've seen an issue when using a LazyVGrid inside a List. The app crashes with:
Thread 1: Fatal error: <UpdateCoalescingCollectionView 0x600000ca0d20> is stuck in a recursive layout loop
When debugging the issue, we were able to narrow down the issue to a minimum reproducible example below:
struct ContentView: View {
let columns = [
GridItem(.adaptive(minimum: 43))
]
var body: some View {
List {
LazyVGrid(columns: columns) {
ForEach(0..<15) { value in
if value == 0 {
Text("a")
} else {
Color.clear
}
}
}
}
}
}
The issue can be reproduced on iPhone 15 Pro Max and iOS 18.x specifically.
In a production app we have a similar layout, but instead of GridItem(.adaptive) we use GridItem(.flexible).
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
179 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi,
I'm working on an app that will mostly live in the menu bar.
I'm trying to make a menu item that looks similar to the Tailscale app's menu:
Note: I'm inspired by how Tailscale's menu is rendered:
I have made a View that shows my avatar, name, and optionally the company I work for:
import SwiftUI
struct MenuWhoAmI: View {
var username: String
var binding: String?
var body: some View {
HStack {
AsyncImage(url: URL(string: "https://avatars.githubusercontent.com/u/76716")!){ image in
image.resizable().scaledToFit()
} placeholder: {
ProgressView()
}
.clipShape(Circle())
VStack(alignment: .leading) {
Text(username)
if let binding = binding {
Text("\(binding)").foregroundStyle(.secondary)
}
}
}
}
}
#Preview {
VStack(alignment: .leading) {
MenuWhoAmI(username: "grahamc").padding()
Divider()
MenuWhoAmI(username: "grahamc", binding: "DeterminateSystems").padding()
}.padding()
}
I tried using it in my menu bar:
import SwiftUI
@main
struct DeterminateApp: App {
var body: some Scene {
MenuBarExtra("Determinate", image: "MenuIcon") {
MenuWhoAmI(username: "grahamc")
Button("Two") {}
Button("Three") {}
Divider()
Button("Quit") {
NSApplication.shared.terminate(nil)
}.keyboardShortcut("q")
}.menuBarExtraStyle(.menu)
}
}
and it renders differently:
After reading the forums and documentation, I understood the MenuBarExtra only renders certain elements. I then tried to use an NSStatusBar with an AppDelegate:
import AppKit
import SwiftUI
@main
struct DeterminateApp: App {
@NSApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
Window("Authentication", id: "login") {}
}
}
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
private var statusItem: NSStatusItem!
func applicationDidFinishLaunching(_ notification: Notification) {
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
if let button = statusItem.button {
button.image = NSImage(named: NSImage.Name("MenuIcon"))
}
statusItem.menu = NSHostingMenu(rootView: Group {
Button(action: { print("hi") }) {
MenuWhoAmI(username: "grahamc")
}
})
}
}
and still, the avatar/name doesn't render like I'd expect, missing the circle clipping:
...and I'm a bit mystified.
How can I make this menu render the way I'm trying for?
Thank you!
macOS 15 includes a neat section in System Preferences Settings to change the dynamic text size, as outlined see: https://support.apple.com/guide/mac-help/make-text-and-icons-bigger-mchld786f2cd/mac
However, it's not immediately clear a) how to get one's app in this list, and b) if the usual methods from iOS to react to text size even work on macOS. Does anyone have any experience here? Or should I implement my own controls in my app's settings and call it a day?
For context, my app is a macOS-native SwiftUI app.
I've read all previous posts on this topic but none seem to address what I'm seeing for iOS 16 and using NavigationStack. I'm also using an overall @EnvironmentObject for navigation state.
I have a split view app. In the detail section, I have a NavigationStack surrounding the detail view. Within the detail view (MyView), there is a base view with a "+" button in the toolbar to create a new entity.
That opens NewEntityView where I show a grid of buttons for the user to select a type to create a new entity before moving to NewEntityView to fill in the details for the entity. The top row of the grid of buttons takes the user straight to the NewEntityView with a NavigationLink. These work fine.
The next row of buttons present a menu of sub-types and then should take the user to the NewEntityView view. These buttons do not work.
Code (simplified to not have clutter):
SplitViewDetailView:
struct SplitViewDetailView: View {
@EnvironmentObject var navigationManager: NavigationStateManager
@Binding var selectedCategory: Route?
var body: some View {
NavigationStack(path: $navigationManager.routes) {
// other irrelevant stuff
MyView()
}
.environmentObject(navigationManager)
.navigationDestination(for: Route.self) { $0 }
}
}
MyView:
struct MyView: View {
@EnvironmentObject var navigationManager: NavigationStateManager
var body: some View {
List {
// other stuff
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {}, label: {
NavigationLink(value: Route.newTypeSelect) {
Image(systemName: "plus")
.frame(width: 44, height: 44)
}
} )
}
}
.navigationDestination(for: Route.self) { $0 }
}
SelectTypeView:
struct SelectTypeView: View {
var body: some View {
ZStack {
VStack {
// Top row with no subtypes
HStack {
ForEach (topRows, id: \.self) { type in
NavigationLink(value: Route.newEntityDetails(type.rawValue)) { <-- these work
Text(type)
}
}
}
HStack {
ForEach (middleRow, id: \.self) { type in
Menu {
ForEach (subtype[type], id: \.self) { sub in
NavigationLink(value: Route.newEntityDetails(sub.rawValue)) { <-- these go nowhere
Text(sub)
}
}
} label: {
Text(type)
}
}
}
}
}
}
}
NavigationStateManager:
class NavigationStateManager: ObservableObject {
@Published var routes = [Route]()
// other stuff
}
And Route:
enum Route: Identifiable {
var id: UUID { UUID() }
case newTypeSelect
case newEntityDetails(String)
}
extension Route: View {
var body: some View {
switch self {
case .newTypeSelect:
SelectTypeView()
case .newEntityDetails(let type):
NewEntityView(selectedType: type)
}
}
}
The menus show up fine but tapping on an item does nothing. I've attempted to wrap the menu in its own NavigationStack but that is rejected stating it is already in one defined by a parent view. I've tried making the links Buttons with destinations and those are also rejected.
What is the newest/best way to present a menu with NavigationLinks? One doesn't simply wrap the menu in a NavigationView if one is using a NavigationStack?
I am using the TabView control in SwiftUI on a tvOS 18 target with the style of sidebarAdaptable. When I have 7 or less tabs things operate correctly. When I add an 8th tab and you navigate to the contents of the tab the menu collapses as expected but you cannot navigate back to restore the menu. This code reproduces the issue:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
Tab("Tab1", systemImage: "person.circle") {
Button("Button1") {}
}
Tab("Tab2", systemImage: "person.circle") {
Button("Button2") {}
}
Tab("Tab3", systemImage: "person.circle") {
Button("Button3") {}
}
Tab("Tab4", systemImage: "person.circle") {
Button("Button4") {}
}
Tab("Tab5", systemImage: "person.circle") {
Button("Button5") {}
}
Tab("Tab6", systemImage: "person.circle") {
Button("Button6") {}
}
Tab("Tab7", systemImage: "person.circle") {
Button("Button7") {}
}
Tab("Tab8", systemImage: "person.circle") {
Button("Button8") {}
}
}
.tabViewStyle(.sidebarAdaptable)
}
}
If you eliminate Tab 8 the problem goes away. You can navigate back to the menu by moving to the left.
Notably the Destination Video sample also reproduces this issue:
https://developer.apple.com/documentation/visionos/destination-video
To reproduce:
Load the above code or Destination Video sample.
Navigate right (click right on remote or swipe right). Menu dismisses and just shows the item you have selected in the upper left corner.
Try to navigate left by clicking left on the remote or swiping left. It looks like the collapsed menu gets focus briefly, screen elements flash but the focus remains outside the menu.
Has anyone else encountered this issue?
In a TabView with the .sidebarAdaptable style, including TabSection elements prevents the default back swipe on the remote from revealing the sidebar. Removing all TabSection elements and using only Tab elements makes it work as expected:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
TabSection("Section") {
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
}
}.tabViewStyle(.sidebarAdaptable)
}
}
Am I using it wrong, or is this a bug?
Hello, I have a problem with the .onMove function. I believe I have set everything up properly. However, the moving does not seem to be working correctly. When I try to move the item, it is highlighted first, as it is supposed to be. Then, while I am moving it through the list, it disappears for some reason, and at the end of the move, it comes back to its initial place. (I use iOS 16.0 minimum, so I don't have to include the EditButton(). It works the same in the edit mode tho)
import SwiftUI
struct Animal: Identifiable {
var id = UUID()
var name: String
}
struct ListMove: View {
@State var animals = [Animal(name: "Dog"), Animal(name: "Cat"), Animal(name: "Cow"), Animal(name: "Goat"), Animal(name: "Chicken")]
var body: some View {
List {
ForEach(animals) { animal in
Text(animal.name)
}
.onMove(perform: move)
}
}
func move(from source: IndexSet, to destination: Int) {
animals.move(fromOffsets: source, toOffset: destination)
}
}
#Preview {
ListMove()
}
Hi,
I'm not sure why but when my fileURL is .jpg file and I drop the file from my app to Finder folders it make the dropped file as .jpeg
Is there a way to fix it?
[.onDrag {
if FileManager.default.fileExists(atPath: file.path) {
// Provide the file as an item for dragging
let fileURL = URL(fileURLWithPath: file.path)
let itemProvider = NSItemProvider(contentsOf: fileURL)
// Remove the file extension in the suggestedName
let baseNameWithoutExtension = fileURL.deletingPathExtension().lastPathComponent
itemProvider?.suggestedName = baseNameWithoutExtension
return itemProvider ?? NSItemProvider()
} else {
// Handle the case where the file no longer exists
print("File no longer exists at path: \(file.path)")
return NSItemProvider()
}
})
Hello everyone,
I am a beginner in programming and recently encountered an interesting issue in SwiftUI. (I must admit that it might not be a bug and could simply be due to my lack of understanding.)
I have extracted the relevant code that causes this behavior. Here's the code:
struct BugView: View {
var body: some View {
List {
VStack {
Button("Bug") {
print("1")
}
Button("Bug") {
print("2")
}
Button("Bug") {
print("3")
}
}
}
}
}
In this view, clicking any of the buttons results in all of them being triggered simultaneously. As a result, the console outputs:
1
2
3
I would appreciate it if someone could help me understand why this happens and how to fix it. Thanks in advance!
I feel like I must be missing something dumb, but I can't figure it out. I'm trying to create a modifier to make items resizable by dragging on the corner (I haven't actually implemented the corner part yet though so dragging anywhere on the object resizes it). However the rate that I'm dragging at is different from the rate that the object is resizing. It's also different for horizontal and vertical translation (the horizontal change is smaller than the rate that I'm dragging while the vertical change is larger).
Any help would be greatly appreciated!
Here's my code for the modifier:
struct Resizable: ViewModifier {
@State var size: CGSize = CGSize(width: 500, height: 500)
@State var activeSize: CGSize = .zero
func body(content: Content) -> some View {
content
.frame(width: abs(size.width + activeSize.width), height: abs(size.height + activeSize.height))
// offset is so the top right corner doesn't move
.offset(x: -abs(size.width + activeSize.width) / 2, y: abs(size.height + activeSize.height) / 2)
.gesture(
DragGesture()
.onChanged { gesture in
activeSize.width = -gesture.translation.width
activeSize.height = gesture.translation.height
}
.onEnded { _ in
size.width += activeSize.width
size.height += activeSize.height
activeSize = .zero
}
)
}
}
extension View {
func resizable(maxSize: CGSize = .zero) -> some View {
modifier(Resizable())
}
}
And it is used like so:
struct ContentView: View {
var body: some View {
Rectangle()
.fill(Color.blue)
.resizable()
}
}
Trying to use new Swift @Observable to monitor GPS position within SwiftUI content view. But how do I tie the latest locations to the SwiftUI Map's mapCameraPosition?
Well ideally the answer could cover:
How to fix this error - So get map tracking along with the User Position, but also
How to include facility to turn on/off the map moving to track the user position (which I'll need to do next). So could be tracking, then disable, move map around and have a look at things, then click button to start syncing the mapcameraposition to the GPS location again
Refer to error I'm embedded in the code below.
import SwiftUI
import MapKit
@Observable
final class NewLocationManager : NSObject, CLLocationManagerDelegate {
var location: CLLocation? = nil
private let locationManager = CLLocationManager()
func startCurrentLocationUpdates() async throws {
if locationManager.authorizationStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
for try await locationUpdate in CLLocationUpdate.liveUpdates() {
guard let location = locationUpdate.location else { return }
self.location = location
}
}
}
struct ContentView: View {
var newlocationManager = NewLocationManager()
@State private var cameraPosition: MapCameraPosition = .region(MKCoordinateRegion(
center: newlocationManager.location?.coordinate ?? <#default value#>,
span: MKCoordinateSpan(latitudeDelta: 0.25, longitudeDelta: 0.25)
))
// GET ERROR: Cannot use instance member 'newlocationManager' within property initializer; property initializers run before 'self' is available
var body: some View {
ZStack {
Map(position: $cameraPosition)
Text("New location manager: \(newlocationManager.location?.description ?? "NIL" )") // works
}
.task {
try? await newlocationManager.startCurrentLocationUpdates()
}
}
}
#Preview {
ContentView()
}
Hi,
I have the following swiftUI code:
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.colorEffect(ShaderLibrary.AlphaConvert())
and the following shader:
[[ stitchable ]] half4 AlphaConvert(float2 position, half4 currentColor) {
return half4(currentColor.r>0.5,currentColor.r<=0.5,0,(currentColor.r>0.5));
}
I am loading a full-res image from my photo library (24MP)... The image initially displays fine, with portions of the image red, and the rest black (due to alpha blending)... However, after rotating the device, I get an image that is a combination of red&green... Note, that the green pixels from the shader have alpha 0, hence, should never be seen. Is there something special that needs to be done on orientation changes so that the shader works fine?
I'm having an issue with my swiftui macOS application where it is continually consuming more memory over time and after a couple of hours will grind to a halt. I've watched a few videos now on how to use Xcode Memory Graph and Instruments to identify the source of a leak (I assume it is a leak). These videos all provide very obvious issues as examples but mine seems more elusive and I don't know how to identify which part of my code is the cause of the issue.
After running instruments I see the following but the leaked objects are not always consistent:
Xcode Memory Graph shows NSSet as the culprit which is shown under CoreFoundation (not my App). I really am a beginner here and because it's not showing me somewhere in my app that I can go and investigate I'm really stuck.
On a ScrollView+LazyVStack, the addition of .scrollTargetLayout causes many list items to be initialized, instead of the ordinary economical behavior of LazyVStack, where only the necessary items and views are initialized. Even worse, as the stack is scrolled down, all list items are reinitialized for every small scroll.
Without, .scrollTargetLayout, everything works fine.
I've tried every variation of locating modifiers, and different ways of identifying the list items, with no success.
Any ideas? Thanks.
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Post.created, ascending: true)],
animation: .default)
private var posts: FetchedResults<Post>
var body: some View {
ZStack{
ScrollView{
LazyVStack(spacing:0) {
ForEach(posts, id: \.self) { post in
PostView(post: post)
}
.onDelete(perform: deletePosts)
}.scrollTargetLayout() // <---- causes multiple Posts re-instantiations for any small scroll, very slow
}
.scrollPosition(id: $scrolledID)
.scrollTargetBehavior(.paging)
Hi! After upgrading to Xcode 16.1 my watchOS app is getting below error using a DatePicker configured with: displayedComponents: .hourAndMinute. I cannot find a solution for this error/warning. It only appears when im using : .hourAndMinute or : .hourAndMinuteandSeconds, but not .date. Note! My code is unchanged only change I Xcode upgrade. Any suggestions?
ForEach<Array, Array, _ConditionalContent<_ConditionalContent<_ConditionalContent<_ConditionalContent<YearPicker, MonthPicker>, _ConditionalContent<DayPicker, ComponentPicker>>, _ConditionalContent<_ConditionalContent<ComponentPicker, ComponentPicker>, _ConditionalContent<AMPMPicker, ModifiedContent<Text, _PaddingLayout>>>>, EmptyView>>: the ID [":"] occurs multiple times within the collection, this will give undefined results!
import SwiftUI
import WidgetKit
struct TimeEditView: View {
let title: String
@Binding var storedValue: String
var body: some View {
Form {
DatePicker(
title,
selection: Binding<Date>(
get: { Date.from(storedValue) ?? Date() },
set: { newDate in
storedValue = newDate.toString()
}
),
displayedComponents: .hourAndMinute
)
.onChange(of: storedValue) {
WidgetCenter.shared.reloadAllTimelines()
print("Morning Start changed!")
}
}
.navigationTitle(title)
}
}
These helper methods allow to use modifier methods in standard for SwiftUI short way.
extension View {
@inline(__always)
func modify(_ block: (_ view: Self) -> some View) -> some View {
block(self)
}
@inline(__always)
func modify<V : View, T>(_ block: (_ view: Self, _ data: T) -> V, with data: T) -> V {
block(self, data)
}
}
_
DISCUSSION
Suppose you have modifier methods:
func addBorder(view: some View) -> some View {
view.padding().border(Color.red, width: borderWidth)
}
func highlight(view: some View, color: Color) -> some View {
view.border(Color.red, width: borderWidth).overlay { color.opacity(0.3) }
}
_
Ordinar Decision
Your code may be like this:
var body: some View {
let image = Image(systemName: "globe")
let borderedImage = addBorder(view: image)
let highlightedImage = highlight(view: borderedImage, color: .red)
let text = Text("Some Text")
let borderedText = addBorder(view: text)
let highlightedText = highlight(view: borderedText, color: .yellow)
VStack {
highlightedImage
highlightedText
}
}
This code doesn't look like standard SwiftUI code.
_
Better Decision
Described above helper methods modify(:) and modify(:,with:) allow to write code in typical for SwiftUI short way:
var body: some View {
VStack {
Image(systemName: "globe")
.modify(addBorder)
.modify(highlight, with: .red)
Text("Some Text")
.modify(addBorder)
.modify(highlight, with: .yellow)
}
}
System provides AnyShape type erasure that animates correctly. But system doesn't provide AnyInsettableShape. Here is my implementation of AnyInsettableShape (and AnyAnimatableData that is needed to support animation).
Let me know if there is simpler solution.
struct AnyInsettableShape: InsettableShape {
private let _path: (CGRect) -> Path
private let _inset: (CGFloat) -> AnyInsettableShape
private let _getAnimatableData: () -> AnyAnimatableData
private let _setAnimatableData: (_ data: AnyAnimatableData) -> AnyInsettableShape
init<S>(_ shape: S) where S : InsettableShape {
_path = { shape.path(in: $0) }
_inset = { AnyInsettableShape(shape.inset(by: $0)) }
_getAnimatableData = { AnyAnimatableData(shape.animatableData) }
_setAnimatableData = { data in
guard let otherData = data.rawValue as? S.AnimatableData else { assertionFailure(); return AnyInsettableShape(shape) }
var shape = shape
shape.animatableData = otherData
return AnyInsettableShape(shape)
}
}
var animatableData: AnyAnimatableData {
get { _getAnimatableData() }
set { self = _setAnimatableData(newValue) }
}
func path(in rect: CGRect) -> Path {
_path(rect)
}
func inset(by amount: CGFloat) -> some InsettableShape {
_inset(amount)
}
}
struct AnyAnimatableData : VectorArithmetic {
init<T : VectorArithmetic>(_ value: T) {
self.init(optional: value)
}
private init<T : VectorArithmetic>(optional value: T?) {
rawValue = value
_scaleBy = { factor in
(value != nil) ? AnyAnimatableData(value!.scaled(by: factor)) : .zero
}
_add = { other in
AnyAnimatableData(value! + (other.rawValue as! T))
}
_subtract = { other in
AnyAnimatableData(value! - (other.rawValue as! T))
}
_equal = { other in
value! == (other.rawValue as! T)
}
_magnitudeSquared = {
(value != nil) ? value!.magnitudeSquared : .zero
}
_zero = {
AnyAnimatableData(T.zero)
}
}
fileprivate let rawValue: (any VectorArithmetic)?
private let _scaleBy: (_: Double) -> AnyAnimatableData
private let _add: (_ other: AnyAnimatableData) -> AnyAnimatableData
private let _subtract: (_ other: AnyAnimatableData) -> AnyAnimatableData
private let _equal: (_ other: AnyAnimatableData) -> Bool
private let _magnitudeSquared: () -> Double
private let _zero: () -> AnyAnimatableData
mutating func scale(by rhs: Double) {
self = _scaleBy(rhs)
}
var magnitudeSquared: Double {
_magnitudeSquared()
}
static let zero = AnyAnimatableData(optional: nil as Double?)
@inline(__always)
private var isZero: Bool { rawValue == nil }
static func + (lhs: AnyAnimatableData, rhs: AnyAnimatableData) -> AnyAnimatableData {
guard let (lhs, rhs) = fillZeroTypes(lhs, rhs) else { return .zero }
return lhs._add(rhs)
}
static func - (lhs: AnyAnimatableData, rhs: AnyAnimatableData) -> AnyAnimatableData {
guard let (lhs, rhs) = fillZeroTypes(lhs, rhs) else { return .zero }
return lhs._subtract(rhs)
}
static func == (lhs: AnyAnimatableData, rhs: AnyAnimatableData) -> Bool {
guard let (lhs, rhs) = fillZeroTypes(lhs, rhs) else { return true }
return lhs._equal(rhs)
}
@inline(__always)
private static func fillZeroTypes(_ lhs: AnyAnimatableData, _ rhs: AnyAnimatableData) -> (AnyAnimatableData, AnyAnimatableData)? {
switch (!lhs.isZero, !rhs.isZero) {
case (true, true): (lhs, rhs)
case (true, false): (lhs, lhs._zero())
case (false, true): (rhs._zero(), rhs)
case (false, false): nil
}
}
}
I'm starting with the template code from Apple from:
File > New Project > macOS app using Swift UI and Swift Data. Selection works fine if only adding items, but after deleting any selected item selection stops working for some rows. It seems like the UI and model get out of sync. After restarting the app, or simply launching a new window, it works again. Is this a known bug in Swift UI and is there a workaround?
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Item]
var body: some View {
NavigationSplitView {
List {
ForEach(items) { item in
NavigationLink {
Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
} label: {
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
}
.onDelete(perform: deleteItems)
}
.navigationSplitViewColumnWidth(min: 180, ideal: 200)
.toolbar {
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
} detail: {
Text("Select an item")
}
}
private func addItem() {
withAnimation {
let newItem = Item(timestamp: Date())
modelContext.insert(newItem)
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(items[index])
}
}
}
}
Hello. Recently, while studying alignmentGuide, I had questions about it behaving differently from the documentation when setting multiple alignment guides.
For example, the document states that only the alignmentGuide modifier with a first parameter matching the container's alignment will function.
Therefore, I thought that writing the Swift code below would result in the yellow color's center alignment being aligned with the HStack's bottom alignment.
struct TestView: View {
var body: some View {
HStack(alignment: .bottom) {
Color.yellow
.frame(height: 50)
.alignmentGuide(VerticalAlignment.center) { dim in
dim[.top]
}
.alignmentGuide(VerticalAlignment.top) { dim in
dim[.bottom]
}
.alignmentGuide(VerticalAlignment.bottom) { dim in
dim[VerticalAlignment.center]
}
Text("Hello, world")
}
.border(.green)
}
}
Expect
However, in reality, I observed that the top of the yellow color aligns with the HStack's bottom alignment. From this, I inferred that the 3rd alignmentGuide is applied first, and this also causes the first alignmentGuide to work, which makes me curious about how this is possible. If I leave only the 3rd alignmentGuide, it behaves as I expected.
Real Behavior
Could anybody help me to figure it out this behavior? Thank you