This is how it look in the app:
On the left there is a simple list created from ForEach
. When user tap any element on that list BottomSheet is presented with a Binded value for selected item. How can I get that value and update NSManagedObject in core data when user tap save button? Is there a simple and easy way to do this?
The same situation in code:
struct SettingsView: View {
@State var isTextInputPresented = false
@State var editingTextFieldValue = ""
private var onSave: ((String) -> Void)? = nil
var body: some View {
ZStack {
ScrollView {
ForEach(users, id: \.self) { user in //users are from @FetchRequest
HStack {
TextLabel(user.name, color: theme.secondTeamColor)
.padding(EdgeInsets(vertical: 10))
Spacer()
}
.onTapGesture {
editingTextFieldValue = user.name
isTextInputPresented = true
// cannot assign onSave handler here🤷🏼♂️
}
}
}
BottomSheetView(title: "Edit input", isShowing: $isTextInputPresented) {
TextInputView(text: $editingTextFieldValue, onSave: onSave)
}
}
}
}
import SwiftUI
struct TextInputView: View {
@Environment(Theme.self) private var theme
@Binding var text: String
@FocusState private var focus: Bool
var onSave: ((String) -> Void)?
var body: some View {
HStack(spacing: 20) {
TextField("", text: $text, prompt: Text("Placeholder").foregroundColor(.gray))
.padding(10)
.multilineTextAlignment(.center)
.font(.system(size: 24))
.foregroundStyle(theme.backgroundColor)
.tint(theme.backgroundColor.opacity(0.4))
.focused($focus)
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(theme.backgroundColor.opacity(0.5), lineWidth: 3)
)
Button {
onSave?(text)
} label: {
Image(systemName: "checkmark")
}
.font(.bold(withSize: 22))
.frame(width: 56, height: 56)
.background(theme.backgroundColor)
.foregroundStyle(theme.textColor)
.cornerRadius(10)
}
.padding(20)
.onAppear {
focus = true
}
}
}
You could try this approach declaring @State private var onSave: ((String) -> Void)? = nil
and using onSave
in the .onTapGesture
as shown in the example code:
struct SettingsView: View {
@State private var isTextInputPresented = false
@State private var editingTextFieldValue = ""
@State private var onSave: ((String) -> Void)? = nil // <--- here
// for my testing
let users = [User(name: "user-1"), User(name: "user-2")]
var body: some View {
ZStack {
ScrollView {
ForEach(users) { user in // users are from @FetchRequest
HStack {
Text(user.name)
Spacer()
}
.onTapGesture {
editingTextFieldValue = user.name
isTextInputPresented = true
onSave = { newName in
// save newName back to CoreData
print("----> saving: \(newName)")
}
}
}
}
// for my testing
.sheet(isPresented: $isTextInputPresented) {
TextField("Edit input", text: $editingTextFieldValue)
.onSubmit {
onSave?(editingTextFieldValue)
isTextInputPresented = false
}
}
// BottomSheetView(title: "Edit input", isShowing: $isTextInputPresented) {
// TextInputView(text: $editingTextFieldValue, onSave: onSave)
// }
}
}
}
EDIT-1
using the TextInputView
and a @Binding var onSave ...
struct SettingsView: View {
@State private var isTextInputPresented = false
@State private var editingTextFieldValue = ""
@State private var onSave: ((String) -> Void)? = nil // <--- here
// for my testing
let users = [User(name: "user-1"), User(name: "user-2")]
var body: some View {
ZStack {
ScrollView {
ForEach(users) { user in // users are from @FetchRequest
HStack {
Text(user.name)
Spacer()
}
.onTapGesture {
editingTextFieldValue = user.name
isTextInputPresented = true
onSave = { newName in
// save newName back to CoreData
print("----> saving: \(newName)")
}
}
}
}
// for testing using TextInputView
.sheet(isPresented: $isTextInputPresented) {
TextInputView(text: $editingTextFieldValue, onSave: $onSave) // <--- here
}
}
}
}
struct TextInputView: View {
@Environment(Theme.self) private var theme
@Binding var text: String
@FocusState private var focus: Bool
@Binding var onSave: ((String) -> Void)? // <--- here
var body: some View {
//...
}
}