Opening a Sheet with buttons generated with a ForEach Loop
I have a view where a list of buttons is generated using a ForEach loop, the data is a list of email addresses for a given contact. The number of email addresses are variable. On pressing an email, I want to open a sheet showing a email view and pass the email address selected to sheet. I followed the answer to this question here that showed how to do sheets with a ForEach button loop, but I ran into a strange issue, when I add the .sheet call to my code, it makes the ForEach loop buttons all become button, and clicking on it opens the sheet, but always passes the last email address in the list to the sheet, am I missing something or is this a bug in swiftUI?
Edit: Based on feedback from Yrb (Thanks for the feedback BTW) I have edited it my code so its modular enough that you can run it without any editing
import SwiftUI
import UIKit
import MessageUI
import CoreLocation
struct TestEmailAddress { // --> We also have a Email Address struct as they can have labels and we want to display them
var label: String
var email: String
}
extension Int: Identifiable {
public var id: Int {self}
}
struct MailView: UIViewControllerRepresentable {
@Binding var isShowing: Bool
@Binding var result: Result<MFMailComposeResult, Error>?
var recipients: [String]
var messageBody = ""
class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
@Binding var isShowing: Bool
@Binding var result: Result<MFMailComposeResult, Error>?
init(isShowing: Binding<Bool>,
result: Binding<Result<MFMailComposeResult, Error>?>) {
_isShowing = isShowing
_result = result
}
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult,
error: Error?) {
defer {
isShowing = false
}
guard error == nil else {
self.result = .failure(error!)
return
}
self.result = .success(result)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(isShowing: $isShowing,
result: $result)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MailView>) -> MFMailComposeViewController {
let vc = MFMailComposeViewController()
vc.setToRecipients(recipients)
vc.setMessageBody(messageBody, isHTML: true)
vc.mailComposeDelegate = context.coordinator
return vc
}
func updateUIViewController(_ uiViewController: MFMailComposeViewController,
context: UIViewControllerRepresentableContext<MailView>) {
}
}
struct RolodexMailViewTest: View {
@State var testEmails: [TestEmailAddress]
//Alert Stuff
@State private var showAlert = false
//Mail Stuff
@State private var result: Result<MFMailComposeResult, Error>? = nil
@State private var isShowingMailView = false
@State private var selectedEmail: Int? = nil
var body: some View {
Section() {
ForEach(0 ..< self.testEmails.count) { email in // --> here, we display all the numbers we got
if !MFMailComposeViewController.canSendMail() {
Button(action: { self.showAlert = true
self.selectedEmail = email
}) {
VStack(alignment: .leading, spacing: 5) {
Text(self.testEmails[email].label.isEmpty ? "Email" : self.testEmails[email].label)
.font(.system(.subheadline))
.foregroundColor(.secondary)
Text(self.testEmails[email].email)
}
}
}
else {
Button(action: { self.isShowingMailView = true
self.selectedEmail = email }) {
VStack(alignment: .leading, spacing: 5) {
Text(self.testEmails[email].label.isEmpty ? "Email" : self.testEmails[email].label)
.font(.system(.subheadline))
.foregroundColor(.secondary)
Text(self.testEmails[email].email)
}
}
}
}
}
.sheet(item: self.$selectedEmail) { selectedEmail in
MailView(isShowing: self.$isShowingMailView, result: self.$result, recipients: [self.testEmails[selectedEmail].email], messageBody: "Hi \("John Q Test"),\r\n")
}
.alert(isPresented: $showAlert) { ()
return Alert(title: Text("Unable to Send Mail"), message: Text("Please Setup Your Mail App"), dismissButton: .default(Text("Ok")))
}
}
}
let testEmailArray: [TestEmailAddress] = [TestEmailAddress(label: "Work", email: "johnqtest@work.com"), TestEmailAddress(label: "Home", email: "johnqtest@home.com")]
struct TestUIView_Previews: PreviewProvider {
static var previews: some View {
Form() {
RolodexMailViewTest(testEmails: testEmailArray)
}
}
}
When the .sheet is commented in the buttons looks like this: View When .sheet is commented out
However as soon as you comment it out, it becomes one button like this: View When .sheet is included
from Recent Questions - Stack Overflow https://ift.tt/3j9LtjZ
https://ift.tt/eA8V8J
Comments
Post a Comment