Nano Hash - криптовалюты, майнинг, программирование

Перезагрузить вид в зависимости от изменения значения переменной @State

У меня есть вкладка над моим обзором. Вкладки являются динамическими, и 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)")
               }
       }
    
}
}
06.08.2020

  • Я не понимаю этого условия - оно одинаково в обеих ветках - и зачем вам привязка для selectedTabIndex? 06.08.2020
  • хорошо, проверяю, секундочку 06.08.2020
  • Хорошо, я изменил привязку, но проблема та же. Не перезагружать при изменении значения переменной @State. 06.08.2020
  • Это был вопрос, а не предлагаемое решение - для отладки требовался минимальный воспроизводимый пример. 06.08.2020
  • В первой ветке он перезагружает весь ListView (), но во второй ветке он загружает 0 и только первую нажатую вкладку, скажем, я нажал 1 вкладку, она загружается, но когда я нажимаю 2,3 или 4, она не перезагружается. Итак, мой вопрос: значение @State меняется, но почему вторая ветка не перезагружается, а значение другое 06.08.2020
  • хорошо, я показываю весь код вопроса, секундочку 06.08.2020

Ответы:


1

Наконец-то я получил решение. Я вызывал 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)
            
        }
    }
}
}


 
09.08.2020
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..


© 2024 nano-hash.ru, Nano Hash - криптовалюты, майнинг, программирование