Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

swiftui - Display filename in next View too

I have a code that makes a http Request, gets an array with filenames from that, displays them each with an image and the filename below. Everything works fine. Now I made each image a button that opens a detail page. That works but at the top it should say the matching filename from the page before. But I am not able to hand over the filename (name) from ContentView4 to the next page (ts).

The language is SwiftUi

Could you please help me?

Thanks

Nikias

Here is my code:

import SwiftUI

struct ContentView4: View {
    
    @State var showingDetail = false
    
    @State var username: String = "."
    @State var password: String = "."
    
    @State private var name = String("Nikias2")
    
    @State private var t = String()
    @State private var x = -1


    @State var dateien = ["word.png"]
    
    var body: some View {
        ScrollView(.vertical) {

        ZStack{
            VStack {
                ForEach(0 ..< dateien.count, id: .self) {
                    Button(action: {
                        print("button pressed")
                        x = x + 1
                        t = dateien[x]
                        self.showingDetail.toggle()
                    }) {
                    Image("datei")
                    }
                        .scaledToFit()
                        .padding(0)
                    Text(self.dateien[$0])
                    Text(t)
                        .foregroundColor(.white)
            }
            }
        }
        .sheet(isPresented:
                $showingDetail) {
            ts(name: t)
                }
        .onAppear { //# This `onAppear` is added to `ZStack{...}`
            doHttpRequest()
        }

    }
    }
    
 func doHttpRequest() {
            let myUrl = URL(string: "http://192.168.1.180/int.php")! //# Trailing semicolon is not needed
            var request = URLRequest(url: myUrl)
            request.httpMethod = "POST"// Compose a query string
            let postString = "Name=($username)&Passwort=($password)"
            
            request.httpBody = postString.data(using: .utf8)
            
            let task = URLSession.shared.dataTask(with: request) {
                (data, response, error) in
                
                //# Use if-let when you want to use the unwrapped value
                if let error = error {
                    print("error=(error)")
                    return
                }
                
                //# Use guard-let when nil has no meaning and want to exit on nil
                guard let response = response else {
                    print("Unexpected nil response")
                    return
                }
                // You can print out response object
                print("response = (response)")
                
                //Let's convert response sent from a server side script to a NSDictionary object:
                do {
                    //# Use guard-let when nil has no meaning and want to exit on nil
                    guard let data = data else {
                        print("Unexpected nil data")
                        return
                    }
                    //#1 `mutableContainer` has no meaning in Swift
                    //#2 Use Swift Dictionary type instead of `NSDictionary`
                    let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
                    
                    if let parseJSON = json {
                        // Now we can access value of First Name by its key
                        //# Use if-let when you want to use the unwrapped value
                        if let firstNameValue = parseJSON["Name"] as? String {
                            print("firstNameValue: (firstNameValue)")
                            let dateien =  firstNameValue.components(separatedBy: ",")
                            print(dateien)
                            
                            self.dateien = dateien
                        }
                    }
                } catch {
                    print(error)
                }
            }
            task.resume()
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView4()
    }
}


struct ts: View {
    @State var hin = false
    @State var um = false
    @State var datname: String = ""
    var name: String
    
    var body: some View {
        NavigationView {
        VStack {
            Text(name)
                .font(.system(size: 60))
                .foregroundColor(.black)
                .padding(50)
            Button(action: {
                self.hin.toggle()
            }) {
            Text("+")
                .font(.headline)
                .foregroundColor(.white)
                .padding()
                .frame(width: 220, height: 60)
                .background(Color.yellow)
                .cornerRadius(35.0)
            }
            .padding()
            if hin {
                HStack {
                Text("Datei ausw?hlen")
                    .font(.headline)
                    .frame(width: 150, height: 70)
                    .background(Color.yellow)
                    .cornerRadius(20.0)
                    .animation(Animation.default)
                Text("Datei hochladen")
                    .font(.headline)
                    .frame(width: 150, height: 70)
                    .background(Color.yellow)
                    .cornerRadius(20.0)
                    .animation(Animation.default)
            }
            }
            Text("Datei herunterladen")
                .font(.headline)
                .foregroundColor(.white)
                .padding()
                .frame(width: 220, height: 60)
                .background(Color.blue)
                .cornerRadius(35.0)
        Button(action: {
                self.um.toggle()
            }) {
            Text("Datei umbenennen")
                .font(.headline)
                .foregroundColor(.white)
                .padding()
                .frame(width: 220, height: 60)
                .background(Color.green)
                .cornerRadius(35.0)
        }
                .padding()
                if um {
                    HStack {
                        TextField(name, text: $datname)
                        .font(.headline)
                        .frame(width: 150, height: 70)
                        .cornerRadius(20.0)
                        .animation(Animation.default)
                    Text("Datei umbenennen")
                        .font(.headline)
                        .frame(width: 150, height: 70)
                        .background(Color.green)
                        .cornerRadius(20.0)
                        .animation(Animation.default)
                }
                }
            Text("Datei l?schen")
                .font(.headline)
                .foregroundColor(.white)
                .padding()
                .frame(width: 220, height: 60)
                .background(Color.red)
                .cornerRadius(35.0)
            }
        }
    }
}


question from:https://stackoverflow.com/questions/65927496/display-filename-in-next-view-too

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I believe your issue is a result of using @State variables to store all of the attributes. @State variables are not consistent and get refreshed in the background by SwiftUI depending on your views visibility.
The piece that you are missing is a view controller class stored in an @EnviornmentObject variable. This class gets Initiated in your main contentView and is used to keep track and alter of all your attributes.
Each ContentView should reference the single @EnviornmentObject and pull data from that class.

Another solution which may work would be to replace all your @State variables with @StateObject vars. @StateObject vars are basically @State vars but get initiated before the struct get loaded and the value is kept consistent regardless of the view state of the parent struct.

Here is a rough implementation of @EnvironmentObject within your project. Basically use the @EnvironmentObject to pass values to child views

ContentView4.swift

struct ContentView4: View {
    
@EnvironmentObject cv4Controller: ContentView4Controller

     var body: some View {
        ScrollView(.vertical) {

        ZStack{
            VStack {
                ForEach(0 ..< cv4Controller.dateien.count, id: .self) {
                    Button(action: {
                        print("button pressed")
                        x = x + 1
                        t = cv4Controller.dateien[x]
                        self.showingDetail.toggle()
                    }) {
                    Image("datei")
                    }
                        .scaledToFit()
                        .padding(0)
                    Text(self.dateien[$0])
                    Text(cv4Controller.t)
                        .foregroundColor(.white)
            }
            }
        }
        .sheet(isPresented:
                cv4Controller.$showingDetail) {
            ts(name: cv4Controller.t)
                }
        .onAppear { //# This `onAppear` is added to `ZStack{...}`
            cv4Controller.doHttpRequest()
        }

    }
}

ContentView4Controller.swift

class ContentView4Controller: ObservableObject {

        @Published var showingDetail = false
        
        @Published var username: String = "."
        @Published var password: String = "."
        
        @Published private var name = String("Nikias2")
        
        @Published private var t = String()
        @Published private var x = -1

    
        @Published private var t = String()
        @Published private var x = -1


        @Published var dateien = ["word.png"]

     func doHttpRequest() {
            let myUrl = URL(string: "http://192.168.1.180/int.php")! //# Trailing semicolon is not needed
            var request = URLRequest(url: myUrl)
            request.httpMethod = "POST"// Compose a query string
            let postString = "Name=($username)&Passwort=($password)"
            
            request.httpBody = postString.data(using: .utf8)
            
            let task = URLSession.shared.dataTask(with: request) {
                (data, response, error) in
                
                //# Use if-let when you want to use the unwrapped value
                if let error = error {
                    print("error=(error)")
                    return
                }
                
                //# Use guard-let when nil has no meaning and want to exit on nil
                guard let response = response else {
                    print("Unexpected nil response")
                    return
                }
                // You can print out response object
                print("response = (response)")
                
                //Let's convert response sent from a server side script to a NSDictionary object:
                do {
                    //# Use guard-let when nil has no meaning and want to exit on nil
                    guard let data = data else {
                        print("Unexpected nil data")
                        return
                    }
                    //#1 `mutableContainer` has no meaning in Swift
                    //#2 Use Swift Dictionary type instead of `NSDictionary`
                    let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
                    
                    if let parseJSON = json {
                        // Now we can access value of First Name by its key
                        //# Use if-let when you want to use the unwrapped value
                        if let firstNameValue = parseJSON["Name"] as? String {
                            print("firstNameValue: (firstNameValue)")
                            let dateien =  firstNameValue.components(separatedBy: ",")
                            print(dateien)
                            
                            self.dateien = dateien
                        }
                    }
                } catch {
                    print(error)
                }
            }
            task.resume()
    }

}

Example of main ContentView.swift

struct ContentView: View {

var cv4Controller: ContentView4Controller = ContentView4Controller()

var body: some view {
 
  // your main page output
  GeometryReader { geo in 
  
     // just a guess for what you have in your main contentView
     switch(page) {
        case .main:
           ContentView2()
        default:
           ContentView4()
           break
     }

  }.environmentObject(cv4Controller) // this will make cv4Controller available to all child view structs

}


}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...