SwiftUI добавление персонального представления оповещений в NavigationView, кнопка «Назад» не работает с Xcode 12 iOS14

#swift #swiftui #ios14

#swift #swiftui #ios14

Вопрос:

У меня есть расширение (.alertLinearProgressBar), подобное представлению .alert, для отображения хода распаковки. Раньше 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!
        }
    }
}
  

Ответ №1:

Похоже, что ваш AlertLinearProgressBar even с непрозрачностью, установленной на 0 блокировку панели навигации.

Вы можете видеть, что положение наложения, когда оно скрыто, находится в верхнем левом углу и перекрывается с панелью навигации (попробуйте настроить .opacity(self.isShowing ? 1 : 0.5) ).

Что вы можете сделать, так это действительно скрыть его с hidden помощью модификатора.

Вот возможное решение с использованием модификатора if:

 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) {
                $0.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 {
                // ...
            }
        }
    }
}
  

Комментарии:

1. вы поняли, с непрозрачностью 0,5 предупреждение отображается в верхнем левом углу представления и закрывает кнопку. Спасибо, чувак