【问题标题】:.tag() in TabView in SwiftUI challengeSwiftUI 挑战中 TabView 中的 .tag()
【发布时间】:2021-08-03 14:02:01
【问题描述】:

我在弄清楚这一点时遇到了一些挑战。在下面的代码中,我创建了一个 TabView 并能够使用 .tag() 切换哪个选项卡处于活动状态,但我有一个选项卡项的水平 ScrollView。每个选项卡屏幕都显示类似的信息,因此我使用单个视图来创建它,然后使用 ForEach 循环来浏览这些项目。但它破坏了 .tag() 函数,我似乎无法弄清楚如何使用 ForEach 循环让它工作。关于如何解决这个问题或我缺少什么的任何想法?

import SwiftUI
\\ Working code with normal Swipable tabs using .tag()
struct ContentView: View {
    var body: some View {
        
        CustomTabView()
        
    }
}

struct CustomTabView: View {
    
    @State var selectedTab = "house"
    
    var body: some View {
        
        ZStack(alignment: Alignment(horizontal: .center, vertical: .bottom)) {
            
            TabView(selection: $selectedTab) {
                
                HouseView()
                    .tag("house")
                
                EnvelopeView()
                    .tag("envelope")
                
                FolderView()
                    .tag("folder")
                
                SettingsView()
                    .tag("gear")
                
                SliderView()
                    .tag("slider.horizontal.3")

                VideoView()
                    .tag("video")

                UpView()
                    .tag("arrow.up.doc")

            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .ignoresSafeArea(.all, edges: .bottom)
            
            ScrollView(.horizontal, showsIndicators: false, content: {
                
                HStack {
                    
                    ForEach(tabs,id: \.self){image in
                        
                        TabButton(image: image, 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)
        }
        .ignoresSafeArea(.keyboard, edges: .bottom)
        .background(Color.black.opacity(0.05).ignoresSafeArea(.all, edges: .all))
    }
}

// tab...

var tabs = ["house", "envelope", "folder", "gear", "slider.horizontal.3", "video", "arrow.up.doc"]

struct TabButton: View {
    
    var image : String
    @Binding var selectedTab : String
    
    var body: some View {
        
        Button(action: {selectedTab =  image}) {
            
            Image(systemName: image)
                .renderingMode(.template)
                .opacity(self.selectedTab == image ? (1) : (0.5))
                .padding()
        }
    }
}

struct HouseView: View {

    var body: some View {
  
         VStack {
            Text("House View")

      }
   }
}

struct EnvelopeView: View {

    var body: some View {
  
         VStack {
            Text("Envelope View")

      }
   }
}

struct FolderView: View {

    var body: some View {
  
         VStack {
            Text("Folder View")

      }
   }
}

struct SettingsView: View {

    var body: some View {
  
         VStack {
            Text("Settings View")

      }
   }
}

struct SliderView: View {

    var body: some View {
  
         VStack {
            Text("Slider View")

      }
   }
}

struct VideoView: View {

    var body: some View {
  
         VStack {
            Text("Video View")

      }
   }
}

struct UpView: View {

    var body: some View {
  
         VStack {
            Text("Up View")

      }
   }
}

在 TabView 中的视图上执行 ForEach 循环后的问题代码。视图填充但它破坏了 .tag() 功能,我不知道如何让它再次工作。

import SwiftUI

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

struct CustomTabView: View {

    @State var selectedTab = "house"
    @State var viewData : AllViewData!

    var body: some View {

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

            TabView(selection: $selectedTab) {

                ForEach(allViews){views in

                    ViewsCardView(viewData: views)
                        .tag("//not sure if this is the right place for the .tag()")
                }

            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .ignoresSafeArea(.all, edges: .bottom)

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

                HStack {

                    ForEach(tabs,id: \.self){image in

                        TabButton(image: image, 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))
    }
}

// tab...

var tabs = ["house", "envelope", "folder", "gear", "slider.horizontal.3", "video", "arrow.up.doc"]

struct TabButton: View {

    var image : String
    @Binding var selectedTab : String

    var body: some View {

        Button(action: {selectedTab =  image}) {

            Image(systemName: image)
                .renderingMode(.template)
                .opacity(self.selectedTab == image ? (1) : (0.5))
                .padding()
        }
    }
}

struct ViewsCardView: View {

     @State var viewData : AllViewData!

     var body: some View {

         VStack {

           Text(viewData.name)

       }
    }
}

struct AllViewData : Identifiable {

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

}

var allViews = [

    AllViewData(name: "House"),
    AllViewData(name: "Envelope"),
    AllViewData(name: "Folder"),
    AllViewData(name: "Settings"),
    AllViewData(name: "Slider"),
    AllViewData(name: "Video"),
    AllViewData(name: "Up"),

]


【问题讨论】:

  • 请发送Minimal, Reproducible Example。您在代码中留下了太多东西,无法正常运行,因此很难看到发生了什么。另外,请使用股票 SF 符号定义图像,以便我们可以看到标签。
  • 更新了代码,使其可以被复制。感谢您指出这一点。我希望我能找到解决这个问题的方法。
  • 有问题的代码无法编译。您应该去掉第一部分中已经存在的所有内容,然后放入需要交换的结构。
  • 奇怪,因为它为我编译。问题是当像工作代码示例一样滑动到下一个视图时,选项卡不再突出显示。我的麻烦是试图找出 TabViews 的 ForEach,同时还使用 .tag()。我放了一些显示行为的 gif 示例。

标签: swiftui tabview


【解决方案1】:

您遇到的问题是您已将所有内容都输入了字符串。因此,您只是无法访问与标签栏中的每个视图相关联的图像。您的 ForEach 遍历您的 allViews,它只有视图的名称,而不是图像。因此,当您需要设置选项卡时,您没有可用的图像名称。我将您的字符串更改为一个枚举,它为您提供了一组有限的选择,并且可以更好地控制您要完成的工作。很多教程在尝试演示某些内容时都使用强类型,但这是一个坏习惯,可能会导致难以发现的错误。

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

struct CustomTabView: View {
    
    @State var selectedTab = ViewSelect.House // 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
    
}

public enum ViewSelect: String, CaseIterable {
    case House, Envelope, Folder, Settings, Slider, Video, Up
    
    var tabIcon: String {
        switch self {
        case .House:
            return "house"
        case .Envelope:
            return "envelope"
        case .Folder:
            return "folder"
        case .Settings:
            return "gear"
        case .Slider:
            return "slider.horizontal.3"
        case .Video:
            return "video"
        case .Up:
            return "arrow.up.doc"
        }
    }

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

【讨论】:

  • 太棒了!非常感谢您澄清我遇到的问题并提供一些指导。
  • 后续问题。顺便说一句,您的解决方案效果很好,但是一旦我开始在 AllViewData 结构中添加其他变量,我就会遇到枚举内的 allViewData 变量的问题。在 AllViewData 结构中处理许多变量的最佳方法是什么? ViewsCardView 将包含更多信息,而不仅仅是名称,而是使用一个视图,因为布局将保持不变,但数据会发生变化。 @Yrb
  • 我回头看,但我不确定枚举中的 allViewData 变量是什么。但是,这个问题超出了这个问题的范围。 Stack Overflow 对每个人都有用的原因是我们提出谨慎的问题并获得该问题的答案。当出现这样的事情时,您需要提出一个新问题,并发布Minimal, Reproducible Example。那就是你得到这个问题的答案,下一个人会找到那个问题和答案。
猜你喜欢
  • 2018-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多