SwiftUI 在 NavigationView 中添加个人警报视图,后退按钮不适用于 Xcode 12 iOS14

SwiftUI adding personal alert view in NavigationView, the back button doesn't work with Xcode 12 iOS14

我有一个类似于 .alert 视图的扩展 (.alertLinearProgressBar) 来显示解压缩进度。 在 iOS 14 运行良好之前,现在如果我发出此警报,导航后退按钮将不再起作用(如果我向右拖动,它会起作用并返回列表,所以我想问题是与后退按钮栏冲突,只有那个按钮不起作用,顶部栏中的其他按钮有效。

有人知道这个问题吗?

import SwiftUI

var chatData = ["1","2","3","4"]

struct ContentView: View {
    
    @State private var selection = 0
    @State private var isShowingAlert = false
    
    var body: some View {
        TabView (selection: $selection) {
            NavigationView {
                ZStack (alignment: .bottom) {
                
                    MasterView()
                        .navigationBarTitle(Text("Chat"))
                        .navigationBarItems(
                            leading: EditButton(),
                            trailing: Button(
                                action: {
                                //
                            }
                        ) {
                            Image(systemName: "plus.circle")
                            .contentShape(Rectangle())
                        })
                        .background(Color.clear)
                }
            }
            //IF I comment this line below, the navigation is working well
            .alertLinearProgressBar(isShowing: self.$isShowingAlert, progressValue: .constant(0.5), barHeight: 8, loadingText: .constant(""), titleText: .constant(NSLocalizedString("unzipping", comment: "")),isShowingActivityIndicator: .constant(true)).offset(x: 0, y: 1)
        }
    }
}

struct MasterView: View {
    
    
    var body: some View {
        ZStack {
            List {
                ForEach(chatData, id: \.self) { chat in
                    NavigationLink(
                        destination:
                        //Test2()
                            DetailView(text: chat)
                    ) {
                        ChatRow(text: chat)//, progressValue: self.$progressValue)
                    }
                    
                }
            }
        }
    }
}
struct ChatRow: View {
    
    var text: String
    
    var body: some View {
        Text(text)
    }
}
struct DetailView: View {
    
    var text: String
    
    var body: some View {
        Text(text)
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
struct AlertLinearProgressBar<Presenting>: View where Presenting: View {

    @Binding var isShowing: Bool
    @Binding var progressValue:Float
    @State var barHeight: Int
    @Binding var loadingText: String
    @Binding var titleText: String
    
    
    @Binding var isShowingProgressBar: Bool
    @Binding var isShowingActivityIndicator: Bool
    
    let presenting: () -> Presenting
    
    var body: some View {

        GeometryReader { geometry in

            self.presenting()
                .blur(radius: self.isShowing ? 2 : 0).offset(y:1)
                .disabled(self.isShowing)
            
            ZStack {
                Rectangle()
                    .frame(width: geometry.size.width * 0.8,
                           height: self.titleText == "" ? 70:100)
                .foregroundColor(Color.white)
                .cornerRadius(15)
                .shadow(radius: 20)
                .overlay(
                    GeometryReader { geometry in
                        VStack {
                            if self.titleText != "" {
                                Text(self.titleText)
                                    .bold()
                                    .offset(x: 0, y: 0)
                                    .padding(EdgeInsets(top: 4, leading: 0, bottom: 0, trailing: 0))
                            }
                            HStack {
                                Text("\(self.loadingText) " + "\(self.isShowingProgressBar ? self.progressValue.getPercentage(to: 1):"")")
                                    .font(.caption)
                                ActivityIndicator(isAnimating: .constant(true), isShowing: self.$isShowingActivityIndicator, style: .medium)
                            }
                            //.font(.system(size: 13))
                            Spacer()
                                .frame(height:6)
                            ZStack(alignment: .leading) {
                                Rectangle()
                                    .frame(width: geometry.size.width, height: CGFloat(self.barHeight))
                                    .opacity(0.3)
                                    .foregroundColor(Color(UIColor.systemTeal))
                                    .cornerRadius(5.0)
                                Rectangle()
                                    .frame(width: min(CGFloat(self.progressValue)*geometry.size.width, geometry.size.width), height: CGFloat(self.barHeight))
                                    .foregroundColor(Color.blue)
                                    .animation(.linear)
                                    .cornerRadius(5.0)
                            }.opacity(self.isShowingProgressBar ? 1 : 0)
                        }
                        
                    }
                    .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15))
                )
                .padding()
            }
            .frame(width: self.isShowing ? geometry.size.width:0,
                   height: self.isShowing ? geometry.size.height:0)
            .transition(.slide)
            .opacity(self.isShowing ? 1 : 0)
        }
    }
    
    
}
extension Float {
    //number of decimal
    func round(to places: Int) -> Float {
        let divisor = pow(10.0, Float(places))
        return (self * divisor).rounded() / divisor
    }
    func getPercentage(to digits: Int) -> String {
        if self >= 1 {
            return String(Int(self * 100)) + "%"
        }
        return String(format: "%.\(digits)f", self * 100) + "%"
    }
}

extension View {
    func alertLinearProgressBar(isShowing: Binding<Bool>,
                        progressValue: Binding<Float>,
                        barHeight: Int, loadingText: Binding<String>, titleText: Binding<String>=Binding.constant(""), isShowingProgressBar: Binding<Bool>=Binding.constant(true), isShowingActivityIndicator:Binding<Bool>=Binding.constant(false)) -> some View {
        AlertLinearProgressBar(isShowing: isShowing, progressValue: progressValue, barHeight: barHeight, loadingText: loadingText, titleText: titleText, isShowingProgressBar: isShowingProgressBar, isShowingActivityIndicator:isShowingActivityIndicator, presenting: {self})
    }
}

struct ActivityIndicator: UIViewRepresentable {

    @Binding var isAnimating: Bool
    @Binding var isShowing: Bool
    
    let style: UIActivityIndicatorView.Style
    var color:UIColor?
    
    func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView {
        return UIActivityIndicatorView(style: style)
    }

    func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) {
        isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
        uiView.isHidden = isShowing ? false:true
        if color != nil {
            uiView.color = color!
        }
    }
}

看起来您的 AlertLinearProgressBar 即使将不透明度设置为 0 也会阻塞 NavigationBar。

可以看到叠加层隐藏时的位置在左上角,与导航栏重叠(尝试设置.opacity(self.isShowing ? 1 : 0.5))。

你能做的就是用 hidden 修饰符真正隐藏它。

这是一个可能的解决方案,使用 if modifier:

struct AlertLinearProgressBar<Presenting>: View where Presenting: View {
    // ...

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                // ...
            }
            .frame(width: self.isShowing ? geometry.size.width : 0,
                   height: self.isShowing ? geometry.size.height : 0)
            .transition(.slide)
            .opacity(self.isShowing ? 1 : 0.5)
            .if(!isShowing) {
                [=10=].hidden() // use `hidden` here
            }
        }
    }
}
extension View {
    @ViewBuilder func `if`<T>(_ condition: Bool, transform: (Self) -> T) -> some View where T: View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
}

或者,您也可以有条件地显示视图:

struct AlertLinearProgressBar<Presenting>: View where Presenting: View {
    //...
    
    var body: some View {
        GeometryReader { geometry in
            self.presenting()
                .blur(radius: self.isShowing ? 2 : 0).offset(y: 1)
                .disabled(self.isShowing)

            if isShowing {
                // ...
            }
        }
    }
}