Ios14 Introducing Errors with @State Bindings

iOS14 introducing errors with @State bindings

It looks like in iOS 14 the sheet(isPresented:content:) is now created beforehand, so any changes made to selectedModel are ignored.

Try using sheet(item:content:) instead:

var body: some View {
List {
...
}
.sheet(item: self.$selectedModel) {
SpeakerDetailView(speaker: $0)
}
}

and dismiss the sheet using @Environment(\.presentationMode):

struct SpeakerDetailView: View {
@Environment(\.presentationMode) private var presentationMode
var speaker: Speaker

var body: some View {
Text("Speaker view")
.onTapGesture {
presentationMode.wrappedValue.dismiss()
}
}
}

Cant get my sheet to display the right information

In iOS 14 sheet(isPresented:content:) is now created beforehand and the view is not refreshed when the $businessSheetPresented changes.

Instead of .sheet(isPresented:content:)

.sheet(isPresented: $businessSheetPresented) {
if let pressedUser = pressedUser {
DisplayBusinessSheet(user: pressedUser)
}
}

you should use .sheet(item:content:)

.sheet(item: $pressedUser) { user in
DisplayBusinessSheet(user: pressedUser)
}

Note: with the above solution you don't really need businessSheetPresented unless it's used in some other place apart from triggering the sheet.

Displaying a Sheet from multiple options in swiftUI

Here is another approach for your problem which uses sheet(item:content:)

struct ContentView: View {
@State private var selectedSpeaker: Speaker?
@State private var selectedMicrophone: Microphone?
@State private var selectedAmp: Amplifier?
@State private var showSettingsSheet = false

var body: some View {
List {
settingsSection
microphonesSection
// more sections
}
}

var settingsSection: some View {
Button(action: {
self.showSettingsSheet = true
}) {
Text("Settings")
}
.sheet(isPresented: self.$showSettingsSheet) {
SettingsView()
}
}

@ViewBuilder
var microphonesSection: some View {
Button(action: {
self.selectedMicrophone = microphones[0]
}) {
Text("Mic 1")
}
Button(action: {
self.selectedMicrophone = microphones[1]
}) {
Text("Mic 2")
}
.sheet(item: self.$selectedMicrophone) {
MicDetailView(microphone: $0)
}
}
}

This way you also don't need enum ActiveSheet.


You can always use @Environment(\.presentationMode) to dismiss a sheet, no need to pass the variable to the sheet (as in SettingsView(showSheet: self.$showingSheet)):

struct SettingsView: View {
@Environment(\.presentationMode) private var presentationMode

var body: some View {
Text("SettingsView")
.onTapGesture {
presentationMode.wrappedValue.dismiss()
}
}
}

@State property value is not retain when called within the sheet(item:) method

I think you're getting caught by the fact that sheet(item:) only re-renders based on item -- not the encapsulating View's @State variables. As long as you explicitly pass isReseting through the item, it will work:


struct Item: Identifiable, Equatable {
var id = UUID()
var name:String
var active:Bool
}

struct ContentView: View {

var items:[Item] = [Item(name: "Oranges", active: true),
Item(name: "Apples", active: false),
Item(name: "Cookies", active: false) ]

struct SheetItem : Identifiable {
var item: Item
var isReseting: Bool

var id: UUID {
self.item.id
}
}

@State private var selectedItem: SheetItem?
@State private var isReseting: Bool?

var body: some View {
List{
ForEach(items){ item in
HStack{
Text(item.name)

Button(item.active ? "Reset": "Initiate"){
isReseting = true
selectedItem = SheetItem(item: item, isReseting: isReseting ?? false)
}
.padding()
.background(item.active ? Color.blue: Color.gray)
.foregroundColor(.white)
.cornerRadius(30)
.frame(width: 100, height: 65)
}
}
}
.sheet(item: $selectedItem) { item in
let _ = print("Value in sheet: \(item.isReseting)")

if item.isReseting == true {
Text("It's reseting!!!")
} else {
Text("It's NOT reseting")
}
}
}
}

A second way to accomplish this is explicitly pass a Binding (even though you don't need to mutate it in the sheet), since it will maintain its link to the @State variable:

struct Item: Identifiable{
var id = UUID()
var name:String
var active:Bool
}

struct ContentView: View {

var items:[Item] = [Item(name: "Oranges", active: true),
Item(name: "Apples", active: false),
Item(name: "Cookies", active: false) ]

@State private var selectedItem: Item?
@State private var isReseting: Bool?

var body: some View {
List{
ForEach(items){ item in
HStack{
Text(item.name)

Button(item.active ? "Reset": "Initiate"){
selectedItem = item
isReseting = true
let _ = print("Value after button tap: \(isReseting)")// output: Value after button tap: Optional(true)
}
.padding()
.background(item.active ? Color.blue: Color.gray)
.foregroundColor(.white)
.cornerRadius(30)
.frame(width: 100, height: 65)
}
}
}
.sheet(item: $selectedItem){ item in
// I'm expecting isReseting to be true here, but it's nil
SheetView(isReseting: $isReseting)
}
}
}

struct SheetView : View {
@Binding var isReseting : Bool?

var body: some View {
let _ = print("Value in sheet: \(isReseting)")// outputs: Value in sheet: nil

if isReseting == true {
Text("It's reseting!!!")
}else{
Text("It's NOT reseting")
}
}
}



Related Topics



Leave a reply



Submit