When there are more than 5 tabs in TabView, the tabs from the 5th and on get put in the "More" tab as a list.
But when each tab has its own NavigationStack, the tabs in "More" would have double navigation bars. The expected behavior is there should be only one navigation bar, and NavigationStack for tabs in "More" should be collapsed with navigation for the "More" tab itself.
Minimal reproducible case:
Run the code below as an app
Navigate to "More" tab
Navigate to "Tab 5" or "Tab 6"
You can see there are two navigation bars stacked on top of each other
struct Item: Identifiable {
let name: String
var id: String { name }
}
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
let items = [
Item(name: "Tab 1"),
Item(name: "Tab 2"),
Item(name: "Tab 3"),
Item(name: "Tab 4"),
Item(name: "Tab 5"),
Item(name: "Tab 6"),
]
var body: some View {
TabView {
ForEach(items) { item in
NavigationStack {
List {
Text(item.name)
}.navigationTitle(item.name)
}.tabItem {
Label(item.name, systemImage: "person")
}
}
}
}
}
Before iOS 18, I can get around this issue by making my own "More" tab. But now with the expectation that user can re-arrange the tabs and all tabs would show up in the sidebar, the "make my own more tab" approach no longer work very well.
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Since iOS 18 I have noticed a strange issue which happens to the TabView in SwiftUI when you switch from Dark to Light mode.
With this code:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
List {
ForEach(0..<100, id: \.self) { index in
Text("Row: \(index)")
}
}.tabItem {
Image(systemName: "house")
Text("Home")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The TabBar does not switch colours when going from dark to light, it work correctly when going from light to dark.
Here is a video of iOS 18 with the issue:
Here is a video of iOS 17.5 with same code and no issue:
On real device it looks (better), the color does update but with delay.
I have submitted a feedback bug report, but in the meanwhile has anyone been back to resolve this?
Trying to migrate to Swift 6.
However getting this error when using SwiftUI StoreKit purchase environment.
Sending main actor-isolated value of type 'PurchaseAction' with later accesses to nonisolated context risks causing data races
@Environment(\.purchase) private var purchase
let result = try await purchase(product)
What is current best-practice for supporting an external display in a SwiftUI iOS app in 2024?
(I'm only interested in iOS 17 and/or iOS 18)
The only docs I found require abandoning the SwiftUI App structure and "switching back to a full UIKit App Delegate".
Is this still the only option?
Are there any complete examples on how to accomplish this?
Also is testing external displays with Simulator at all reliable? All experiences I read about say that it never works.
Thanks in advance.
I am trying out the new TextField selection ability on macOS but it crashes in various different ways with extremely large stack traces. Looks like it is getting into re-entrant function calls.
A similar problem is described on the SwiftUI forums with no responses yet.
Here is my simple example
struct ContentView: View {
@State private var text: String = ""
@State private var selection: TextSelection?
var body: some View {
TextField("Message", text: $text, selection: $selection)
.padding()
}
}
Setting text to a value like "Hallo World" causes an instant crash as soon as you start typing in the TextField.
Setting text empty (as in example above) lets you edit the text but as it crashes as soon as you commit it (press enter).
Any workarounds or fixes?
Hello,
After a fair amount of time of trial and error, I have seemingly discovered a bug in iOS 18 with .toolBar with placement:. keyboard)
Feedback: FB15205988
Xcode Version: 16.0 (16A242d)
iOS Version: 18.0 (22A3351)
I'd appreciate help to see if I'm missing something here.
What's happening?
When using .toolBar with (placement: .keyboard), within a NavigationSplitView detail:, encompassed in a TabView, the .toolBar view does not appear above the keyboard.
Within the code, the usage of .toolBar is within ShakeDetail.swift.
When commenting out the TabView within ShakeTabView.swift, or running on iOS 17.5, the .toolbar appears.
Would greatly appreciate help if someone knows a workaround, or a misunderstanding here of course!
Code
Shake.swift
import Foundation
import SwiftUI
struct Shake: Equatable, Identifiable, Hashable {
var name: String
let id = UUID()
static var example = Shake(name: "Banana")
static var many: [Shake] {
return [
Shake(name: "Apple"),
Shake(name: "Banana"),
Shake(name: "Cherry"),
Shake(name: "Berry"),
]
}
}
ShakeDetail.swift
import SwiftUI
struct ShakeDetail: View {
@State var shake: Shake = Shake(name: "")
var body: some View {
List {
TextField("dsf", text: $shake.name, prompt: Text("Enter your favorite shake"))
}
.scrollDismissesKeyboard(.interactively)
.toolbar {
ToolbarItem(placement: .keyboard) {
HStack(alignment: .center) {
Text(shake.name)
.font(.title3)
.foregroundColor(.red)
}
}
}
.toolbarColorScheme(.dark, for: .navigationBar)
.toolbarBackground(
Color.purple,
for: .navigationBar
)
.toolbarBackground(.visible, for: .navigationBar)
}
}
#Preview {
ShakeDetail()
}
ShakeListView.swift
struct ShakeListView: View {
@Binding var shakes: [Shake]
@Binding var selectedShake: Shake?
var body: some View {
List(selection: $selectedShake) {
ForEach(shakes) { shake in
NavigationLink(value: shake) {
Text(shake.name)
.font(.system(.title2, design: .rounded))
.foregroundStyle(.primary)
}
}
}
.navigationTitle("Shakes")
}
}
#Preview {
@Previewable @State var shakes: [Shake] = Shake.many
@Previewable @State var selectedShake: Shake?
ZStack {
ShakeListView(shakes: $shakes, selectedShake: $selectedShake)
}
}
ShakeSplitView.swift
import SwiftUI
import OSLog
public struct ShakeSplitView: View {
@State var selectedShake: Shake?
@State var shakes = Shake.many
@State private var columnVisibility = NavigationSplitViewVisibility.doubleColumn
public init(isShowingFavorites: Bool = false, columnVisibility: SwiftUI.NavigationSplitViewVisibility = NavigationSplitViewVisibility.doubleColumn) {
self.columnVisibility = columnVisibility
}
public var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
ShakeListView(shakes: $shakes, selectedShake: $selectedShake)
} detail: {
if let selectedShake {
// Add shake detail
ShakeDetail(shake: selectedShake)
} else {
Label("Please select a shake", systemImage: "arrow.backward.circle")
.foregroundColor(.purple)
.font(.system(.title2, design: .rounded))
}
}
.navigationSplitViewStyle(.balanced)
}
}
struct FormulaSplitView_Previews: PreviewProvider {
static var previews: some View {
ShakeSplitView()
}
}
ShakeTabView.swift
import SwiftUI
struct ShakeTabView: View {
var body: some View {
/* TabView breaks the ToolbarItem(placement: .keyboard) */
TabView {
ShakeSplitView()
.tabItem {
Image(systemName: "carrot.fill")
Text("Shakes")
}
}
}
}
#Preview {
ShakeTabView()
}
Why is there inconstancy of appearing the keyboard tool bar Item with tab view?
Try to go to second tab and focus the field. Sometimes it does not appear (in my more complex project it does not appear >90% times).
import SwiftUI
struct MainTabView: View {
var body: some View {
TabView {
FirstTabView()
.tabItem { Label("Tab 1", systemImage: "house") }
SecondTabView()
.tabItem { Label("Tab 2", systemImage: "star") }
}
}
}
struct FirstTabView: View {
@State private var text = ""
var body: some View {
NavigationStack {
VStack {
TextField("Enter something 1", text: $text)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Button("Done") { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) }
}
}
}
}
}
struct SecondTabView: View {
@State private var text = ""
var body: some View {
NavigationStack {
VStack {
TextField("Enter something 2", text: $text)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Button("Done") { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) }
}
}
}
}
}
#Preview {
MainTabView()
}
I have implemented a sample video editing timeline using SwiftUI and am facing issues. So I am breaking up the problem in chunks and posting issue each as a separate question. In the code below, I have a simple timeline using an HStack comprising of a left spacer, right spacer(represented as simple black color) and a trimmer UI in the middle. The trimmer resizes as the left and right handles are dragged. The left and right spacers also adjust in width as the trimmer handles are dragged.
Problem: I want to keep the background thumbnails (implemented currently as simple Rectangles filled in different colors) in the trimmer stationary as the trimmer resizes. Currently they move along as the trimmer resizes as seen in the gif below. How do I fix it?
import SwiftUI
struct SampleTimeline: View {
let viewWidth:CGFloat = 340 //Width of HStack container for Timeline
@State var frameWidth:CGFloat = 280 //Width of trimmer
var minWidth: CGFloat {
2*chevronWidth + 10
} //min Width of trimmer
@State private var leftViewWidth:CGFloat = 20
@State private var rightViewWidth:CGFloat = 20
var chevronWidth:CGFloat {
return 24
}
var body: some View {
HStack(spacing:0) {
Color.black
.frame(width: leftViewWidth)
.frame(height: 70)
HStack(spacing: 0) {
Image(systemName: "chevron.compact.left")
.frame(width: chevronWidth, height: 70)
.background(Color.blue)
.gesture(
DragGesture(minimumDistance: 0)
.onChanged({ value in
leftViewWidth = max(leftViewWidth + value.translation.width, 0)
if leftViewWidth > viewWidth - minWidth - rightViewWidth {
leftViewWidth = viewWidth - minWidth - rightViewWidth
}
frameWidth = max(viewWidth - leftViewWidth - rightViewWidth, minWidth)
})
.onEnded { value in
}
)
Spacer()
Image(systemName: "chevron.compact.right")
.frame(width: chevronWidth, height: 70)
.background(Color.blue)
.gesture(
DragGesture(minimumDistance: 0)
.onChanged({ value in
rightViewWidth = max(rightViewWidth - value.translation.width, 0)
if rightViewWidth > viewWidth - minWidth - leftViewWidth {
rightViewWidth = viewWidth - minWidth - leftViewWidth
}
frameWidth = max(viewWidth - leftViewWidth - rightViewWidth, minWidth)
})
.onEnded { value in
}
)
}
.foregroundColor(.black)
.font(.title3.weight(.semibold))
.background {
HStack(spacing:0) {
Rectangle().fill(Color.red)
.frame(width: 70, height: 60)
Rectangle().fill(Color.cyan)
.frame(width: 70, height: 60)
Rectangle().fill(Color.orange)
.frame(width: 70, height: 60)
Rectangle().fill(Color.brown)
.frame(width: 70, height: 60)
Rectangle().fill(Color.purple)
.frame(width: 70, height: 60)
}
}
.frame(width: frameWidth)
.clipped()
Color.black
.frame(width: rightViewWidth)
.frame(height: 70)
}
.frame(width: viewWidth, alignment: .leading)
}
}
#Preview {
SampleTimeline()
}
Hello!
After upgrading to Xcode 16 & Swift 6 & iOS 18 I starting receiveing strange crashes.
Happens randomly in different view and pointing to onGeometryChange action block. I added DispatchQueue.main.async { in hopes it will help but it didn't.
HStack {
...
}
.onGeometryChange(for: CGSize.self, of: \.size) { value in
DispatchQueue.main.async {
self.width = value.width
self.height = value.height
}
}
As far as I understand, onGeometryChange is defined as nonisolated and Swift 6 enforce thread checking for the closures, SwiftUI views are always run on the main thread. Does it mean we can not use onGeometryChange safely in swiftui?
BUG IN CLIENT OF LIBDISPATCH: Assertion failed: Block was expected to execute on queue [com.apple.main-thread (0x1eacdce40)]
Crashed: com.apple.SwiftUI.AsyncRenderer
0 libdispatch.dylib 0x64d8 _dispatch_assert_queue_fail + 120
1 libdispatch.dylib 0x6460 _dispatch_assert_queue_fail + 194
2 libswift_Concurrency.dylib 0x62b58 <redacted> + 284
3 Grit 0x3a57cc specialized implicit closure #1 in closure #1 in PurchaseModalOld.body.getter + 4377696204 (<compiler-generated>:4377696204)
4 SwiftUI 0x5841e0 <redacted> + 60
5 SwiftUI 0x5837f8 <redacted> + 20
6 SwiftUI 0x586b5c <redacted> + 84
7 SwiftUICore 0x68846c <redacted> + 48
8 SwiftUICore 0x686dd4 <redacted> + 16
9 SwiftUICore 0x6ecc74 <redacted> + 160
10 SwiftUICore 0x686224 <redacted> + 872
11 SwiftUICore 0x685e24 $s14AttributeGraph12StatefulRuleP7SwiftUIE15withObservation2doqd__qd__yKXE_tKlF + 72
12 SwiftUI 0x95450 <redacted> + 1392
13 SwiftUI 0x7e438 <redacted> + 32
14 AttributeGraph 0x952c AG::Graph::UpdateStack::update() + 540
15 AttributeGraph 0x90f0 AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 424
16 AttributeGraph 0x8cc4 AG::Subgraph::update(unsigned int) + 848
17 SwiftUICore 0x9eda58 <redacted> + 348
18 SwiftUICore 0x9edf70 <redacted> + 36
19 AttributeGraph 0x148c0 AGGraphWithMainThreadHandler + 60
20 SwiftUICore 0x9e7834 $s7SwiftUI9ViewGraphC18updateOutputsAsync2atAA11DisplayListV4list_AG7VersionV7versiontSgAA4TimeV_tF + 560
21 SwiftUICore 0x9e0fc0 $s7SwiftUI16ViewRendererHostPAAE11renderAsync8interval15targetTimestampAA4TimeVSgSd_AItF + 524
22 SwiftUI 0xecfdfc <redacted> + 220
23 SwiftUI 0x55c84 <redacted> + 312
24 SwiftUI 0x55b20 <redacted> + 60
25 QuartzCore 0xc7078 <redacted> + 48
26 QuartzCore 0xc52b4 <redacted> + 884
27 QuartzCore 0xc5cb4 <redacted> + 456
28 CoreFoundation 0x555dc <redacted> + 176
29 CoreFoundation 0x55518 <redacted> + 60
30 CoreFoundation 0x55438 <redacted> + 524
31 CoreFoundation 0x54284 <redacted> + 2248
32 CoreFoundation 0x535b8 CFRunLoopRunSpecific + 572
33 Foundation 0xb6f00 <redacted> + 212
34 Foundation 0xb6dd4 <redacted> + 64
35 SwiftUI 0x38bc80 <redacted> + 792
36 SwiftUI 0x1395d0 <redacted> + 72
37 Foundation 0xc8058 <redacted> + 724
38 libsystem_pthread.dylib 0x637c _pthread_start + 136
39 libsystem_pthread.dylib 0x1494 thread_start + 8
Hello,
I've upgraded both of my Apple TVs to tvOS 18. Since then, my app developed with SwiftUI has become almost unusable due to severe lag, particularly when scrolling in a LazyVStack. On the A1625 (Apple TV HD), the lag can last up to 20 seconds, while on the A2843 (Apple TV 4K, 3rd generation, Wi-Fi + Ethernet), it’s about one second.
I can consistently reproduce the issue with this minimal example:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ScrollView {
LazyVStack {
ForEach(0..<1000) { nb in
Button("Item \(nb)") {}
}
}
}
}
}
}
Using Instruments, I found that the hang is related to this call:
389.00 ms 71,4 % 6.00 ms +[_UIFocusRegionEvaluator __regionsByEvaluatingOcclusionsForBaseRegions:occludingRegions:baseRegionsCanOccludeEachOther:inSnapshot:]
Unfortunately, I can't attach the Instruments trace directly here, but you can download it from this link: https://drive.google.com/file/d/1sEIwXhr7_ajjRHZevCIW6jNOlPjaeU6L/view?usp=sharing
Important notes:
The same screen, when written in UIKit, runs smoothly on both devices.
After performing a factory reset on the older device, the performance issue disappeared. However, as you can imagine, I’m already receiving complaints from users who are understandably unwilling to reset their devices.
Does anyone know of a workaround until this is addressed by Apple?
It looks like iOS 18 app changed the way document-based SwiftUI apps function in a way that breaks our app.
Previously, a ReferenceFileDocument would run its init(configuration:) function before any SwiftUI views would load. Now, it runs it after SwiftUI views load and their onAppear modifiers run.
Because we use a reference-type data model, our views reference a different object than the one loaded from our document's content. Much of our app's functionality is broken, and file saving doesn't work (because the data model writing to disk isn't connected to the views)
I filed a bug report, but this seems like a wild change that should affect more than just us. It wasn't happening earlier in the iOS betas. It feels like it only got added in the last beta, but I'm not sure.
Has anyone else run into this, or have any guidance for how best to deal with this?
My problem: I tap in one of the TextFields defined below and try to type. After typing a single character, the cursor disappears from the TextField and I need to tap in the field again to enter the next character.
I have the following code:
@Observable
final class Species {
. . .
public var list: [String]
. . .
}
struct SpeciesCapture: View {
@State private var species = Species()
@State var trainingList: [String] = []
var body: some View {
NavigationStack {
VStack(alignment: .leading) {
HStack {
Text("some text")
Spacer()
Button("Add") {
trainingList.append("")
}
}
List {
ForEach($trainingList, id: \.self) { $animal in
TextField("Animal", text: $animal)
.textCase(.lowercase)
}
}
}
.onAppear {
trainingList = species.list
. . .
}
. . . // etc.
}
}
}
It appears that I am continually losing focus. How do I fix this problem?
Xcode 16.0 targeting iOS 18. The behavior appears in both Preview and the Simulator. (Haven't tried it on a physical device).
I have an app that plays sound files stored locally. I'm using a single SwiftUI view with a MPVolumeView so the user can control system volume from the player in my app. When I'm playing the sound file on the iPhone, my volume slider operates as expected. When I AirPlay to my AppleTV, the volume slider still works to control the volume, but when I hit play in my app, the volume snaps to a different value, but actual sound volume doesn't change. Control still works. Flipping to control center, I see a volume mismatch between system volume and the MPVolumeView.
Here's the code that I use to put the slider in my app.
struct VolumeSlider: UIViewRepresentable {
func makeUIView(context: Context) -> MPVolumeView {
let vv = MPVolumeView(frame: .zero)
vv.showsVolumeSlider = true
vv.setVolumeThumbImage(UIImage() ,for: UIControl.State.normal)
return vv
}
func updateUIView(_ uiView: MPVolumeView, context: Context) {
// No need to update the view in this case
}
}
I'm using AVFoundation and AVAudioPlayer to playback the sound file. I'm using MediaPlayer to tell MPNowPlayingInfoCenter the track info and AlbumArt. Audio control via control center works perfectly. Does the same if I target iOS 16 or 17.
Is this a bug with the MPVolumeView or the way I added it to the app?
Hey all,
I am facing a new issue on iOS 18 with ScenePhase and .onChange modifier.
Here's roughly the code:
.onChange(of: scenePhase, initial: true) { old, new in
if new == .active {
doStuff()
}
}
on iOS 17 this was working as expected and triggered when eg. ap was brough from background or user navigated back to view
on ios18 though this code gets triggered constatnly in my case when I eg. navigate to another screen on top of the one with that .onChange. after navigation happens, the onChange is being triggered continuosly and does not stop which causes doStuff() to be called multiple times
I am developing an app that supports iOS 15 and later.
Up until iOS 17, the behavior of onDrag and onDrop was as follows:
The item is moved by holding it and dragging it to the onDrop area.
When the item is dropped in the onDrop area, the logic is executed, and simultaneously, the item disappears immediately.
However, in iOS 18 the item remains for about 0.5 to 1.0 seconds before disappearing, even though there is no logic in the onDrop.
Is this the expected behavior, or is it a bug?"
Please...
Failed to build module 'Charts'; this SDK is not supported by the compiler (the SDK is built with 'Apple Swift version 6.0 effective-5.10 (swiftlang-6.0.0.7.41 clang-1600.0.24.1)', while this compiler is 'Apple Swift version 6.0 effective-5.10 (swiftlang-6.0.0.9.11 clang-1600.0.26.2)'). Please select a toolchain which matches the SDK.
ANY WORKAROUNDS?
SwiftUI [[stichable]] metal shader & CIFilter written in metal extern"C" can't work at the same time
In my project, I used two metal shaders in two ways.
One is link to SwiftUI's modifier .colorEffect(ShaderLibrary.myShader()), which metal shader marked as [[stichable]].
Another one is a custom CIFilter, which kernel been written in external "C" closure.
Because custom CIFilter must add build rules so Xcode can compile it, so I added -fcikernel to Metal Compiler and -cikernel to Metal Linker from Build Settings, just like Apple's document told me that.
But the result is weird, if I add rules, custom CIFilter works, [[stichable]] shader doesn't work. if I delete rules, and comment out code of CIFilter(for avoiding warning), [[stichable]] shader works, but now I can't use my custom CIFilter.
Actually, once these two shaders works well in my project, but when I updated Xcode from 15 to 16, it became weird, the 2 shaders can't exist at same time. Even though I go back to Xcode 15, I can't save them.
I have no idea, please help, thank you.
XCode 16 / iOS 18 on iPhone 14 Pro
Hi, I'm trying to personalize the Detect animal poses in Vision example (WWDC 23).
Detect animal poses in Vision
After some tests I saw that the landmarks and connection drawings work only if I do not ignore the safe area, if I ignore it (removing the toggle) or use the app on the iPad the drawings are no longer applied correctly.
In the example GeometryReader is used to detect the size of the view:
...
ZStack {
GeometryReader { geo in
AnimalSkeletonView(animalJoint: animalJoint, size: geo.size)
}
}.frame(maxWidth: .infinity)
...
struct AnimalSkeletonView: View {
// Get the animal joint locations.
@StateObject var animalJoint = AnimalPoseDetector()
var size: CGSize
var body: some View {
DisplayView(animalJoint: animalJoint)
if animalJoint.animalBodyParts.isEmpty == false {
// Draw the skeleton of the animal.
// Iterate over all recognized points and connect the joints.
ZStack {
ZStack {
// left head
if let nose = animalJoint.animalBodyParts[.nose] {
if let leftEye = animalJoint.animalBodyParts[.leftEye] {
Line(points: [nose.location, leftEye.location], size: size)
.stroke(lineWidth: 5.0)
.fill(Color.orange)
}
}
...
}
}
}
}
}
// Create a transform that converts the pose's normalized point.
struct Line: Shape {
var points: [CGPoint]
var size: CGSize
func path(in rect: CGRect) -> Path {
let pointTransform: CGAffineTransform =
.identity
.translatedBy(x: 0.0, y: -1.0)
.concatenating(.identity.scaledBy(x: 1.0, y: -1.0))
.concatenating(.identity.scaledBy(x: size.width, y: size.height))
var path = Path()
path.move(to: points[0])
for point in points {
path.addLine(to: point)
}
return path.applying(pointTransform)
}
}
Looking online I saw that it was recommended to change the property cameraView.previewLayer.videoGravity
from:
cameraView.previewLayer.videoGravity = .resizeAspectFill
to:
cameraView.previewLayer.videoGravity = .resizeAspect
but it doesn't work for me.
Could you help me understand where I'm wrong?
Thanks!
I am trying to build a video editing timeline using SwiftUI which consists of a series of trimmers (sample code for trimmer below). I plan to embed multiple of these trimmers in an HStack to make an editing timeline (HStack in turn will be embedded in a ScrollView). What I want to achieve is that if I trim end of any of these trimmers by dragging it's left/right edge, the other trimmers on timeline should move left/right to fill the gap. I understand as the view shrinks/expands during trimming, there might be a need for spacers on the edges of HStack whose widths need to be adjusted while trimming is ongoing.
Right now the code I have for the trimmer uses a fixed frameWidth of the view, so the view occupies full space even if the trimming ends move. It's not clear how to modify my code below to achieve what I want. This was pretty much possible to do in UIKit by the way.
import SwiftUI
struct SimpleTrimmer: View {
@State var frameWidth:CGFloat = 300
let minWidth: CGFloat = 30
@State private var leftOffset: CGFloat = 0
@State private var rightOffset: CGFloat = 0
@GestureState private var leftDragOffset: CGFloat = 0
@GestureState private var rightDragOffset: CGFloat = 0
private var leftAdjustment: CGFloat {
// NSLog("Left offset \(leftOffset + leftDragOffset)")
var adjustment = max(0, leftOffset + leftDragOffset)
if frameWidth - rightOffset - adjustment - 60 < minWidth {
adjustment = frameWidth - rightOffset - minWidth - 60.0
}
return adjustment
}
private var rightAdjustment: CGFloat {
var adjustment = max(0, rightOffset - rightDragOffset)
if frameWidth - adjustment - leftOffset - 60 < minWidth {
adjustment = frameWidth - leftOffset - 60 - minWidth
}
return adjustment
}
var body: some View {
HStack(spacing: 10) {
Image(systemName: "chevron.compact.left")
.frame(width: 30, height: 70)
.background(Color.blue)
.offset(x: leftAdjustment)
.gesture(
DragGesture(minimumDistance: 0)
.updating($leftDragOffset) { value, state, trans in
state = value.translation.width
}
.onEnded { value in
var maxLeftOffset = max(0, leftOffset + value.translation.width)
if frameWidth - rightAdjustment - maxLeftOffset - 60 < minWidth {
maxLeftOffset = frameWidth - rightAdjustment - minWidth - 60
}
leftOffset = maxLeftOffset
}
)
Spacer()
Image(systemName: "chevron.compact.right")
.frame(width: 30, height: 70)
.background(Color.blue)
.offset(x: -rightAdjustment)
.gesture(
DragGesture(minimumDistance: 0)
.updating($rightDragOffset) { value, state, trans in
state = value.translation.width
}
.onEnded { value in
var minRightOffset = max(0, rightOffset - value.translation.width)
if minRightOffset < leftAdjustment - 60 - minWidth {
minRightOffset = leftAdjustment - 60 - minWidth
}
rightOffset = minRightOffset
}
)
}
.foregroundColor(.black)
.font(.title3.weight(.semibold))
.padding(.horizontal, 7)
.padding(.vertical, 3)
.background {
RoundedRectangle(cornerRadius: 7)
.fill(.yellow)
.padding(.leading, leftAdjustment)
.padding(.trailing, rightAdjustment)
}
.frame(width: frameWidth)
}
}
#Preview {
SimpleTrimmer()
}
It seems that after adding a lock screen widget in iOS 18, changing the widget settings doesn't work properly. The first setting change is applied, but after that, adjusting the settings has no effect. This issue appears to be present in other apps like Gmail as well, which suggests it might be an iOS 18 bug. Is there a solution to this problem?