UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Why is this sheet closing when I'm not telling it to?

Forums > SwiftUI

The code has several things going on so I'm trying to shorten it a bit here to what I hope is the relevant parts. I have core data set up with an entity "Category" to hold a single "name" attribute which is a String.

That view starts with:

@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Category.name, ascending: true)],
    animation: .default
)
private var labels: FetchedResults<Category>

@State private var isShowingLabels = false

In the third section of my List, I have:

Section {
    Button("Edit Labels") {
        isShowingLabels.toggle()
    }

    .sheet(isPresented: $isShowingLabels) {
        LabelView().environment(\.managedObjectContext, viewContext)
    }
}

In the LabelView, I am displaying a list in the same way. The view starts with:

@Environment(\.managedObjectContext) private var viewContext
@Environment(\.presentationMode) var presentationMode

@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Category.name, ascending: true)],
    animation: .default
)
private var labels: FetchedResults<Category>

@State private var newLabelName = ""

At the top of my list I have a section where I have created a way to enter a new category label into my list:

Section {
    HStack {
        TextField("New Label", text: $newLabelName)
        Button(action: {
            addItem()
        }) {
            Image(systemName: "plus.circle.fill")
                .imageScale(.large)
                .foregroundColor(.accentColor)
        }
        .buttonStyle(BorderlessButtonStyle())
        .disabled(newLabelName == "")
    }
}

And the addItem function is:

private func addItem() {
    withAnimation {
        let newLabel = Category(context: viewContext)
        newLabel.name = newLabelName

        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        newLabelName = ""
    }
}

In the second section with the labels displayed, I also have .onDelete(perform: deleteItems) which is using this function:

private func deleteItems(offsets: IndexSet) {
    withAnimation {
        offsets.map { labels[$0] }.forEach(viewContext.delete)

        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
}

There is nothing in my button or in the addItem function to close the sheet. And yet, when a new item is added to core data the sheet disappears:

https://www.youtube.com/watch?v=B7vJlCXX_CA

So one might think, well, maybe as it is updating the list in the background, something is triggering it to close the foreground sheet. But... when an item is deleted from the list in the sheet which also triggers a save... the list in the sheet and in the background both update and the sheet does NOT close.

https://www.youtube.com/watch?v=IdDHwUyrd8Q

The only thing that should be closing this sheet is if the user taps on the close button in the toolbar or swipes the sheet down... so I'm a bit confused what is going on. Is there any way to stop the sheet from dismissing itself when a new item is added?

2      

This is very odd. If I manually close the onscreen keyboard after entering the new text but before hitting the + button... and then tap on the + button... then the item is added and the sheet remains open. So it seems to be some issue with it closing the keyboard when the item is saved that is causing it to close the sheet?

2      

It might because of @Environment(\.presentationMode) var presentationMode. I assume that you are using this for the "Close" button.

Try? add to LabelView instead of the presentationMode

@Binding var isShowingLabels: Bool

then in the "Close" button

isShowingLabels = false

then in your first view

.sheet(isPresented: $isShowingLabels) {
    LabelView(isShowingLabels: $isShowingLabels)
      .environment(\.managedObjectContext, viewContext)
}

This should bypass when the keyboard closes.

2      

Thanks @NigelGee. Yes, your assumption on the Close button for my sheet was correct. I just tried your idea... commented out the @Environment(.\presentationMode), added in your suggestion of using an @Binding (and passed isShowingLabels: .constant(true) in the preview to make it stop complaining there)... and, unfortunately, still the same behavior when I run it on my iPod Touch and iPad Pro. The keyboard automatically slides down when I tap the + button... I don't have any code trying to dismiss the keyboard at all. It is closing on its own... and it is apparently taking the sheet with it when it does. (unless I manually dismiss the keyboard first and then tap on the + button).

The view calling on the sheet is linked from another view using a Navigation Link. So that view is also using @Environment(.presentationMode) to .dismiss() when the user clicks on certain items. I don't think I would have to follow this back replacing all the @Environment(.\presentationMode) with @Binding instead would I?

2      

Actually, to paint a bigger picture... it starts with a view that brings up another view as a full screen cover (main view bringing up an add/edit form). That view then uses a navigation link to slide over to another view (add/edit view bringing up a custom "picker" view to make selections - including "None" and a button to customize the "picker" list), and that customize button to bring up a sheet to add/edit/delete items in the custom picker list. So there is a bit of using @Environment(.\presentationMode) going on there as I'm using that in the full screen cover with buttons to close (or save - and then close) to return to my main view. I'm using it in my navigation link in a form to have it automatically slide back to the previous view when a selection is made in my custom picker. And then finally, I was using it again in the sheet that I bring up to edit the "picker" list to close the sheet (but now it is using the @Binding instead). And it all works as expected with both @Environment(.\presentationMode) and now @Binding for that final view... EXCEPT for the issue with the keyboard automatically closing itself AND that final add/edit/delete sheet with it.

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.