I have code that makes my filter bar disappear when user has tapped on a product (a shirt or pair of trousers). This all takes place in the Marketplace tab.
I think the code will work once the bug is fixed however I cannot get rid of the buh about missing arguments.
The code for marketplace is:
#Binding var shirtData : Shirt!
#Binding var showDetailShirt: Bool
#Binding var trouserData : Trouser!
#Binding var showDetailTrouser: Bool
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 10){
if !showDetailShirt && !showDetailTrouser {
marketplaceFilterBar
}
if selectedMarketplaceFilter == .shirt {
MarketplaceShirtView()
}
if selectedMarketplaceFilter == .trouser {
MarketplaceTrouserView()
}
}
}
Here is code for the TabView
#StateObject var appModel: AppViewModel = .init()
#StateObject var sharedData: SharedDataModel = SharedDataModel()
#Binding var shirtData : Shirt!
#Binding var showDetailShirt: Bool
#Binding var trouserData : Trouser!
#Binding var showDetailTrouser: Bool
// Animation Namespace...
#Namespace var animation
// Hiding Tab Bar...
init(){
UITabBar.appearance().isHidden = true
}
var body: some View {
VStack(spacing: 0){
// Tab View...
TabView(selection: $appModel.currentTab) {
Marketplace(animation: _animation)
.environmentObject(sharedData)
.tag(Tab.Market)
.setUpTab()
Home()
.environmentObject(sharedData)
.tag(Tab.Home)
.setUpTab()
}
On the Marketplace line in the TabView I am getting the error:
Missing arguments for parameters 'shirtData', 'showDetailShirt', 'trouserData', 'showDetailTrouser' in call
UPDATED:
On my MarketplaceShirtView I have the following code:
#StateObject var MarketplaceModel = MarketplaceViewModel()
#State private var selectedMarketplaceFilter: MarketplaceFilterViewModel = .shirt
#Namespace var animation : Namespace.ID
#State var showDetailShirt = false
#State var selectedShirt : Shirt!
// Shared Data...
#EnvironmentObject var sharedData: SharedDataModel
When I use an if statement to determine whether to display the Detail view I get the error: Cannot convert value of type 'Binding<Shirt?>’ to expected argument type 'Binding'
Here is the code:
if selectedShirt != nil && showDetailShirt{
ShirtDetailView(shirtData: $selectedShirt, showDetailShirt: $showDetailShirt,animation: _animation)
}
According to the code you posted MarcetPlace should be initialized like this:
Marketplace(shirtData: $shirtData, showDetailShirt: $showDetailShirt, trouserData: $trouserData, showDetailTrouser: $showDetailTrouser)
Edit:
Well you got a custom initializer and properties without default values there so probably you have to initialize those too.
E.g.
init(shirtData: Binding<Shirt>, .....
Edit 2:
To be more precise, in your TabView:
// Hiding Tab Bar...
init(shirtData: Binding<Shirt?>, showDetailShirt: Binding<Bool>, trouserData: Binding<Trouser?>, showDetailTrouser: Binding<Bool>){
self._shirtData = shirtData
self._showDetailShirt = showDetailShirt
self._trouserData = trouserData
self._showDetailTrouser = showDetailTrouser
UITabBar.appearance().isHidden = true
}
I don´t think you need those implicit unwrappings so instead of #Binding var shirtData : Shirt! use #Binding var shirtData : Shirt and in the initializer init(shirtData: Binding<Shirt?>, would become init(shirtData: Binding<Shirt>,
Related
I'm new in Swift and I'm trying to do my project more object oriented.
Im making app for using DJI SDK, and I'm trying to change some things in view when some variable changes in composite class.
So I have:
Code in AppController :
#main
struct AppController: App {
#State var djiService = ProductCommunicationService()
var body: some Scene {
WindowGroup {
InfoFormView(djiService: $djiService, rcEngineConn: $rcEngineConn, bridgeStatus: $bridgeStatus, fpvMode: $fpvMode, libMode: $libMode)
}
}
And in ProductCommunicationService there is few variables and logic
class ProductCommunicationService: NSObject {
#Published var registered = false
#Published var connected = false
#Published var enableBridgeMode = false
#Published var bridgeAppIP = "0.0.0.0"
func registerWithSDK() {
.....
What I'm trying to do, is refresh view I have below when som variable in ProductCom.. class changes
struct InfoFormView: View {
#Binding var djiService : ProductCommunicationService
#Binding var rcEngineConn : Bool
#Binding var bridgeStatus : Bool
#Binding var fpvMode : Bool
#Binding var libMode : Bool
var body: some View {
HStack(alignment: .top){
VStack(alignment: .leading, spacing: 20) {
Text("CR Fly Beta").font(.title).bold()
Text("Connected to aircraft: " + (self.djiService.connected ? "Yes": "No")).font(.title)
Text("Connected to RC: " + (self.rcEngineConn ? "Yes": "No")).font(.title)
Text("Bridge Mode Status: " + (self.djiService.enableBridgeMode ? "On" : "Off")).font(.title)
HStack(){
if(self.djiService.connected){
Button("Lets FLY!"){
self.fpvMode = true
}.buttonStyle(.bordered).font(.title2)
Button("Photo Library"){
self.libMode = true
}.buttonStyle(.bordered).font(.title2)
}
}
Is there any way to refresh it when variable changes? I tried everything, also creating ProductComService with inserted variables(which didn't work because of #State)
So I figured it out.
I created a new object of data myObject with implementation of ObservableObject.
This object contained just variables with #Pubslished.
Then in appController I stored #ObservableObject myObject = myObject()
And bridged it to a view and productCommServise.
Don’t forget o #Published and #ObservableObject every where you initialize it
I am trying to call a detailed view of an item when an item is tapped. In this case, the item is a pair of trousers in the MarketplaceTrouserView. When I call TrouserDetailView, I get an error. This must be to do with initialising but I've repeatedly tried this and failed. What could be the solution?
MarketplaceTrouserView:
import SwiftUI
struct MarketplaceTrouserView: View {
#StateObject var MarketplaceModel = MarketplaceViewModel()
#State private var selectedMarketplaceFilter: MarketplaceFilterViewModel = .trouser
#State var showDetailTrouser = false
#State var selectedTrouser : Trouser!
#EnvironmentObject var sharedData: SharedDataModel
var body: some View {
var columns = Array(repeating: GridItem(.flexible()), count: 2)
ZStack{
VStack{
HStack {
Text("Find Trousers To Buy")
}
}
}
if MarketplaceModel.trousers.isEmpty{
ProgressView()
}
else{
ScrollView {
LazyVGrid(columns: Array(repeating: GridItem(.flexible(),spacing: 10), count: 2),spacing: 20){
ForEach(MarketplaceModel.filteredTrouser){trouser in
// Trouser items in grid view
TrouserView(trouserData: trouser)
.onTapGesture {
withAnimation {
selectedTrouser = trouser
showDetailTrouser.toggle()
}
}
}
}
}
}
}
if selectedTrouser != nil && showDetailTrouser{
TrouserDetailView(/*Here is the error asking for trouserData & showDetailTrouser*/)
}
}
}
}
TrouserDetailView:
import SwiftUI
import SDWebImageSwiftUI
struct TrouserDetailView: View {
#State var trouserData : Trouser
#State var showDetailTrouser: Bool
#EnvironmentObject var sharedData: SharedDataModel
#EnvironmentObject var marketplaceData: MarketplaceViewModel
var body: some View {
ScrollView {
VStack{
HStack {
Button(action: {
withAnimation(.easeOut){showDetailTrouser.toggle()}
}) {
Image(systemName: "arrow.backward.circle.fill")
}
Text(trouserData.trouser_name)
}
VStack {
WebImage(url: URL(string: trouserData.trouser_image))
}
}
}
}
Trouser Model:
import SwiftUI
import FirebaseFirestoreSwift
import Firebase
struct Trouser: Identifiable, Codable {
#DocumentID var id: String?
var trouser_name: String = ""
var trouser_image: String = ""
}
The error is when i call TrouserDetailView (as marked in the code)
After applying changes, my MainPage view has errors in the initialiser.
MainPage
struct MainPage: View {
#StateObject var appModel: AppViewModel = .init()
#StateObject var sharedData: SharedDataModel = SharedDataModel()
#State var shirtData : Shirt
#State var showDetailShirt: Bool
#State var trouserData : Trouser
#State var showDetailTrouser: Bool
#Namespace var animation
init () {
#State var shirtData = Shirt()
#State var showDetailShirt = false
#State var trouserData = Trouser()
#State var showDetailTrouser = false
UITabBar.appearance().isHidden = true
} //ERROR HERE: 'Return from initializer without initializing all stored properties'
var body: some View {
VStack {
TabView(selection: $appModel.currentTab) {
Marketplace()
.environmentObject(sharedData)
.tag(Tab.Market)
.setUpTab()
Home()
.environmentObject(sharedData)
.tag(Tab.Home)
.setUpTab()
}
By the logic of provided code, state is not needed for the first one and second should be replaced with binding, ie.
struct TrouserDetailView: View {
var trouserData : Trouser
#Binding var showDetailTrouser: Bool
// ...
and call
if selectedTrouser != nil && showDetailTrouser {
TrouserDetailView(trouserData: selectedTrouser,
showDetailTrouser: $showDetailTrouser)
}
#State var trouserData : Business
#State var showDetailTrouser: Bool
These variables you must initialize the value locally or switch to #Binding to bind the data with the parent variables.
I created view using Function and which i am calling from another view (AbcView), I want to perform normal #Binding with that, but not sure how to pass value and create #Binding in function.
In Below code I want to pass selectedPassengerId from AbcView to function topSheetClassViews and perform #Binding whenever value passengerIds in SelectedTitleView is updating so that I can get updated value in AbcView.
import SwiftUI
struct AbcView: View {
#StateObject var abcViewModel: AbcViewModel
#State private var selectedPassengerId: Int?
init(accessibiltyID: String, abcViewModel: AbcViewModel) {
self._abcViewModel = StateObject(wrappedValue: abcViewModel)
}
var body: some View {
VStack(spacing: 0) {
// Some Design
}
.overlay(
TopView((accessibilityID: accessibilityID, content: topSheetClassViews(abcViewModel: abcViewModel), selectedRowID: $selectedPassengerId, rowHeight: $rowHeight),, alignment: .top
)
)
}
}
func topSheetClassViews(abcViewModel: AbcViewModel) -> [AnyView] {
var views: [AnyView] = []
for passenger in 0..<abcViewModel.Passengers.count {
views.append(TopSheetPassengerInfoView(abcViewModel: abcViewModel, index: passenger).convertToAnyView())
}
return views
}
struct SelectedTitleView: View {
#ObservedObject var abcViewModel: AbcViewModel
var passengerIds: Int
var body: some View {
VStack(alignment: .trailing) {
Text("passengerIds \(passengerIds)") // here getting correct id which I want to pass to AbcView
Text(abcViewModel.passengerTitle(passengerId: passengerIds))
}
}
}
struct TopSheetPassengerInfoView: View {
#ObservedObject var abcViewModel: AbcViewModel
var index: Int
var body: some View {
VStack(alignment: .leading, spacing: 0) {
Text(abcViewModel.passengers[index].fullName ?? "")
SelectedTitleView(abcViewModel: abcViewModel, passengerIds: Int(abcViewModel.Passengers[index].passengerId ?? "") ?? 0)
}
}
}
Just put it through everywhere you need to pass it, like
here
func topSheetClassViews(abcViewModel: AbcViewModel, selection: Binding<Int?>) -> [AnyView] {
here
views.append(TopSheetPassengerInfoView(abcViewModel: abcViewModel, selectedID: selection, index: passenger).convertToAnyView())
here
struct TopSheetPassengerInfoView: View {
#ObservedObject var abcViewModel: AbcViewModel
#Binding var selectedID: Int?
and so on
I'm pretty new to SwiftUI (and Swift I haven't touch for a while either) so bear with me:
I have this view:
import SwiftUI
import Combine
var settings = UserSettings()
struct Promotion: View {
#State var isModal: Bool = true
#State private var selectedNamespace = 2
#State private var namespaces = settings.namespaces
var body: some View {
VStack {
Picker(selection: $selectedNamespace, label: Text("Namespaces")) {
ForEach(0 ..< namespaces.count) {
Text(settings.namespaces[$0])
}
}
}.sheet(isPresented: $isModal, content: {
Login()
})
}
}
What I do here, is to call a Login view upon launch, login, and when successful, I set the
var settings
as such in the LoginView
settings.namespaces = ["just", "some", "values"]
my UserSettings class is defined as such
class UserSettings: ObservableObject {
#Published var namespaces = [String]()
}
According to my recently obtained knowledge, my Login view is setting the namespaces property of my UserSettings class. Since this class is an ObservableObject, any view using that class should update to reflect the changes.
However, my Picker remains empty.
Is that because of a fundamental misunderstanding, or am I just missing a comma or so?
You have to pair ObservableObject with ObservedObject in view, so view is notified about changes and refreshed.
Try the following
struct Promotion: View {
#ObservedObject var settings = UserSettings() // << move here
#State var isModal: Bool = true
#State private var selectedNamespace = 2
// #State private var namespaces = settings.namespaces // << not needed
var body: some View {
VStack {
Picker(selection: $selectedNamespace, label: Text("Namespaces")) {
ForEach(namespaces.indices, id: \.self) {
Text(settings.namespaces[$0])
}
}
}.sheet(isPresented: $isModal, content: {
Login(settings: self.settings) // inject settings
})
}
}
struct Login: View {
#ObservedObject var settings: UserSettings // << declare only !!
// ... other code
}
I am trying to make the navigation bar transparent using init(), but I get the error "Return from initializer without initializing all stored properties" and I don't know how to solve it. Here is my code:
import SwiftUI
struct DoctorHomePage: View {
#Binding var shouldPopToRootView : Bool
#State var hiddingNavBar = true
#State private var curent: Int? = nil
#State private var profileSegue: Int? = nil
#State private var isActive: Bool = false
let defaults = UserDefaults.standard
let networkRequest = Network()
#State var cancelable: AnyCancellable? = nil
#State var localPatients : [Patients] = []
#Environment(\.colorScheme) var colorScheme: ColorScheme
#State private var isShowing = false
init() {
UINavigationBar.appearance().backgroundColor = .clear
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
} // I get the error here
var body: some View {
NavigationView {
VStack {
Text("Hello, World!")
}
}
}
}
You haven't initialized shouldPopToRootView.