【问题标题】:Add shadow above SwiftUI's TabView在 SwiftUI 的 TabView 上方添加阴影
【发布时间】:2021-06-23 15:10:19
【问题描述】:

我正在尝试在 SwiftUI 中实现 TabView,它与屏幕背景颜色相同,但在其上方也有 阴影,如下图所示:

到目前为止,我已经能够正确显示颜色,但我不知道如何添加阴影。这是我的代码:

struct ContentView: View {
    
    init() {
        let appearance = UITabBarAppearance()
        appearance.configureWithTransparentBackground()

        UITabBar.appearance().standardAppearance = appearance
    }
    
    var body: some View {
        TabView {
            Text("First View")
                .tabItem {
                    Image(systemName: "square.and.arrow.down")
                    Text("First")
                }
            Text("Second View")
                .tabItem {
                    Image(systemName: "square.and.arrow.up")
                    Text("Second")
                }
        }
    
    }
}

有人知道怎么做吗?我会很感激你的帮助:)

【问题讨论】:

    标签: swift swiftui shadow swiftui-tabview


    【解决方案1】:

    简答

    我找到了解决方案。您可以创建自己的阴影图像并将其添加到 UITabBar 外观,如下所示:

    // load your custom shadow image
    let shadowImage: UIImage = ...
    
    //you also need to set backgroundImage, without it shadowImage is ignored
    UITabBar.appearance().backgroundImage = UIImage()
    UITabBar.appearance().shadowImage = shadowImage
    

    更详细的回答

    设置背景图片

    注意通过设置

    UITabBar.appearance().backgroundImage = UIImage()
    

    你让你的 TabView 透明,所以如果你有可以在它下面滚动的内容是不理想的。为了克服这个问题,您可以设置 TabView 的颜色。

    let appearance = UITabBarAppearance()
    appearance.configureWithTransparentBackground()
    appearance.backgroundColor = UIColor.systemGray6
    UITabBar.appearance().standardAppearance = appearance
    
    

    设置 shadowImage

    我想以编程方式生成阴影图像。为此,我创建了 UIImage 的扩展。 (code taken from here)

    extension UIImage {
        static func gradientImageWithBounds(bounds: CGRect, colors: [CGColor]) -> UIImage {
            let gradientLayer = CAGradientLayer()
            gradientLayer.frame = bounds
            gradientLayer.colors = colors
            
            UIGraphicsBeginImageContext(gradientLayer.bounds.size)
            gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image!
        }
    }
    

    最后我把我的 TabView 设置成这样:

    let image = UIImage.gradientImageWithBounds(
        bounds: CGRect( x: 0, y: 0, width: UIScreen.main.scale, height: 8),
        colors: [ 
            UIColor.clear.cgColor, 
            UIColor.black.withAlphaComponent(0.1).cgColor
        ]
    )
    
    let appearance = UITabBarAppearance()
    appearance.configureWithTransparentBackground()
    appearance.backgroundColor = UIColor.systemGray6
            
    appearance.backgroundImage = UIImage()
    appearance.shadowImage = image
    
    UITabBar.appearance().standardAppearance = appearance
    
    

    结果

    【讨论】:

    • +1 并且非常出色地提出了这个 SwiftUI 解决方案。实际上,您的方式使您无需创建自己的 TabView 即可实现您想要的。我个人发现在某些时候我几乎总是需要做一些我需要自己的 TabView 的事情(即:隐藏它,到目前为止,你不能像在 UIKit 中那样在 SwiftUI 中隐藏子查看的 TabView使用UITabBar.appearance().isHidden = true),最终我发现拥有自己的代码并不那么痛苦,因为它很灵活,并且最终编写的代码更少,但这是一个偏好问题。
    • 在 iOS 15 中不工作:|,在较小的情况下工作正常
    • 嗨 @AbhishekThapliyal 我可以确认该解决方案在 iOS 15 上对我不起作用。阴影显示正确,但标签栏是透明的。我将在接下来的几周内更新答案。
    • @EllaGogo: 我的不好,它正在工作,如果没有你可以试试 if #available(iOS 15.0, *) { UITabBar.appearance().scrollEdgeAppearance = appearance } else { // 回退到早期版本}
    【解决方案2】:

    为了实现您所希望的,最好的选择是创建一个自定义TabView

    事实上,在 SwiftUI 中,您可以使用 UITabBarAppearance().shadowColor,但除了在 TabView 本身顶部绘制一条 2px 的线之外,这并没有多大作用。

    相反,您可以使用以下代码创建自定义TabView 并实现所需的图形效果。

    import SwiftUI
    
    
    enum Tab {
        case borrow,ret,device,you
    }
    
    struct TabView: View {
        @Binding var tabIdx: Tab
        
        var body: some View {
            HStack {
                Group {
                    Spacer()
                    
                    Button (action: {
                        self.tabIdx = .borrow
                    }) {
                        VStack{
                            Image(systemName: "arrow.down.circle")
                            Text("Borrow")
                                .font(.system(size: 10))
                            
                        }
                    }
                    .foregroundColor(self.tabIdx == .borrow ? .purple : .secondary)
                    
                    Spacer()
                    
                    Button (action: {
                        self.tabIdx = .ret
                    }) {
                        VStack{
                            Image(systemName: "arrow.up.circle")
                            Text("Return")
                                .font(.system(size: 10))
                            
                        }
                    }
                    .foregroundColor(self.tabIdx == .ret ? .purple : .secondary)
                    
                    Spacer()
                    
                    Button (action: {
                        self.tabIdx = .device
                    }) {
                        VStack{
                            Image(systemName: "safari")
                            Text("Device")
                                .font(.system(size: 10))
                            
                        }
                    }
                    .foregroundColor(self.tabIdx == .device ? .purple : .secondary)
                    
                    Spacer()
                    
                    Button (action: {
                        self.tabIdx = .you
                    }) {
                        VStack{
                            Image(systemName: "person.circle")
                            Text("You")
                                .font(.system(size: 10))
                            
                        }
                    }
                    .foregroundColor(self.tabIdx == .you ? .purple : .secondary)
                    
                    Spacer()
                }
            }
            .padding(.bottom, 30)
            .padding(.top, 10)
            .background(Color(red: 0.95, green: 0.95, blue: 0.95))
            .font(.system(size: 30))
            .frame(height: 80)
        }
    }
    
    
    struct ContentView: View {
        @State var tabIdx: Tab = .borrow
        
        var body: some View {
            NavigationView {
                VStack(spacing: 20) {
                    Spacer()
                    
                    if tabIdx == .borrow {
                        Text("Borrow")
                    } else if tabIdx == .ret {
                        Text("Return")
                    } else if tabIdx == .device {
                        Text("Device")
                    } else if tabIdx == .you {
                        Text("You")
                    }
                    Spacer(minLength: 0)
                    TabView(tabIdx: self.$tabIdx)
                        .shadow(radius: 10)
                }
                .ignoresSafeArea()
                
            }
        }
        
    }
    

    请记住,当您执行此操作时,您的所有选项卡都被指定为 enum Tab {} 中的 case,并且 TabView() 包含一些 Button 元素,它们将使用 @State var tabIdx 更改选项卡。因此您可以通过修改self.tabIdx = <yourtab> 语句来调整您的操作。

    在每个按钮之后使用此语句设置活动颜色:

    .foregroundColor(self.tabIdx == .borrow ? .purple : .secondary)
    

    在这里,您可以将.purple 更改为适合您的任何内容。

    您可以看到在ContentView 上,if-else if 块捕获了 SubView。这里我放置了一些Text() 元素,比如Text("Borrow"),所以你可以通过调用BorrowView() 之类的东西来替换它们。

    当我从ContentView 中调用TabView 时,我添加了阴影,但您甚至可以在TabView 本身的HStack 之后添加.shadow(radius: 10)

    这将是最终输出

                     

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      • 1970-01-01
      相关资源
      最近更新 更多