Swift UI Detail Remove

How can I push a detailpage and remove all previous navigationlinks in swiftUI?

I solved it by adding an id to the NavigationView, and then setting this to another id in the viewmodel when it should reset.

Like this:

struct MyView: View {
@StateObject var viewModel = ViewModel()

var body: some View {
NavigationView {
// ...
}
.id(viewModel.id)
}
}

In the viewmodel:

class ViewModel: ObservableObject {
@Published var id = UUID().uuidString

func reset() {
id = UUID().uuidString
}
}

This resets the NavigationView as Swift thinks it's a different view because the id changed.

How to stop showing Detail view when item in Master view deleted?

Try the following (not tested, just idea - on delete there is not new selection/navigation in stack so details view is not refreshed, so we can try to force that refresh explicitly):

struct ContentView: View {
@State private var items = ["Item 1", "Item 2", "Item 3"]

@State private var refreshID = UUID() // << this !!

var body: some View {
NavigationView {
List {
ForEach(items, id: \.self) { item in
NavigationLink(destination: DetailView(item: item)) {
Text(item)
}
}
.onDelete(perform: delete)
}
Text("Please select an item.")
}
.id(refreshID) // << here !!
}

func delete(at offsets: IndexSet) {
items.remove(atOffsets: offsets)
refreshID = UUID() // << here !!
}
}

How to delete an item of a list from another view in SwiftUI?

You need to pass item in DetailView, like by-index

NavigationLink(destination: DetailView(index: index)) {   // << here !!
Text(self.viewModel.items[index].title)
}

so, it is possible to remove by index

struct DetailView: View {
@EnvironmentObject var viewModel: ViewModel
let index: Int

var body: some View {
Button("Delete") {
self.remove(at: IndexSet(integer: self.index)) // << here !!
}
}

func remove(at offsets: IndexSet) {
withAnimation {
viewModel.items.remove(atOffsets: offsets)
}
}
}

How do I cleanly delete elements from a Sidebar List in SwiftUI on macOS

The reason this does not work is because your Destinationview to the right does not get updated when the State in your sidebar changes. Move the logic to the viewmodel and create a designated View that holds the UI for the Details.

  1. move the selected var to your viewmodel:

    class ModelData: ObservableObject {
    @Published var myLinks = [
    URL(string: "https://google.com")!,
    URL(string: "https://apple.com")!,
    URL(string: "https://amazon.com")!]
    @Published var selected: URL?
    }
  2. create a new View for destination:

    struct DestinationView: View{
    @EnvironmentObject var modelData: ModelData
    var body: some View{

    if let selected = modelData.selected{
    Text("Viewing detailed data for: \(selected)")
    }else{
    Text("Choose a link")
    }
    }
    }
  3. change navigationview destination:

    NavigationLink(destination: DestinationView() ) {
    Text(url.absoluteString)
    }
  4. change your ondelete modifier:

     if let selection = modelData.selected {
    modelData.myLinks.remove(at: modelData.myLinks.firstIndex(of: selection)!)
    }
    modelData.selected = nil

How to display default detail in NavigationSplitView after deleting an item — on iPad

Bind your selection with List using @State property and also you don't require to add NavigationLink, NavigationSplitView automatically show detail for the selected list item.

Now if you remove the selected item from the list then after deleting it from the array simply set nil to the selection binding of List.

struct ContentView: View {
@State var items = ["item 1", "item 2", "item 3", "item 4"]
@State private var selection: String?

var body: some View {
NavigationSplitView {
List(selection: $selection) {
ForEach(items, id: \.self) { item in
Text(item)
}
.onDelete(perform: { offsets in
items.remove(atOffsets: offsets)
guard selection != nil, !items.contains(selection!) else { return }
selection = nil
})
}
} detail: {
if let selectedItem = selection {
Text(selectedItem)
}
else {
Text("Select item")
}
}
}
}

Suggest you to check the Apple documentation of NavigationSplitView for more details.

Remove NavigationView close icon SwiftUI

As mentioned in the comments by @Nirav D, this button is used to toggle the sidebar visibility.

iOS 16 & above

In iOS 16, Apple gave Navigation a big refresh:

  1. Introducing NavigationStack(which is probably what you want), it is used to present a view allowing the user to navigate using NavigationLink as you would on an iPhone.
  2. Introducing NavigationSplitView(which is what you’re seing in the simulator right now), it is used to present a menu (sidebar) that can present detail views. You can have up to 3 columns.
  3. Deprecating NavigationView, from now on you have to use the above containers as NavigationView will be obsoleted in a future iOS release.

iOS 15 & below

In versions earlier than 16, you have to use NavigationView. NavigationView accepts navigationViewStyle, the default style on iPhone is StackNavigationViewStyle where the content is presented in one column. However, on iPad in order to maximise the use of screen estate, SwiftUI sets the default style to ColumnNavigationViewStyle that presents the content in columns (Master -> Detail…).

  • If you mean to use a single column: you must use either NavigationStack or NaigationView with .navigationViewStyle(.stack);

  • If you have to use multiple columns & still hide the button: use .navigationBarHidden(true) on the sidebar view, or .toolbar(.hidden, for: .navigationBar) for iOS 16+.

For more info, check: Navigation & The SwiftUI cookbook for navigation



Related Topics



Leave a reply



Submit