Post

Replies

Boosts

Views

Activity

Reply to Mitigating overlapping text for sticky section headers for a plain List in iOS 26
Also filed FB19434244 Mitigating overlapping text for sticky section headers for a plain List with .scrollEdgeEffectStyle: For a List with .listStyle(.plain), for .scrollEdgeEffectStyle(.soft, for: .top), the headers should be un-pinned or there should be a modifier to make them un-pinned for .scrollEdgeEffectStyle(.hard, for: .top), the pinned header view should attach to the top bar and get a blurry material background, similar to a safeAreaBar()
Topic: UI Frameworks SubTopic: SwiftUI
Aug ’25
Reply to Mitigating overlapping text for sticky section headers for a plain List in iOS 26
👍 .safeAreaBar() now works together with .scrollEdgeEffectStyle(.hard, for: .top) out of the box in Beta 5: struct SafeAreaBarExample: View { var body: some View { NavigationStack { List { Text("Hello") } .listStyle(.plain) .navigationTitle("Example") .navigationBarTitleDisplayMode(.inline) .scrollEdgeEffectStyle(.hard, for: .top) .safeAreaBar(edge: .top, alignment: .leading) { Text("Safe Area Bar") .font(.body.bold()) .padding() .frame(maxWidth: .infinity, alignment: .leading) } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("More", systemImage: "ellipsis") { } } } } } }
Topic: UI Frameworks SubTopic: SwiftUI
Aug ’25
Reply to Animate colours in a SwiftUI Canvas
I was also looking into this recently; it seems Canvas isn't animatable in the classic sense, but it can be animated using a KeyframeAnimator: struct AnimatedCanvasView: View { @State private var trigger = false var body: some View { KeyframeAnimator( initialValue: Color.blue, trigger: trigger, content: { color in Canvas { context, _ in context.fill( Path(ellipseIn: CGRect(x: 50, y: 50, width: 100, height: 100)), with: .color(color) ) } }, keyframes: { _ in KeyframeTrack(\.self) { LinearKeyframe(Color.red, duration: 1.0) LinearKeyframe(Color.green, duration: 1.0) LinearKeyframe(Color.blue, duration: 1.0) } } ) .onTapGesture { trigger.toggle() } } } extension Color: @retroactive Animatable { public var animatableData: AnimatableValues<CGFloat, CGFloat, CGFloat, CGFloat> { get { let uiColor = UIColor(self) var red: CGFloat = 0 var green: CGFloat = 0 var blue: CGFloat = 0 var alpha: CGFloat = 0 uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) return AnimatableValues(red, green, blue, alpha) } set { self = Color( red: newValue.value.0, green: newValue.value.1, blue: newValue.value.2, opacity: newValue.value.3 ) } } } #Preview { AnimatedCanvasView() } (not sure if there's a more clean way to make Color Animatable / if there is a reason why it's not Animatable by default)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Aug ’25
Reply to Mitigating overlapping text for sticky section headers for a plain List in iOS 26
Is there a modifier to make section headers non-sticky? You can use the automatic .listStyle(.automatic) or opt for a lazy stack instead and apply your decorators. For examples, refer to Grouping data with lazy stack views. .listStyle(.automatic) results in in .insetGrouped, so that's a different look. I tried the LazyVStack approach and this worked well for a screen that was pretty custom-styled anyway. Side note: LazyVStack made me a little upset by applying the spacing not only between rows, but also after the section header; requiring dancing around with the spacing and paddings to get the correct look; I wished for a separation of "spacing between sections", "spacing between rows" and "spacing between [section header/rows/section footer]". But I'm wondering if this is a well-rounded approach for Views that just want a plain styled data list. It's certainly more feasible with the delicate separators-going-all-the-way-through-to-the-edge-of-the-screen gone in iOS 26, but still, custom-rebuilding all the Views with details like spacings and font styling and separators; just to get non-sticky headers? Even with List seemingly stuck in its past as UITable/CollectionViewController wrapper, I'm keeping my fingers crossed that something like List and .listStyle(.plain) might get a come-back. Imo it would be worth having a View that provides a plain minimal default styling for plain simple data lists with convenience like configurable pinnedHeaders etc. You can provide a background for your section header. However you can't provide a material for the scrollEdgeEffectStyle apart from either hard or soft ScrollEdgeEffectStyle. Can you give safeAreaBar(edge:alignment:spacing:content:) a try and disable the scroll edge effect using scrollEdgeEffectHidden. That would allow you provide a view as a custom bar. To clarify, I'm looking for a way to get the same blurry material behind the top bar and the pinned column headers. So I was hoping there would be a way to extend the scrollEdgeEffectStyle to the pinned headers or to add my own custom view (instead of pinned headers) into/below the top bar (so that it then gets the same material). I don't care what material it is exactly, I just want it to go nicely with the iOS 26 look. In this example I also don't care if it's a pinned header or an extra to the top bar, as it's only one header for the whole view. It would be nice to have a general solution for pinned section headers though. Side note: The Calendar app does something similar to the "extra view in the top bar" to get a the week days above the calendar: When I use .background(Material.regular) in a .safeAreaBar, the top bar always gets an opaque light gray background (beta 4), so that doesn't seem to do the trick (using List here, but it's the same with LazyVStack): struct ContentView: View { var body: some View { NavigationStack { List { ForEach(1...100, id: \.self) { idx in Text("Row \(idx)") } } .listStyle(.plain) .navigationTitle("Example") .navigationBarTitleDisplayMode(.inline) .safeAreaBar(edge: .top) { Text("Header") .font(.subheadline.bold()) .foregroundStyle(.secondary) .padding(.horizontal) .padding(.vertical, 4) .frame(maxWidth: .infinity, alignment: .leading) .background(Material.regular) } //.scrollEdgeEffectStyle(.hard, for: [.top]) .scrollEdgeEffectHidden() } } }
Topic: UI Frameworks SubTopic: SwiftUI
Aug ’25
Reply to Sheet-like presentation on the side on iPad
I filed 2 feedback reports about this: FB19252284: Support for side/corner-attached .sheet() with presentationDetents on iPad I’m suggesting to add support for .sheet() with presentationDetents on iPad; with the sheet then attaching to the side / to the corner of the screen, similar to how the Maps app presents its sheet. Currently the sheet always presents form/page-like in the middle of the screen which is of limited use for apps that want to present a map behind the sheet. It would be great if the side/corner (trailing/leading; trailing-bottom or leading-bottom corner) and the sheet width could be configured. Attached are screen shots of a standalone example with a custom glass container used for non-draggable sheet-like presentation and the Maps app with its fully draggable side sheet: FB19252414: Container glass background disappears when a Menu with a glass effect appears When .glassEffect() is used to build a custom sideways sheet-like presentation on iPad, the glass background disappears when a Menu with a glass effect appears. Example code: import MapKit import SwiftUI struct ContentView: View { var body: some View { Map() .overlay(alignment: .topLeading) { NavigationStack { VStack { Text("Sheet over map example") } .toolbar { ToolbarItem(placement: .topBarTrailing) { Menu( content: { Button("Example") {} }, label: { Image(systemName: "ellipsis") } ) } } .navigationTitle("Example") .navigationBarTitleDisplayMode(.inline) .containerBackground(Color.clear, for: .navigation) } .frame(width: 400) .frame(maxHeight: .infinity) .glassEffect(.regular, in: .rect(cornerRadius: 22)) .padding() } } } #Preview { ContentView() }
Topic: UI Frameworks SubTopic: SwiftUI
Jul ’25
Reply to Button Touch Not Canceled in ScrollView on Modal in SwiftUI for iOS 18
This is still happening in iOS 26 Beta 3, reported this via Feedback Assistant: FB18927179: Button touch is not cancelled when sheet drag or scroll gesture starts on a Button inside a ScrollView inside a .sheet Steps to reproduce: Use the attached example snippet: A Button inside a ScrollView inside a .sheet Start dragging the sheet or scrolling with the finger on the Button. Expected behavior: After a little bit of drag movement, it should detect that it’s a scroll/sheet drag and the Button touch should be cancelled / the button action should not be fired. This behaviour can be observed when no ScrollView is present. Observed behavior: Button touch is not cancelled and the action fires, even when the gesture clearly looked like a sheet drag/scroll. Example code: struct ContentView: View { @State var showAlert = false var body: some View { Text("Hello, world!") .sheet(isPresented: .constant(true)) { NavigationStack { ScrollView(.vertical) { VStack { ForEach(1...100, id: \.self) { _ in Button("Hello World") { self.showAlert = true } } } .frame(maxWidth: .infinity) .buttonStyle(.borderedProminent) } .alert(isPresented: $showAlert) { Alert(title: Text("Button tapped")) } .navigationTitle("Scrollable view in sheet") .navigationBarTitleDisplayMode(.inline) } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jul ’25
Reply to Keeping the glass-style background inside a sheet with presentationDetents when navigating inside the sheet
Found it, .containerBackground does the trick: import SwiftUI import MapKit struct ContentView: View { var body: some View { Map() .sheet(isPresented: .constant(true)) { NavigationStack { VStack { Text("Hello") NavigationLink("Show Foo") { Text("Foo") .navigationTitle("Foo") .containerBackground(Color.clear, for: .navigation) /* <--- */ } } } .presentationDetents([.medium, .large]) .presentationBackgroundInteraction(.enabled) } } }
Topic: UI Frameworks SubTopic: SwiftUI
Jul ’25
Reply to Mitigating overlapping text for sticky section headers for a plain List in iOS 26
Also filed FB19434244 Mitigating overlapping text for sticky section headers for a plain List with .scrollEdgeEffectStyle: For a List with .listStyle(.plain), for .scrollEdgeEffectStyle(.soft, for: .top), the headers should be un-pinned or there should be a modifier to make them un-pinned for .scrollEdgeEffectStyle(.hard, for: .top), the pinned header view should attach to the top bar and get a blurry material background, similar to a safeAreaBar()
Topic: UI Frameworks SubTopic: SwiftUI
Replies
Boosts
Views
Activity
Aug ’25
Reply to Mitigating overlapping text for sticky section headers for a plain List in iOS 26
👍 .safeAreaBar() now works together with .scrollEdgeEffectStyle(.hard, for: .top) out of the box in Beta 5: struct SafeAreaBarExample: View { var body: some View { NavigationStack { List { Text("Hello") } .listStyle(.plain) .navigationTitle("Example") .navigationBarTitleDisplayMode(.inline) .scrollEdgeEffectStyle(.hard, for: .top) .safeAreaBar(edge: .top, alignment: .leading) { Text("Safe Area Bar") .font(.body.bold()) .padding() .frame(maxWidth: .infinity, alignment: .leading) } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("More", systemImage: "ellipsis") { } } } } } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
Boosts
Views
Activity
Aug ’25
Reply to Animate colours in a SwiftUI Canvas
I was also looking into this recently; it seems Canvas isn't animatable in the classic sense, but it can be animated using a KeyframeAnimator: struct AnimatedCanvasView: View { @State private var trigger = false var body: some View { KeyframeAnimator( initialValue: Color.blue, trigger: trigger, content: { color in Canvas { context, _ in context.fill( Path(ellipseIn: CGRect(x: 50, y: 50, width: 100, height: 100)), with: .color(color) ) } }, keyframes: { _ in KeyframeTrack(\.self) { LinearKeyframe(Color.red, duration: 1.0) LinearKeyframe(Color.green, duration: 1.0) LinearKeyframe(Color.blue, duration: 1.0) } } ) .onTapGesture { trigger.toggle() } } } extension Color: @retroactive Animatable { public var animatableData: AnimatableValues<CGFloat, CGFloat, CGFloat, CGFloat> { get { let uiColor = UIColor(self) var red: CGFloat = 0 var green: CGFloat = 0 var blue: CGFloat = 0 var alpha: CGFloat = 0 uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) return AnimatableValues(red, green, blue, alpha) } set { self = Color( red: newValue.value.0, green: newValue.value.1, blue: newValue.value.2, opacity: newValue.value.3 ) } } } #Preview { AnimatedCanvasView() } (not sure if there's a more clean way to make Color Animatable / if there is a reason why it's not Animatable by default)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Aug ’25
Reply to Mitigating overlapping text for sticky section headers for a plain List in iOS 26
Is there a modifier to make section headers non-sticky? You can use the automatic .listStyle(.automatic) or opt for a lazy stack instead and apply your decorators. For examples, refer to Grouping data with lazy stack views. .listStyle(.automatic) results in in .insetGrouped, so that's a different look. I tried the LazyVStack approach and this worked well for a screen that was pretty custom-styled anyway. Side note: LazyVStack made me a little upset by applying the spacing not only between rows, but also after the section header; requiring dancing around with the spacing and paddings to get the correct look; I wished for a separation of "spacing between sections", "spacing between rows" and "spacing between [section header/rows/section footer]". But I'm wondering if this is a well-rounded approach for Views that just want a plain styled data list. It's certainly more feasible with the delicate separators-going-all-the-way-through-to-the-edge-of-the-screen gone in iOS 26, but still, custom-rebuilding all the Views with details like spacings and font styling and separators; just to get non-sticky headers? Even with List seemingly stuck in its past as UITable/CollectionViewController wrapper, I'm keeping my fingers crossed that something like List and .listStyle(.plain) might get a come-back. Imo it would be worth having a View that provides a plain minimal default styling for plain simple data lists with convenience like configurable pinnedHeaders etc. You can provide a background for your section header. However you can't provide a material for the scrollEdgeEffectStyle apart from either hard or soft ScrollEdgeEffectStyle. Can you give safeAreaBar(edge:alignment:spacing:content:) a try and disable the scroll edge effect using scrollEdgeEffectHidden. That would allow you provide a view as a custom bar. To clarify, I'm looking for a way to get the same blurry material behind the top bar and the pinned column headers. So I was hoping there would be a way to extend the scrollEdgeEffectStyle to the pinned headers or to add my own custom view (instead of pinned headers) into/below the top bar (so that it then gets the same material). I don't care what material it is exactly, I just want it to go nicely with the iOS 26 look. In this example I also don't care if it's a pinned header or an extra to the top bar, as it's only one header for the whole view. It would be nice to have a general solution for pinned section headers though. Side note: The Calendar app does something similar to the "extra view in the top bar" to get a the week days above the calendar: When I use .background(Material.regular) in a .safeAreaBar, the top bar always gets an opaque light gray background (beta 4), so that doesn't seem to do the trick (using List here, but it's the same with LazyVStack): struct ContentView: View { var body: some View { NavigationStack { List { ForEach(1...100, id: \.self) { idx in Text("Row \(idx)") } } .listStyle(.plain) .navigationTitle("Example") .navigationBarTitleDisplayMode(.inline) .safeAreaBar(edge: .top) { Text("Header") .font(.subheadline.bold()) .foregroundStyle(.secondary) .padding(.horizontal) .padding(.vertical, 4) .frame(maxWidth: .infinity, alignment: .leading) .background(Material.regular) } //.scrollEdgeEffectStyle(.hard, for: [.top]) .scrollEdgeEffectHidden() } } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
Boosts
Views
Activity
Aug ’25
Reply to Sheet-like presentation on the side on iPad
I filed 2 feedback reports about this: FB19252284: Support for side/corner-attached .sheet() with presentationDetents on iPad I’m suggesting to add support for .sheet() with presentationDetents on iPad; with the sheet then attaching to the side / to the corner of the screen, similar to how the Maps app presents its sheet. Currently the sheet always presents form/page-like in the middle of the screen which is of limited use for apps that want to present a map behind the sheet. It would be great if the side/corner (trailing/leading; trailing-bottom or leading-bottom corner) and the sheet width could be configured. Attached are screen shots of a standalone example with a custom glass container used for non-draggable sheet-like presentation and the Maps app with its fully draggable side sheet: FB19252414: Container glass background disappears when a Menu with a glass effect appears When .glassEffect() is used to build a custom sideways sheet-like presentation on iPad, the glass background disappears when a Menu with a glass effect appears. Example code: import MapKit import SwiftUI struct ContentView: View { var body: some View { Map() .overlay(alignment: .topLeading) { NavigationStack { VStack { Text("Sheet over map example") } .toolbar { ToolbarItem(placement: .topBarTrailing) { Menu( content: { Button("Example") {} }, label: { Image(systemName: "ellipsis") } ) } } .navigationTitle("Example") .navigationBarTitleDisplayMode(.inline) .containerBackground(Color.clear, for: .navigation) } .frame(width: 400) .frame(maxHeight: .infinity) .glassEffect(.regular, in: .rect(cornerRadius: 22)) .padding() } } } #Preview { ContentView() }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
Boosts
Views
Activity
Jul ’25
Reply to Button Touch Not Canceled in ScrollView on Modal in SwiftUI for iOS 18
This is still happening in iOS 26 Beta 3, reported this via Feedback Assistant: FB18927179: Button touch is not cancelled when sheet drag or scroll gesture starts on a Button inside a ScrollView inside a .sheet Steps to reproduce: Use the attached example snippet: A Button inside a ScrollView inside a .sheet Start dragging the sheet or scrolling with the finger on the Button. Expected behavior: After a little bit of drag movement, it should detect that it’s a scroll/sheet drag and the Button touch should be cancelled / the button action should not be fired. This behaviour can be observed when no ScrollView is present. Observed behavior: Button touch is not cancelled and the action fires, even when the gesture clearly looked like a sheet drag/scroll. Example code: struct ContentView: View { @State var showAlert = false var body: some View { Text("Hello, world!") .sheet(isPresented: .constant(true)) { NavigationStack { ScrollView(.vertical) { VStack { ForEach(1...100, id: \.self) { _ in Button("Hello World") { self.showAlert = true } } } .frame(maxWidth: .infinity) .buttonStyle(.borderedProminent) } .alert(isPresented: $showAlert) { Alert(title: Text("Button tapped")) } .navigationTitle("Scrollable view in sheet") .navigationBarTitleDisplayMode(.inline) } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jul ’25
Reply to Keeping the glass-style background inside a sheet with presentationDetents when navigating inside the sheet
Found it, .containerBackground does the trick: import SwiftUI import MapKit struct ContentView: View { var body: some View { Map() .sheet(isPresented: .constant(true)) { NavigationStack { VStack { Text("Hello") NavigationLink("Show Foo") { Text("Foo") .navigationTitle("Foo") .containerBackground(Color.clear, for: .navigation) /* <--- */ } } } .presentationDetents([.medium, .large]) .presentationBackgroundInteraction(.enabled) } } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
Boosts
Views
Activity
Jul ’25