Перезагрузить вид в зависимости от изменения значения переменной @State - PullRequest
2 голосов
/ 06 августа 2020

У меня есть вкладка в верхней части экрана. Вкладки - динамические c и ListView () , показанные под вкладкой, зависят от индекса вкладки. Для индекса вкладки 0 ListView () исправлен, но начиная с индекса 1 и далее ListView () будет перезагружаться в зависимости от выбранного индекса вкладки. Итак, моя текущая выбранная вкладка выглядит следующим образом:

@State private var selectedTabIndex = 0

И я перезагружаю View статично, вот так:

if self.selectedTabIndex == 0 {
     ListView(id: selectedTabIndex)
} else if self.selectedTabIndex == 1 {
     ListView(id: selectedTabIndex)          
} else if self.selectedTabIndex == 2 {
     ListView(id: selectedTabIndex)       
} else if self.selectedTabIndex == 3 {
     ListView(id: selectedTabIndex)
} else if self.selectedTabIndex == 4 {
     ListView(id: selectedTabIndex)
} else if self.selectedTabIndex == 5 {
     ListView(id: selectedTabIndex)
}

Это работает нормально, перезагрузите ListView (), но это неправильный подход, потому что индекс вкладки будет более или менее динамически. Итак, я попробовал что-то вроде этого, поскольку мое значение selectedTabIndex изменяется, когда я нажимаю на вкладку:

if self.selectedTabIndex == 0 {
     ListView(id: selectedTabIndex)
} else {
     ListView(id: selectedTabIndex)
}

Но он перезагружается только на первой нажатой вкладке, а не на других. Как я могу это исправить? Поскольку я новичок в SwiftUI, мне иногда это трудно. Пожалуйста, помогите.

Подробнее:

import SwiftUI

struct WorkView: View {
@EnvironmentObject var navBarPreference: NavBarPreferences

@State private var selectedTabIndex = 0
@State private var isEmpty: Bool = true //
@State private var showWorkDetailView:Bool = false
@State var isCategoryAvailable:Bool = false

@ObservedObject var WorkVM = WorkViewModel() //
@State var workCategoryName: [String] = [" "]
@State var workCategoryID: [Int] = [0]
@State var selectedID: Int = 0
@State var workContentModel = [WorkContentModel]() //

var body: some View {
    VStack(spacing: 0) {
        HeaderView(title: "ワーク")
        VStack {
            
            if self.workCategoryName.isEmpty == false {
                SlidingTab(selection: $selectedTabIndex, tabs: self.workCategoryName).padding(.top, 10)
            }
            
        }
        
        Spacer().frame(maxHeight: 24)
        
        //(selectedTabIndex == 0 ? SelectedFirstTab() : Text("Second View")).padding()
        
        if self.selectedTabIndex == 0 {
            SelectedFirstTab(selectedTabIndex: self.selectedTabIndex, isCategoryAvailable: self.$isCategoryAvailable, workCategoryName: self.$workCategoryName, workCategoryID: self.$workCategoryID, selectedID: self.$selectedID)
        } else if self.selectedTabIndex == 1 {
            SelectedFirstTab(selectedTabIndex: self.selectedTabIndex, isCategoryAvailable: self.$isCategoryAvailable, workCategoryName: self.$workCategoryName, workCategoryID: self.$workCategoryID, selectedID: self.$workCategoryID[self.selectedTabIndex])

        } else if self.selectedTabIndex == 2 {
            SelectedFirstTab(selectedTabIndex: self.selectedTabIndex, isCategoryAvailable: self.$isCategoryAvailable, workCategoryName: self.$workCategoryName, workCategoryID: self.$workCategoryID, selectedID: self.$workCategoryID[self.selectedTabIndex])

        } else if self.selectedTabIndex == 3 {
            SelectedFirstTab(selectedTabIndex: self.selectedTabIndex, isCategoryAvailable: self.$isCategoryAvailable, workCategoryName: self.$workCategoryName, workCategoryID: self.$workCategoryID, selectedID: self.$workCategoryID[self.selectedTabIndex])

        } else if self.selectedTabIndex == 4 {
            SelectedFirstTab(selectedTabIndex: self.selectedTabIndex, isCategoryAvailable: self.$isCategoryAvailable, workCategoryName: self.$workCategoryName, workCategoryID: self.$workCategoryID, selectedID: self.$workCategoryID[self.selectedTabIndex])

        } else if self.selectedTabIndex == 5 {
            SelectedFirstTab(selectedTabIndex: self.selectedTabIndex, isCategoryAvailable: self.$isCategoryAvailable, workCategoryName: self.$workCategoryName, workCategoryID: self.$workCategoryID, selectedID: self.$workCategoryID[self.selectedTabIndex])
        }
        
        //Spacer()
    }.frame(minWidth: SCREEN_WIDTH)
        
        //.position(x: SCREEN_WIDTH/2, y: SCREEN_HEIGHT/2)
        //            .background(
        //                Image("PPImage")
        //                    .resizable()
        //                    .frame(minWidth: 375, minHeight: 945)
        //                //.aspectRatio(contentMode: .fit)
        //        )
        .edgesIgnoringSafeArea(.top)
        .navigationBarTitle("", displayMode: .inline)
        .navigationBarHidden(self.navBarPreference.navBarIsHidden)
        .navigationBarBackButtonHidden(self.navBarPreference.navigationBarBackButtonHidden)
        .onAppear{ self.navBarPreference.navBarIsHidden = true
            self.navBarPreference.navigationBarBackButtonHidden = true }
}

}

struct SelectedFirstTab: View {
@State private var isEmpty: Bool = true
@ObservedObject var WorkVM = WorkViewModel()
@State var workContentModel = [WorkContentModel]()

var selectedTabIndex: Int = 0
@Binding var isCategoryAvailable:Bool
@Binding var workCategoryName: [String]
@Binding var workCategoryID: [Int]
@Binding var selectedID: Int


var body: some View {
    VStack {
        if self.workContentModel.isEmpty {
            EmptyContent()
        } else {
            ScrollView(showsIndicators: false) {
                ForEach(self.workContentModel) { content in
                    NavigationLink(destination: WorkDetailView(data: content)) {
                        WorkViewRow(data: content)
                    }.frame(minWidth: SCREEN_WIDTH, minHeight: 118)
                        .padding(.top, 5)
                        .padding(.bottom, 5)
                }
            }.frame(maxHeight: 600)
        }
    }
    .onAppear {
        
        if self.isCategoryAvailable == false {
            self.WorkVM.getWorkList() { workCategory, content in
                for i in 0..<workCategory.count {
                    self.workCategoryName.append(workCategory[i].name ?? " ")
                    self.workCategoryID.append(workCategory[i].id ?? 0)
                }
                self.workCategoryName.removeFirst()
                
                self.workContentModel = content
                self.isCategoryAvailable = true
                self.isEmpty = false
                
                // print("myContent:\(content)")
                // print("workCategoryID:\(self.workCategoryID)")
                
                self.selectedID = self.workCategoryID[self.selectedTabIndex]
                print("selectedID:\(self.selectedID)")
                
            }
            
        } else if self.isCategoryAvailable == true {
            self.WorkVM.getCategory(id: self.selectedID) { content in
                self.workContentModel = content
                self.isEmpty = false
                self.selectedID = self.workCategoryID[self.selectedTabIndex]
                print("selectedID:\(self.selectedID)")
            }
        }
        
    }
}
}

struct EmptyContent: View {
var body: some View {
    ZStack {
        Rectangle()
            .foregroundColor(.clear)
            .frame(maxHeight: 600)
        
        VStack {
            Image("EmptyBackgroundImage")
                .resizable()
                .frame(maxWidth: 150, maxHeight: 146)
            CustomizedText(text: "表示されるワークは \n ありません", tracking: 2.2, frameHeight: 72, fontFamily: "HiraginoSans-W6", fontFamilySize: 22, lineLimit: 2)
                .frame(maxWidth: 218, maxHeight: 72)
            CustomizedText(text: "ここではワーク情報をお届けします。\n 最新のワークを探していますのでお待ちください。", tracking: 1.2, frameHeight: 42, fontFamily: "HiraginoSans-W3", fontFamilySize: 12, lineLimit: 2).frame(maxWidth: 333, maxHeight: 42)
            Spacer().frame(maxHeight: 210)
            
        }
    }
}
}

Ползунок :

 import SwiftUI

 struct SlidingTab: View {

// Internal state to keep track of the selection index
@State private var selectionState: Int = 0 {
    didSet {
        selection = selectionState
    }
}

// Binding the selection index which will  re-render the consuming view
 @Binding var selection: Int

// The title of the tabs
 private var tabs: [String]

init(selection: Binding<Int>, tabs: [String]) {
    self._selection = selection
    self.tabs = tabs
}

var body: some View {
    VStack {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 24.scale()) {
                ForEach(self.tabs, id: \.self) { tab in
                    VStack {
                        Text(tab)
                                .frame(maxHeight: 55)
                                .font(.custom("HiraginoSans-W6", size: 15))
                            .foregroundColor(self.selection == self.tabs.firstIndex(of: tab) ? APP_TEXT_COLOR : APP_TEXT_COLOR.opacity(0.5))
                        
                        Rectangle()
                            .frame(maxHeight: 3)
                            .foregroundColor(self.selection == self.tabs.firstIndex(of: tab) ? APP_COLOR : Color.clear)
                            .animation(.linear(duration: 0.25))
                        
                    }.fixedSize()
                        .onTapGesture {
                             withAnimation {
                            let selection = self.tabs.firstIndex(of: tab) ?? 0
                            self.selectionState = selection
                            }
                    }
                }
            }.padding(.horizontal, 20.scale())
        }
    }
    
}
}

И мой ViewModel :

import Foundation
import Combine
import Alamofire
import SwiftyJSON

class WorkViewModel: ObservableObject {
var updateValue =  PassthroughSubject<WorkViewModel, Never>()

@Published var workCategory = [WorkCategoryModel]() {
    willSet {
        updateValue.send(self)
    }
}

@Published var workContent = [WorkContentModel]() {
    willSet {
        updateValue.send(self)
    }
}

func getWorkList(completionHandler: @escaping ([WorkCategoryModel], [WorkContentModel]) -> Void) {
    AF.request(Router.get(endpoint: "/mobile/works/top"))
        .responseDecodable(of: WorkTabModel.self) { response in
            
            print("Original URL request WorkList Tab:\(String(describing: response.request))")
            
            switch response.result {
            case let .success(value):
                if let workCategory = value.data.workCategories {
                    self.workCategory.append(contentsOf: workCategory)
                }
               // print("workCategory**:\(self.workCategory)")
                
                if let workContent = value.data.work?.content {
                    self.workContent.append(contentsOf: workContent)
                }
                print("workContent**:\(self.workContent)")

                completionHandler(self.workCategory, self.workContent)

            case let .failure(error):
                print("WorkModel Error**:\(error)")
            }
    }
    
}

func getCategory(id: Int, completionHandler: @escaping ([WorkContentModel]) -> Void) {
    let urlString = "\(baseUrl)/mobile/works/top?work_category_id=\(id)"
    let userToken = UserDefaults.standard.value(forKey: "access_token") ?? ""
    let token = "Bearer \(userToken)"

    let headers: HTTPHeaders = [
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Authorization": token
    ]

    AF.request(urlString, headers: headers)
        .responseJSON { response in
        print("Original URL request WorkList Category:\(String(describing: response.request))")
        print("Category JSON response:\(response)")
    }
    .responseDecodable(of: WorkTabModel.self) { response in
               
               print("Original URL request WorkList Tab:\(String(describing: response.request))")
               
               switch response.result {
               case let .success(value):
                   if let workContent = value.data.work?.content {
                       self.workContent.append(contentsOf: workContent)
                   }
                   print("workContent**:\(self.workContent)")

                   completionHandler(self.workContent)

               case let .failure(error):
                   print("WorkModel Error**:\(error)")
               }
       }
    
}
}

1 Ответ

0 голосов
/ 09 августа 2020

Наконец-то я получил решение. Я вызывал API из .onAppear {} , и когда я нажимал на другую вкладку на верхнем слайдере, я получал id и с этим id я хотел для вызова того же API, но с id . Несмотря на то, что я использовал переменную @ State для id , представление не перезагружалось. Поэтому я вызвал API из .onTapGesture {} . Но все же у меня были некоторые трудности, потому что значение .onTapGesture {} и @ State менялось одновременно. Поэтому я использовал DispatchQueue.main.asyncAfter и вызвал API, используя оттуда значение @ State . Я делюсь приведенным ниже кодом, если это может кому-то помочь:

struct WorkView: View {
@EnvironmentObject var navBarPreference: NavBarPreferences

@State private var selectedTabIndex = 0
@State private var showWorkDetailView:Bool = false
@State var isCategoryAvailable:Bool = false

@ObservedObject var WorkVM = WorkViewModel() //
@State var workCategoryName: [String] = [" "]
@State var workCategoryID: [Int] = [0]
@State var workContentModel = [WorkContentModel]()
@State var hasShown: Bool = false

var body: some View {
    VStack(spacing: 0) {
        HeaderView(title: "ワーク")
        VStack {
            if self.workCategoryName.isEmpty == false {
                SlidingTab(selection: $selectedTabIndex, tabs: self.workCategoryName).padding(.top, 10)
                    .onTapGesture {
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                            if self.isCategoryAvailable == true {
                                self.hasShown = true
                                //self.workContentModel.removeAll()
                                print("myWorkCategoryIDs:\(self.workCategoryID)")
                                print("mySelectedIndex:\(self.selectedTabIndex)")
                                let mySelectedID = self.workCategoryID[self.selectedTabIndex]
                                self.WorkVM.workContent.removeAll()
                                self.workContentModel.removeAll()
                                self.getContent(id: mySelectedID)
                            }
                        }
                    }
            }
        }
        
        Spacer().frame(maxHeight: 24)
        
        //(selectedTabIndex == 0 ? SelectedFirstTab() : Text("Second View")).padding()
        VStack {
            if self.workContentModel.isEmpty {
                EmptyContent()
            } else {
                ScrollView(showsIndicators: false) {
                    ForEach(self.workContentModel) { content in
                        //Text("hihihihihihihihihi").frame(minWidth: 100, minHeight: 118)
                        NavigationLink(destination: WorkDetailView(data: content)) {
                            WorkViewRow(data: content)
                        }.frame(minWidth: SCREEN_WIDTH, minHeight: 118)
                            .padding(.top, 5)
                            .padding(.bottom, 5)
                    }
                }.frame(maxHeight: 600)
            }
        }
        
        //Spacer()
    }.frame(minWidth: SCREEN_WIDTH)
        .edgesIgnoringSafeArea(.top)
        .navigationBarTitle("", displayMode: .inline)
        .navigationBarHidden(self.navBarPreference.navBarIsHidden)
        .navigationBarBackButtonHidden(self.navBarPreference.navigationBarBackButtonHidden)
        .onAppear{ self.navBarPreference.navBarIsHidden = true
            self.navBarPreference.navigationBarBackButtonHidden = true
            
            if (self.hasShown == false && self.isCategoryAvailable == false) {
                self.WorkVM.workContent.removeAll()
                self.workContentModel.removeAll()
                self.getCategoryWithContent()
            }
    }
    
    
}

func getCategoryWithContent() {
    self.WorkVM.getWorkList() { workCategory, content in
        for i in 0..<workCategory.count {
            self.workCategoryName.append(workCategory[i].name ?? " ")
            self.workCategoryID.append(workCategory[i].id ?? 0)
        }
        self.workCategoryName.removeFirst()
        
        self.workContentModel = content
        self.isCategoryAvailable = true
        
        print("selectedTabIndex:\(self.selectedTabIndex)")
        print("getCategoryWithContent called")
        
    }
}

func getContent(id: Int) {
    self.WorkVM.getCategory(id: id) { content in
        self.workContentModel = content
        print("selectedTabIndex:\(self.selectedTabIndex)")
        print("getContent called")
    }
}
}


struct EmptyContent: View {
var body: some View {
    ZStack {
        Rectangle()
            .foregroundColor(.clear)
            .frame(maxHeight: 600)
        
        VStack {
            Image("EmptyBackgroundImage")
                .resizable()
                .frame(maxWidth: 150, maxHeight: 146)
            CustomizedText(text: "表示されるワークは \n ありません", tracking: 2.2, frameHeight: 72, fontFamily: "HiraginoSans-W6", fontFamilySize: 22, lineLimit: 2)
                .frame(maxWidth: 218, maxHeight: 72)
            CustomizedText(text: "ここではワーク情報をお届けします。\n 最新のワークを探していますのでお待ちください。", tracking: 1.2, frameHeight: 42, fontFamily: "HiraginoSans-W3", fontFamilySize: 12, lineLimit: 2).frame(maxWidth: 333, maxHeight: 42)
            Spacer().frame(maxHeight: 210)
            
        }
    }
}
}


 
...