There is a button in the TabBar, this button should open the camera
"Button(action: {...}, label: { ..."
The camera code is written in "CameraView" and "CameraModel" :
struct CameraView: View {
#StateObject var camera = CameraModel()
var body: some View {
ZStack{
// Camera preview...
CameraPreview(camera: camera)
.ignoresSafeArea(.all, edges: .all)
VStack{
if camera.isTaken{
HStack {
Spacer()
Button(action: {}, label: {
Image(systemName: "arrow.triangle.2.circlepath.camera")
.foregroundColor(.black)
.padding()
.background(Color.white)
.clipShape(Circle())
})
.padding(.trailing,10)
}
}
Spacer()
HStack{
if camera.isTaken{
Button(action: {}, label: {
Text("Save")
.foregroundColor(.black)
.fontWeight(.semibold)
.padding(.vertical,10)
.padding(.horizontal,20)
.background(Color.white)
.clipShape(Capsule())
})
.padding(.leading)
Spacer()
}
else{
Button(action: {camera.isTaken.toggle()}, label: {
ZStack{
Circle()
.fill(Color.white)
.frame(width: 65, height: 65)
Circle()
.stroke(Color.white,lineWidth: 2)
.frame(width: 75, height: 75)
}
})
}
}
.frame(height: 75)
}
}
.onAppear(perform: {
camera.Check()
})
}
}
class CameraModel: ObservableObject{
#Published var isTaken = false
#Published var session = AVCaptureSession()
#Published var alert = false
// since were going to read pic data....
#Published var output = AVCapturePhotoOutput()
// preview....
#Published var preview : AVCaptureVideoPreviewLayer!
func Check(){
// first checking camerahas got permission...
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized:
setUp()
return
// Setting Up Session
case .notDetermined:
// retusting for permission....
AVCaptureDevice.requestAccess(for: .video) { (status) in
if status{
self.setUp()
}
}
case .denied:
self.alert.toggle()
return
default:
return
}
}
func setUp(){
// setting up camera...
do{
// setting configs...
self.session.beginConfiguration()
// change for your own...
let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
let input = try AVCaptureDeviceInput(device: device!)
// checking and adding to session...
if self.session.canAddInput(input){
self.session.addInput(input)
}
// same for output....
if self.session.canAddOutput(self.output){
self.session.addOutput(self.output)
}
self.session.commitConfiguration()
}
catch{
print(error.localizedDescription)
}
}
}
// setting view for preview...
struct CameraPreview: UIViewRepresentable {
#ObservedObject var camera : CameraModel
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: UIScreen.main.bounds)
camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
camera.preview.frame = view.frame
// Your Own Properties...
camera.preview.videoGravity = .resizeAspectFill
view.layer.addSublayer(camera.preview)
// starting session
camera.session.startRunning()
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
How to call the camera on click Button in TabBar "Button(action: {}, label: {
)"?
This is just an example of how I did it in the past (after all permissions etc... have been done).
Use your code to do the same.
struct ContentView: View {
#State var image: UIImage?
#State private var showCamera = false
var body: some View {
VStack {
Button(action: { self.showCamera.toggle() }) {
Image(systemName: "camera.circle").resizable().frame(width: 100, height: 100)
}
if image != nil {
Image(uiImage: image!).resizable().frame(width: 200, height: 200)
}
} // this is where it happens
.sheet(isPresented: $showCamera, onDismiss: {self.showCamera = false}) {
CameraViewController(photo: $image)
}
}
}
struct CameraViewController: UIViewControllerRepresentable {
#Environment(\.presentationMode) var presentationMode
#Binding var photo: UIImage?
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
}
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraViewController>) -> UIImagePickerController {
let vc = UIImagePickerController()
vc.sourceType = .camera
vc.delegate = context.coordinator
return vc
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate, AVCapturePhotoCaptureDelegate {
var parent: CameraViewController
var captureSession: AVCaptureSession!
var capturePhotoOutput: AVCapturePhotoOutput!
var theCamera: AVCaptureDevice!
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
let photoQualityPrioritizationMode = AVCapturePhotoOutput.QualityPrioritization.speed
init(_ imagePickerController: CameraViewController) {
self.parent = imagePickerController
}
// called when a picture has been taken
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info:[UIImagePickerController.InfoKey : Any]) {
guard let image = info[.originalImage] as? UIImage else {
print("No image found")
return
}
parent.photo = image // <--- the photo image
parent.presentationMode.wrappedValue.dismiss()
}
}
}
Related
As said in the title, I would like to show the location of my users on a map in my app. I would like something like Snapshat map :
Snapshat Map Picture
I used SwiftUI and Firebase.
Here is what I have done so far :
import SwiftUI
import Firebase
import CoreLocation
import MapKit
struct mapTimelineView: View {
#StateObject private var locationViewModel = LocationViewModel.shared
#State private var showNewPostView = false
#ObservedObject var viewModel = TimelineViewModel()
#ObservedObject var authViewModel = AuthViewModel()
#ObservedObject var obs = observer()
var body: some View {
ZStack (alignment: .bottomTrailing) {
// Map(coordinateRegion: $locationViewModel.region, showsUserLocation: true)
// .accentColor(Color("accentColor"))
// .edgesIgnoringSafeArea(.all)
mapView(geopoints: self.obs.data["data"] as! [String : GeoPoint]) <--- /!\ the problem occurs here /!\
Button {
showNewPostView.toggle()
} label: {
Image(systemName: "plus")
.resizable()
.renderingMode(.template)
.frame(width: 30, height: 30)
.font(.system(size: 30, weight: .bold, design: .default))
.padding()
}
.background(Color("accentColor"))
.foregroundColor(Color("backgroundColor"))
.clipShape(Circle())
.padding()
.shadow(radius: 20)
.fullScreenCover(isPresented: $showNewPostView) {
uploadPostView()
}
}
.navigationBarTitleDisplayMode(.inline)
.navigationTitle("home")
.background(Color("backgroundColor"))
}
}
struct mapTimelineView_Previews: PreviewProvider {
static var previews: some View {
mapTimelineView()
}
}
struct mapView: UIViewRepresentable {
#ObservedObject var authViewModel = AuthViewModel()
var geopoints : [String: GeoPoint]
func makeCoordinator() -> Coordinator {
return mapView.Coordinator(parent1: self)
}
let map = MKMapView()
let manager = CLLocationManager()
func makeUIView(context: Context) -> MKMapView {
manager.delegate = context.coordinator
manager.startUpdatingLocation()
map.showsUserLocation = true
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 48.856614, longitude: 2.3522219), span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
map.region = region
return map
}
func updateUIView(_ uiView: MKMapView, context: Context) {
for i in geopoints {
let point = MKPointAnnotation()
point.coordinate = CLLocationCoordinate2D(latitude: i.value.latitude, longitude: i.value.longitude)
point.title = i.key
uiView.removeAnnotations(uiView.annotations)
uiView.addAnnotation(point)
}
}
class Coordinator: NSObject, CLLocationManagerDelegate {
#ObservedObject var authViewModel = AuthViewModel()
var parent: mapView
init(parent1: mapView) {
parent = parent1
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let uid = self.authViewModel.userSession?.uid else { return }
let last = locations.last
Firestore.firestore().collection("locations").document("coordinate").setData(["updates" : [uid : GeoPoint(latitude: (last?.coordinate.latitude)!, longitude: (last?.coordinate.longitude)!)]],merge: true) { (err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
print("success")
}
}
}
}
class observer : ObservableObject{
#Published var data = [String : Any]()
init() {
let db = Firestore.firestore()
db.collection("locations").document("coordinate").addSnapshotListener { (snap, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
let updates = snap?.get("updates") as! [String : GeoPoint]
self.data["data"] = updates
}
}
}
It shows a map and the user location.
But my problem is that my app crash because there is "nil" on this line :
mapView(geopoints: self.obs.data["data"] as! [String : GeoPoint])
I got this error message :
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
And, I don't understand this issue because I do have data in my database :
So, if anyone has a solution, I would like to know it.
I'm having trouble figuring out how to smoothly navigate from my SignInView() to my FirstView(). I have my FirstView() inside of a Navigation Stack, but the transition between the views is very abrupt and devoid of the transition that you normally get with the use of a NavigationLink. How can I get the transition to work?
Much appreciated!
Here is the relevant code...
struct ContentView: View {
#EnvironmentObject var viewModel: AppViewModel
var body: some View {
VStack{
NavigationView {
if viewModel.signedIn {
FirstView()
.transition(.slide)
} else {
//.onAppear method is used for keyboard management (See Misc Functions...)
SignInView()
.onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
.navigationBarHidden(true)
}
}
.onAppear {
viewModel.listen()
}
}
}
}
class AppViewModel: ObservableObject {
private var db = Firestore.firestore()
#Published var userInfo: User?
#Published var signedIn: Bool = false
var handle: AuthStateDidChangeListenerHandle?
let authRef = Auth.auth()
var authHandle : AuthStateDidChangeListenerHandle?
var rootInfoCollection : CollectionReference!
var userIdRef = ""
func fetchUserData(){
db.collection("Users").document("\(userIdRef)").getDocument { document, error in
// Check for error
if error == nil {
// Check that this document exists
if document != nil && document!.exists {
self.userInfo = document.map { (documentSnapshot) -> User in
let data = documentSnapshot.data()
let uid = data?["uid"] as? UUID ?? UUID()
let company = data?["company"] as? String ?? ""
let name = data?["name"] as? String ?? ""
let admin = data?["admin"] as? Bool ?? false
let photo = data?["photo"] as? String ?? ""
return User(uid: uid, company: company, name: name, admin: admin, photo: photo)
}
withAnimation {
self.signedIn = true
}
}
}
}
}
func listen(){
handle = authRef.addStateDidChangeListener({ auth, user in
print(user?.email ?? "No User Found")
if let user = auth.currentUser {
self.userIdRef = user.uid
self.rootInfoCollection = Firestore.firestore().collection("/Users/")
DispatchQueue.main.async {
self.fetchUserData()
}
} else {
self.signedIn = false
}
})
}
func signIn(email: String, password: String){
authRef.signIn(withEmail: email, password: password) { result, error in
guard result != nil, error == nil else {
return
}
}
}
}
struct SignInView: View {
#EnvironmentObject var viewModel: AppViewModel
#State private var username : String = ""
#State private var password : String = ""
#State private var shouldShowLoginAlert: Bool = false
#State var selectedImageArray : [Image] = []
var disableLoginButton : Bool {
return self.username.isEmpty || self.password.isEmpty
}
var body: some View {
VStack{
Image(uiImage: #imageLiteral(resourceName: "awText"))
.resizable()
.frame(width: 180, height: 100)
.padding(.bottom, 50)
TextField("Email", text: $username)
.padding(.leading)
.disableAutocorrection(true)
.autocapitalization(.none)
Rectangle().fill(Color.gray.opacity(0.25)).frame(height: 1, alignment: .center).padding(.bottom)
.padding(.bottom)
.onChange(of: self.username, perform: { value in
if value.count > 10 {
self.username = String(value.prefix(20)) //Max 10 Characters for Username.
}
})
SecureField("Password", text: $password)
.padding(.leading)
.disableAutocorrection(true)
.autocapitalization(.none)
Rectangle().fill(Color.gray.opacity(0.25)).frame(height: 1, alignment: .center)
.onChange(of: self.username, perform: { value in
if value.count > 10 {
self.username = String(value.prefix(10)) //Max 10 Characters for Password.
}
})
//SignIn Button
Button(action: {
viewModel.signIn(email: username, password: password)
}, label: {
Text("Sign In")
.disabled(disableLoginButton)
.frame(width: 300, height: 50)
.background(Color.green)
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
.padding()
})
}
Replacing the default NavigationView behavior with your own animations isn't necessarily totally straightforward. I'll lay out one possibility, but another would be to use a real NavigationView transition, but just hide the back button once you're on FirstView.
To do the transition yourself, you'll need one root element to NavigationView, an if clause, a transition(.slide) and withAnimation. Here's a simplified version of your code showing just these elements:
class AppViewModel: ObservableObject {
#Published var signedIn = false
}
struct FirstView : View {
var body: some View {
Text("Signed in")
}
}
struct ContentView: View {
#StateObject var viewModel = AppViewModel()
var body: some View {
NavigationView {
VStack {
if viewModel.signedIn {
FirstView()
.transition(.slide)
} else {
Button("Sign me in") {
withAnimation {
viewModel.signedIn = true
}
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.navigationBarHidden(true)
}
}
}
A have an app made in SwiftUI, with Parse used for DB.
I'm some parts of the app i've integrated some cloud functions that send notifications (for example: when someone send's you a message, you will receive a push notification triggered by that cloud function).
In the past days i'm struggling and searching for how to open a specific view when you press the Notification to open the app.
I've found some solutions, but could not make them work.
This is the code that i have so far :
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
//Parse Intialization
...
//notifications
registerForPushNotifications()
//Notification Badge
UIApplication.shared.applicationIconBadgeNumber = 0
// start notification while app is in Foreground
UNUserNotificationCenter.current().delegate = self
return true
}
// This function will be called right after user tap on the notification
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("app opened from PushNotification tap")
UIApplication.shared.applicationIconBadgeNumber = 0
completionHandler()
}
}
#main
struct MyApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView(currentTab: Tab.home)
}
}
}
The app prints "app opened from PushNotification tap", but if I put a variable in AppDelegate and I listen for changes in ContentView with .onReceive or .onChange for that variable, nothing is hapenning
struct ContentView: View {
#ObservedObject var appState = AppState()
#State var currentTab : Tab
#State var noReloadAddItemView = false
var body: some View {
TabView(selection: $appState.currentTab) {
NavigationView {
HomeView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
}
.tabItem {
if appState.currentTab == .home {
Image(systemName: "house.fill")
} else {
Image(systemName: "house")
}
Text(LocalizedStringKey("HomeTabMenu"))
}.tag(Tab.home)
NavigationView {
SearchView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
}
.tabItem {
if appState.currentTab == .search {
Image(systemName: "magnifyingglass.circle.fill")
} else {
Image(systemName: "magnifyingglass")
}
Text(LocalizedStringKey("SearchTabMenu"))
}.tag(Tab.search)
NavigationView {
AddItemView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
}
.tabItem {
if appState.currentTab == .add {
Image(systemName: "plus.circle.fill")
} else {
Image(systemName: "plus.circle")
}
Text(LocalizedStringKey("SellTabMenu"))
}.tag(Tab.add)
NavigationView {
ShoppingCartFavoritesView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
}
.tabItem {
if appState.currentTab == .favorites {
Image(systemName: "cart.fill")
} else {
Image(systemName: "cart")
}
Text(LocalizedStringKey("CartTabMenu"))
}.tag(Tab.favorites)
NavigationView {
ProfileView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
}
.tabItem {
if appState.currentTab == .profile {
Image(systemName: "person.fill")
} else {
Image(systemName: "person")
}
Text(LocalizedStringKey("ProfileTabMenu"))
}.tag(Tab.profile)
}
.accentColor(Color("ColorMainDark"))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(currentTab: Tab.home)
}
}
class AppState: ObservableObject {
#Published var currentTab : Tab = .home
}
enum Tab {
case home, search, add, favorites, profile
}
You need some sort of shared state that you can modify that SwiftUI knows to react to. An ObservableObject is perfect for this:
class AppState: ObservableObject {
static let shared = AppState()
#Published var pageToNavigationTo : String?
}
Then, to listen to it and respond to it, you can do a couple different methods in your main view.
Option 1 -- NavigationLink binding based on the value of the ObservedObject:
struct ContentView : View {
#ObservedObject var appState = AppState.shared //<-- note this
#State var navigate = false
var pushNavigationBinding : Binding<Bool> {
.init { () -> Bool in
appState.pageToNavigationTo != nil
} set: { (newValue) in
if !newValue { appState.pageToNavigationTo = nil }
}
}
var body: some View {
NavigationView {
Text("My content")
.overlay(NavigationLink(destination: Dest(message: appState.pageToNavigationTo ?? ""),
isActive: pushNavigationBinding) {
EmptyView()
})
}
}
}
struct Dest : View {
var message : String
var body: some View {
Text("\(message)")
}
}
Or, you could use onReceive:
struct ContentView : View {
#ObservedObject var appState = AppState.shared
#State var navigate = false
var body: some View {
NavigationView {
VStack {
if navigate {
NavigationLink(destination: Text("Test"), isActive: $navigate ) {
EmptyView()
}
}
Text("My content")
.onReceive(appState.$pageToNavigationTo) { (nav) in
if nav != nil { navigate = true }
}
}
}
}
}
I'll leave the implementation details of your specific NavigationView, NavigationLink, TabView, etc to you, but this should get you started.
Finally, a fully-functional minimal example that mocks a notification and shows how the navigation view:
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
print("Dispatch")
AppState.shared.pageToNavigationTo = "test"
}
return true
}
}
class AppState: ObservableObject {
static let shared = AppState()
#Published var pageToNavigationTo : String?
}
#main
struct MultiWindowApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView : View {
#ObservedObject var appState = AppState.shared
#State var navigate = false
var pushNavigationBinding : Binding<Bool> {
.init { () -> Bool in
appState.pageToNavigationTo != nil
} set: { (newValue) in
if !newValue { appState.pageToNavigationTo = nil }
}
}
var body: some View {
NavigationView {
Text("My content")
.overlay(NavigationLink(destination: Dest(message: appState.pageToNavigationTo ?? ""),
isActive: pushNavigationBinding) {
EmptyView()
})
}
}
}
struct Dest : View {
var message : String
var body: some View {
Text("\(message)")
}
}
Trying to init CustomButton(title: "Add", icon: .add, status: .enable)
My code is below. I do get the title but enums are not working.
Plus recieving error
Cannot convert value of type 'Image' to expected argument type 'String'
at Image(icon)
import SwiftUI
struct CustomButton: View {
var title: String
var icon: String
var status: Color
var body: some View {
Button(action: {
}) {
Text(title)
.foregroundColor(.white)
.background(Color(.green))
.font(Font.custom("SFCompactDisplay", size: 14))
Image(icon)
.renderingMode(.original)
.foregroundColor(.white)
}
}
enum Icon {
case add
case edit
var image: Image {
switch self {
case .add:
return Image("Add")
case .edit:
return Image("Edit")
}
}
}
enum Status {
case enable
case disable
var color : Color {
switch self {
case .enable:
return Color(.green)
case .disable:
return Color(.gray)
}
}
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon.image
self.status = status.color
}
}
I assume you wanted this
struct CustomButton: View {
var title: String
var icon: Icon
var status: Color
var body: some View {
Button(action: {
}) {
Text(title)
.foregroundColor(.white)
.background(Color(.green))
.font(Font.custom("SFCompactDisplay", size: 14))
icon.image
.renderingMode(.original)
.foregroundColor(.white)
}
}
enum Icon {
case add
case edit
var image: Image {
switch self {
case .add:
return Image("Add")
case .edit:
return Image("Edit")
}
}
}
enum Status {
case enable
case disable
var color : Color {
switch self {
case .enable:
return Color(.green)
case .disable:
return Color(.gray)
}
}
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon
self.status = status.color
}
}
I figured it out. It works now.
struct CustomButton: View {
let title: String
let icon : String
let status: Color
#State private var buttonDisabled = true
var body: some View {
Button(action: {
}) {
ZStack(alignment:.bottom) {
HStack {
Text(title)
.foregroundColor(.white)
.font(Font.custom("SFCompactDisplay-Bold", size: 20))
.bold()
.fontWeight(.bold)
.background(status)
Image(icon)
.renderingMode(.original)
.foregroundColor(.white)
.background(Color(.white))
}
.frame(width: 335, height: 20, alignment: .center)
.padding()
.background(status)
}
.cornerRadius(10)
}
}
enum Icon {
case add
case edit
case none
var image: String {
switch self {
case .add:
return "Add"
case .edit:
return "Edit"
case .none:
return "empty"
}
}
}
enum Status {
case enable
case disable
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon.image
if status == .enable {
self.status = Color(#colorLiteral(red: 0, green: 0.6588235294, blue: 0.5254901961, alpha: 1))
} else {
self.status = Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
}
}
}
struct CustomButton_Previews: PreviewProvider {
static var previews: some View {
CustomButton(title: "Odeme Yontemi Ekle", icon: .none, status: .enable)
}
}
i have a bug, if i click on button before the animation before the card flip back. i think for me the best it would be to disable the button for 2 sec, but i made some research and didnt find anything!
struct CardBack: View {
var body: some View {
Image("back_card")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 250)
}
}
struct ContentView: View {
#State var flipped = false
#State private var cardsFront = ["bigCard1", "bigCard2", "bigCard3", "bigCard4", "bigCard5" ]
#State private var cardBack = "back_card"
#State private var disablled = true
var body: some View {
VStack {
Spacer()
ZStack {
Image(flipped ? self.cardsFront.randomElement()! : self.cardBack)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 250)
.rotation3DEffect(Angle(degrees: flipped ? 180 : 0 ), axis: (x: 0, y: 1, z: 0))
}
Spacer()
HStack {
Button(action: {
withAnimation(.spring()) {
self.flipped.toggle()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
withAnimation(.spring()) {
self.flipped.toggle()
}
}
}) {
Image("circle")
.renderingMode(.original)
}
Button(action: {
}) {
Image("plus")
.renderingMode(.original)
}
iOS 13, Swift 5
You can set the button as disabled initially and then enable it using the same sort of logic I used here.
import SwiftUI
struct ContentView: View {
#State var changeColor = false
var body: some View {
TextView(changeColor: $changeColor)
}
}
struct TextView: View {
#Binding var changeColor: Bool
var body: some View {
Text("Hello World")
.foregroundColor(changeColor ? Color.black: Color.red)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.changeColor.toggle()
}
}
}
}
You are almost there, you just need to use the .appear tag in your code to do this.