首页 > 解决方案 > 在 SwiftUI 中使用 TabView 时,第一个选项卡栏按钮出现两次

问题描述

从屏幕截图中可以看出,“语言”选项卡出现了两次。

第一个 TabView 选项卡出现两次

我有以下代码用于在应用程序启动时调用的 HostingTabBar:


struct HostingTabBar: View {
    
    private enum Tab: Hashable {
        case language
        case canvas
        case homework
        case test
        case more
    }
    
    @State private var selectedTab: Tab = .language
    
    var body: some View {
        TabView(selection: $selectedTab) {
        LanguageView()
            .tag(0)
            .tabItem {
                Text("Language")
                Image("language")
            }
        CanvasView()
            .tag(1)
            .tabItem {
                Text("Canvas")
                Image("canvas")
            }
        HomeworkView()
            .tag(2)
            .tabItem {
                Text("Homework")
                Image("homework")
            }
        TestView()
            .tag(3)
            .tabItem {
                Text("Test")
                Image("test")
            }
        MoreView()
            .tag(4)
            .tabItem {
                Text("More")
                Image("more")
            }
        }
        .accentColor(nil)
    }
}

struct HostingTabBar_Previews: PreviewProvider {
    static var previews: some View {
        HostingTabBar()
    }
}

语言视图()是:

import CoreData

struct LanguageView: View {
    
    @State private var addLanguageIsPresented: Bool = false
    @State private var text: String = ""
    @State private var languageDuplicateIsPresented: Bool = false
    @State private var selectAll: Bool = false

    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(entity: Languages.entity(), sortDescriptors: [])

    var languages: FetchedResults<Languages>
    
    var body: some View {
        NavigationView {
            List {
                ForEach(languages) { language in
                    NavigationLink(destination: WordsView(language: language)) {
                        LanguageRowView(language: language, selectAll: selectAll)
                    }
                }
                .onDelete { indexSet in
                    for index in indexSet {
                        viewContext.delete(languages[index])
                    }
                    do {
                        try viewContext.save()
                    } catch {
                        print(error.localizedDescription)
                    }
                }
                .frame(width: screenSize.width - 30, height: 50)
            }
            .navigationBarTitle("Language", displayMode: .inline).opacity(0.8)
            .background(Color.init(.systemGroupedBackground))
            .toolbar {
                ToolbarItemGroup(placement: .navigationBarLeading) {
                    Button(action: {
                        self.text = ""
                        self.addLanguageIsPresented = true
                        print("add Language is presented is: \(self.addLanguageIsPresented)")
                    }, label: {
                        Image("addLanguage")
                            .foregroundColor(.green)
                    })
                    
                    Button(action: {
                        print("selectAll is: \(selectAll) before selection")
                        if selectAll { selectAll = false } else { selectAll = true }
                        print("selectAll is: \(selectAll) after selection")
                    }, label: {
                        if selectAll { Image("unSelectAll") } else { Image("selectAll") }
                    })
                }
                ToolbarItemGroup(placement: .navigationBarTrailing) {
                    Button(action: {
                        
                    }, label: {
                        Image("keyboards")
                            .foregroundColor(.green)
                    })
                    
                    Button(action: {
            
                    }, label: {
                        Image("delete")
                            .foregroundColor(.green)
                    })
                }
            }
        }
        
        addLanguageAlert(title: "Add Language or Sub-Division", isShown: $addLanguageIsPresented, text: $text, onDone: { text in
            print("Inside addLanguageAlert")
            guard text.count > 0 else { return }
            
            // submit language to the addAndSaveLanguage method
            let newLanguage = Languages(context: viewContext)
            newLanguage.name = text
            newLanguage.ckupload = true

            let selectedLanguage = languages.filter { $0.selected == true }
            if selectedLanguage.count > 0 {
                newLanguage.selected = false
            } else {
                newLanguage.selected = true
            }
            newLanguage.setAsHomework = false
            newLanguage.selectedHomework = false
            newLanguage.tickedHomework = false
            newLanguage.tickedLanguage = false

            let recordName = "idlanguage-\(UUID())"
            let zone = CKRecordZone(zoneName: "languagesList")
            let identification = CKRecord.ID(recordName: recordName, zoneID: zone.zoneID)
            let record = CKRecord(recordType: "Languages", recordID: identification)
            let coder = NSKeyedArchiver(requiringSecureCoding: true)
            record.encodeSystemFields(with: coder)
            let metadata = coder.encodedData
            newLanguage.ckmetadata = metadata
            newLanguage.ckrecordname = recordName

            do {
                try viewContext.save()
                print("Language saved.")
            } catch {
                print(error.localizedDescription)
            }
        })
    }
}

struct LanguageView_Previews: PreviewProvider {
    static var previews: some View {
        LanguageView()
    }
}

点击一行加载 wordsView():

import CoreData

struct WordsView: View {
        
    @State private var addWordIsPresented: Bool = false
    @State private var english: String = ""
    @State private var foreign: String = ""
    @State private var selectAll: Bool = false

    @Environment(\.managedObjectContext) private var viewContext
    
    let language: Languages
    
    var body: some View {
    
        var words = language.words?.allObjects as! [Words]
    
        NavigationView {
            List {
                ForEach(words) { word in
                    WordRowView(word: word, selectAll: selectAll)
                }
                .onDelete { indexSet in
                    for index in indexSet {
                        viewContext.delete(words[index])
                    }
                    do {
                        try viewContext.save()
                    } catch {
                        print(error.localizedDescription)
                    }
                }
                .frame(width: screenSize.width, height: 75)
            }
            .navigationBarTitle("\(language.name ?? "")", displayMode: .inline).opacity(0.8)
            .background(Color.init(.systemGroupedBackground))
        }
        .toolbar {
            ToolbarItemGroup(placement: .navigationBarLeading) {
                Button(action: {
                    self.english = ""
                    self.foreign = ""
                    self.addWordIsPresented = true
                }, label: {
                    Image("addWord")
                })
                    
                Button(action: {
                    print("selectAll is: \(selectAll) before selection")
                    if selectAll { selectAll = false } else { selectAll = true }
                    print("selectAll is: \(selectAll) after selection")
                }, label: {
                    if selectAll { Image("unSelectAll") } else { Image("selectAll") }
                })
            }
            ToolbarItemGroup(placement: .primaryAction) {
                Button(action: {
        
                }, label: {
                    Image("delete")
                })
            }
        }
        
        addWordAlert(title: "Add Word/Phrase", isShown: $addWordIsPresented, english: $english, foreign: $foreign, onDone: { _,_  in
            // pull out the English and foreign words, or an empty string if there was a problem
            english = english.trimmingCharacters(in: .whitespacesAndNewlines)
            foreign = foreign.trimmingCharacters(in: .whitespacesAndNewlines)
            guard english.count > 0 && foreign.count > 0 else { return }
            
            let newWord = Words(context: viewContext)
            newWord.english = english
            newWord.foreign = foreign
            newWord.language = language
            newWord.ckimage = false
            newWord.ckupload = true
            newWord.bonusCorrectAnswers = 0
            newWord.ckreference = self.language.ckrecordname
            newWord.homeworkAttempts = 0
            newWord.homeworkCorrectAnswers = 0
            newWord.image = nil
            newWord.languageAttempts = 0
            newWord.languageCorrectAnswers = 0
            newWord.tickedWord = false
            newWord.tickedSearchWord = false
            newWord.tickedHomework = false
            newWord.tickedSearchHomework = false
            
            words.append(newWord)
                
            let selectedWord = words.filter{ $0.language == language && $0.selected == true }
            if selectedWord.count > 0 {
                newWord.selected = false
            } else {
                newWord.selected = true
            }
                
            let recordName = "idword-\(UUID())"
            let zone = CKRecordZone(zoneName: "languagesList")
            let id = CKRecord.ID(recordName: recordName, zoneID: zone.zoneID)
            let record = CKRecord(recordType: "Words", recordID: id)
            let coder = NSKeyedArchiver(requiringSecureCoding: true)
            record.encodeSystemFields(with: coder)
            let metadata = coder.encodedData
                
            newWord.ckmetadata = metadata
            newWord.ckrecordname = recordName

            do {
                try viewContext.save()
                print("Word saved.")
            } catch {
                print(error.localizedDescription)
            }
        })
    }
}

struct wordsView_Previews: PreviewProvider {
    static var previews: some View {
        HostingTabBar().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}

let screenSize = UIScreen.main.bounds

“测试”标签栏项目被移动到“更多”标签中的列表中,并带有一个在点击时加载 TestView 的披露指示器。导航栏中还有一个编辑按钮,点击时如下所示:

更多选项卡中的编辑按钮

标签: swiftswiftuitabbartabview

解决方案


您对.tag(_:). ' TabViewsselection是一个Tab绑定,而您的标签都是Ints(0、1、2 等)。要解决此问题,请将您tag(_:)的 s 更改为Tab枚举值。

代码:

struct HostingTabBar: View {
    
    private enum Tab: Hashable {
        case language
        case canvas
        case homework
        case test
        case more
    }
    
    @State private var selectedTab: Tab = .language
    
    var body: some View {
        TabView(selection: $selectedTab) {
        LanguageView()
            .tag(Tab.language)
            .tabItem {
                Text("Language")
                Image("language")
            }
        CanvasView()
            .tag(Tab.canvas)
            .tabItem {
                Text("Canvas")
                Image("canvas")
            }
        HomeworkView()
            .tag(Tab.homework)
            .tabItem {
                Text("Homework")
                Image("homework")
            }
        TestView()
            .tag(Tab.test)
            .tabItem {
                Text("Test")
                Image("test")
            }
        MoreView()
            .tag(Tab.more)
            .tabItem {
                Text("More")
                Image("more")
            }
        }
        .accentColor(nil)
    }
}

推荐阅读