I have a list view with items that can be selected to show a detail view of the item like this:
NavigationView {
List {
ForEach(items) { item in
NavigationLink(destination: DetailView(item: item)) {
DetailRow(item: item)
}
}
}
}
Obviously, all the detail views are created when the list view is created. I think this is problematic from a performance and memory usage view. I'd rather have one single detail view object and then set the item values for it when a particular item is selected.
But I can't figure out how to do this. Or is the above way really a good implementation?
SwiftUI makes sure things are efficient. There's no need to worry about that; at least not in this simple example. (Optimisations can be needed with advanced animations like is mentioned towards the end in this WWDC talk.)
SwiftUI code is a structural specification which is analysed & executed at run-time. So your assumption "all the detail views are created when the list view is created" is not true.
You can read about that here.
So, your code is perfectly fine and optimal.
Related
I'm starting to learn swiftUI and I have a strange problem,
I have created a simple list that displays perfectly in the preview... But not in the simulator.
Does anyone have an idea?
https://www.dropbox.com/s/eo1ldvdbgntzr8v/Enregistrement%20de%20l%E2%80%99%C3%A9cran%202021-06-04%20%C3%A0%2018.42.03.mov?dl=0
Project : https://github.com/maxupcreation/Dfi/tree/main/Dfi
to answer more correctly, you'd better show us yout whole source code.
it seems second view(maybe AddChallengeView.swift file)'s input cannot reflect to original view(=ContentView.swift)'s List. so there might be two problems
because you refer your "items" property from another view, you'd better check if you use ObservableObject protocol and #ObservedObject property wrapper properly.
at ForEach statement, you use nil coalescing, so check whether item value is nil
I'm working on an app that involves inputting the amount of cards players ended up with, and ordering them in a list. But if theres a 2 or 3 way tie, I want the user to be able to have a menu that lets them select the order of who had the highest card to lowest card, that way I can organize the list. How do I get the user to order them, like what kind of Alert/Popup lets me do that?
Edit: Basically I was asking how to make a picker that lets you arrange multiple items into a specific order but it seems the best thing to do is just to have a stack appear with buttons for each item, where you can click them and go from there to create your order. Hope this helps for anyone in a similar situation!
For that kind of user interaction where they are doing more than just tapping an option (in your case, you want them to order the various cards), I would create your own custom view rather than use an alert or action sheet or similar.
The way you implement will depend on how you want it to look. If you want the view to appear on top of your current view (a bit like an alert does) where it only takes up the space needed for the content) then you can embed in a zStack. If you want it to slide up from the bottom as almost the same size as the full screen then you can use a sheet (sometimes also referred to as a modal).
A little difficult to explain how they look visually - if you google image search “SwiftUI sheet” then you’ll see what I mean (if you aren’t already familiar with them)
ZStack
you put your current view in a ZStack then create a new view which goes in the ZStack after it but you wrap it in an if statement so it’s conditionally shown based on a Boolean being true.
E.g.
if gameTied { ChooseSortOrderView() }
then when your game finishes - if it’s a tie, you set your Boolean to true and up pops the new view.
You can pass in the tied cards, get the user to sort them via drag and drop, form, picker (whatever you want), submit it. Then set the bool back to false to make the view go away.
sheet
The other alternative instead of using a zstack would be sheet so you get a modal view appear. Similar approach but instead of the ZStack, you use a .sheet modifier.
I am following along with this SwiftUI Tutorial: https://developer.apple.com/tutorials/swiftui/handling-user-input
The concepts here are perfect for an app I want to create. I do however have one question.
Whilst this tutorial is great for showing the basics of using Environment Objects to update SwiftUI views (in this case, to add a star image to elements that have been favourited.), how might I go about saving these changes to last beyond the app's runtime.
Right now, I can favourite a bunch of Landmarks but if I quit and re-launch the app, those selections are lost. Is there a "SwiftUI friendly" way to store those favourite selections and have the main Landmark List view automatically draw the star images to mark previously chosen favourites when the app is launched cold? I'm guessing UserDefaults would be the way, but I don't know how well that will adapt to these funky Environment Objects.
Thank you.
EDIT:
I am now using UserDefaults to persist an array of "TeamProfile" objects which gets appended to whenever a team is marked as Favourite.
In my SwiftUI code, I am trying to add Star images to favourites with the following code. These TeamRow items are built into a List by the parent view.:
struct TeamRow: View {
var team: TeamProfile
var body: some View {
HStack {
Text(team.TeamName)
Spacer()
if team.isFavourite || teamsSelected.contains(team) {
Image(systemName: "star.fill")
.imageScale(.medium)
.foregroundColor(.yellow)
}
}
}
}
teamsSelected is the array that is being maintained by UserDefaults. It should add a star to TeamRow items from my persisted array (which is loaded on app launch and I can verify it's contents). However, the star is only drawn on the row if I make new favourite selections during the app session.
I can verify the contents of the data I am persisting with UserDefaults, so I don't know why SwiftUI is not responding by starring the correct elements when the app is launched.
I'm building a SwiftUI app for macOS, then I came with the following challenge.
Given a view hierarchy like:
Which basically shows a collection of elements in ElementListView. Then the FiltersView is used to search new elements to possibly add to the element list, the results of that search are shown in rows like FilterRow.
When a user clicks on FilterRow, that means I want to add a new element to the ElementListView, but I am not sure of How to propagate events between the two branches of the view hierarchy in SwiftUI?
If I were to implement this in pure AppKit, I would probably use the responder chain, but I guess it's not the SwiftUI way of doing it.
You can have a shared ObservableObject for filters and list views. As soon as ObservableObject changes SwiftUI updates views connected to it.
Unlike in UIKit, where a LongPressGesture is actually delayed, in SwiftUI it began as soon as you hover/pan/touch the view. So if you have a LongPressGesture/Action in a View within a List or a NavigationLink, it'll prevent scrolling the List, or triggering the NavigationLink action.
Anyone have any idea if it's possible to delay it with current API?