【问题标题】:TabView with custom views using ForEach in SwiftUI在 SwiftUI 中使用 ForEach 自定义视图的 TabView
【发布时间】:2022-01-21 20:31:05
【问题描述】:

我之前问过一个关于如何在此处将一组 TabButtons 链接到 .tag() 的问题:.tag() in TabView in SwiftUI challenge,但现在我想自定义每个 TabView 以具有不同的信息,而不仅仅是从中读取的一行文本创建的枚举案例。在下面的代码中,我添加了我想用每个 TabView 填充的其他视图。我希望将来能够插入其他选项卡/视图。我在底部创建了自定义视图,但不确定如何与枚举链接,然后在 TabView 中使用 ForEach。

import SwiftUI

struct ContentView: View {
   var body: some View {
       
       CustomTabView()
       
   }
}

struct CustomTabView: View {

   @State var selectedTab = ViewSelect.HomeView // This is an enum defined below.
   @State var viewData : AllViewData!

   var body: some View {

       ZStack(alignment: Alignment(horizontal: .center, vertical: .bottom)) {

           TabView(selection: $selectedTab) {
               ForEach(ViewSelect.allCases, id: \.self) { view in // This iterates through all of the enum cases.
                   ViewsCardView(viewData: view.allViewData)
                       .tag(view.rawValue) // by having the tag be the enum's raw value,
                                           // you can always compare enum to enum.
               }
           }
           .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
           .ignoresSafeArea(.all, edges: .bottom)

           ScrollView(.horizontal, showsIndicators: false, content: {

               HStack {

                   ForEach(ViewSelect.allCases ,id: \.self){viewSelect in

                       TabButton(viewSelect: viewSelect, selectedTab: $selectedTab)

                   }
               }

           })
           .padding(.horizontal, 25)
           .padding(.vertical, 5)
           .background(Color.white)
           .clipShape(Capsule())
           .shadow(color: Color.black.opacity(0.15), radius: 5, x: 5, y: 5)
           .shadow(color: Color.black.opacity(0.15), radius: 5, x: -5, y: -5)
           .padding(.horizontal)
       }
       .background(Color.black.opacity(0.05).ignoresSafeArea(.all, edges: .all))
   }
}

struct TabButton: View {
   let viewSelect: ViewSelect
   @Binding var selectedTab: ViewSelect

   var body: some View {

       Button(action: {selectedTab = viewSelect}) {

           Image(systemName: viewSelect.tabIcon)
               .renderingMode(.template)
               // this compares the selection to the button's associated enum.
               // The enum provides the image name to the button,
               // but we are always dealing with a case of the enum.
               .opacity(selectedTab == viewSelect ? (1) : (0.5))
               .padding()
       }
   }
}

struct ViewsCardView: View {

   @State var viewData: AllViewData

   var body: some View {

       VStack {

           Text(viewData.name)

       }
   }
}

struct AllViewData : Identifiable, Hashable {

   var id = UUID().uuidString
   var name : String
   var text : Int

}

public enum ViewSelect: String, CaseIterable {
   case HomeView, EnvelopeView, FolderView, SettingsView

   var tabIcon: String {
       switch self {
       case .HomeView:
           return "house"
       case .EnvelopeView:
           return "envelope"
       case .FolderView:
           return "folder"
       case .SettingsView:
           return "gear"

       }
   }

   var allViewData: AllViewData {
       return AllViewData(name: self.rawValue, text: self.hashValue)
   }
}

struct DataForViews : Identifiable {
   
   var id = UUID().uuidString
   var someText : SomeText
   var someImage : SomeImage
   var someData : String
   var moreText : String
   
   enum SomeText : String, CaseIterable {
       case friends
       case enemies
       case neutral
       case both
   }
   
   enum SomeImage : String, CaseIterable {
       case friends = "person.3"
       case enemies = "person.fill.xmark"
       case neutral = "person"
       case both = "person.circle"
   }
}


struct HomeView: View {
   
   @State var viewData = DataForViews(someText: .friends, someImage: .friends, someData: "Some Data", moreText: "More Text")
   
   var body: some View {
       VStack {
           Text(viewData.someText.rawValue)
           Image(systemName: viewData.someImage.rawValue)
               .resizable()
               .frame(width: 40, height: 40)
           
           Text(viewData.someData)
           Text(viewData.moreText)
       }
   }
}

struct EnvelopeView: View {
   
   @State var viewData = DataForViews(someText: .enemies, someImage: .enemies, someData: "Some Data", moreText: "More Text")
   
   var body: some View {
       VStack {
           Text(viewData.someText.rawValue)
           Image(systemName: viewData.someImage.rawValue)
               .resizable()
               .frame(width: 40, height: 40)
           
           
           Text(viewData.moreText)
       }
   }
}

struct FolderView: View {
   
   @State var viewData = DataForViews(someText: .neutral, someImage: .neutral, someData: "Some Data", moreText: "More Text")
   
   var body: some View {
       VStack {
           Text(viewData.someText.rawValue)
           Image(systemName: viewData.someImage.rawValue)
               .resizable()
               .frame(width: 40, height: 40)
           
           Text(viewData.someData)
           Text(viewData.moreText)
       }
   }
}

struct SettingsView: View {
   
   @State var viewData = DataForViews(someText: .both, someImage: .both, someData: "Some Data", moreText: "More Text")
   
   var body: some View {
       VStack {
           Text(viewData.someText.rawValue)
           Image(systemName: viewData.someImage.rawValue)
               .resizable()
               .frame(width: 40, height: 40)
           
           Text(viewData.someData)
           
       }
   }
} 

【问题讨论】:

  • 问题不清楚 - 是什么阻止了你这样做?
  • 我其实不知道该怎么做。我不知道如何在 TabView() ForEach 循环中实现 HomeView()、EnvelopeView()、FolderView() 和 SettingsView(),或者是否有不同的方法来解决这个问题?我知道你可以通过 TabView() 来实现,然后调用视图,然后是 tabItem,最后是 .tag()。但是,如果我要插入新视图以及重构 .tag() 的选项卡,就会变得很麻烦。 @Asperi

标签: swiftui enums swiftui-tabview


【解决方案1】:

我想我想通了。我花了很多时间修修补补,我来这里是为了堆栈溢出来尝试进一步澄清。但是下面的解决方案应该有效。我在 HomeView() 中创建了一个将 ViewSelect 链接为枚举的变量,然后我使用 DataForViews 结构中的数组初始化了不同的选项,并将选择链接到与 tabItems 绑定的 ViewSelect 枚举。

然后在 ContentView 中,我遵循相同的模式,只是在 HomeView() 上使用了 ForEach 循环,而对于 .tag(),它与 ​​DataForViews 中的选择相关联。

struct CustomTabView: View {

    @State var selectedTab = ViewSelect.HomeView // This is an enum defined below.
    @State var viewData : AllViewData!

    var body: some View {

        ZStack(alignment: Alignment(horizontal: .center, vertical: .bottom)) {

            TabView(selection: $selectedTab) {
                ForEach(viewDataStuff) { view in
                    HomeView(viewData: view)
                        .tag(view.selection)
                }
struct DataForViews : Identifiable, Hashable {
    
    var id = UUID().uuidString
    var someText : SomeText
    var someImage : SomeImage
    var someData : String
    var moreText : String
    var selection : ViewSelect
    
    enum SomeText : String, CaseIterable {
        case friends
        case enemies
        case neutral
        case both
    }
    
    enum SomeImage : String, CaseIterable {
        case friends = "person.3"
        case enemies = "person.fill.xmark"
        case neutral = "person"
        case both = "person.circle"
    }
}
var viewDataStuff = [
    
    DataForViews(someText: .friends, someImage: .friends, someData: "Text", moreText: "Text", selection: .HomeView),
    DataForViews(someText: .enemies, someImage: .enemies, someData: "Text", moreText: "Text", selection: .EnvelopeView),
    DataForViews(someText: .neutral, someImage: .neutral, someData: "Text", moreText: "Text", selection: .FolderView),
    DataForViews(someText: .both, someImage: .both, someData: "Text", moreText: "Text", selection: .SettingsView),
]


struct HomeView: View {
    
    @State var viewData : DataForViews
    
    var body: some View {
        VStack {
            Text(viewData.someText.rawValue)
            Image(systemName: viewData.someImage.rawValue)
                .resizable()
                .frame(width: 40, height: 40)
            
            Text(viewData.someData)
            Text(viewData.moreText)
        }
    }
}
'''

【讨论】:

    猜你喜欢
    • 2021-03-08
    • 1970-01-01
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多