Небольшое всплывающее окно соглашения в SwiftUI

Мне нужно обеспечить пользовательское соглашение с политиками приложения и ссылку на эти политики в том же маленьком всплывающем окне, в котором запрашивается пользовательское соглашение.

Я подумал, что смогу использовать обычное оповещение:

return Alert(title: Text("Agreements Confirmation"), message: Text("\nIn order to use the app you need to agree with our policies"), primaryButton: .default(Text("Agree")) {

              //Let the user access                                                                    
           }
                                                        
 }, secondaryButton: .cancel(Text("Reject")))

Но похоже, что вы вообще не можете использовать ссылки в предупреждениях.

Я всегда могу использовать .sheet или .popover, но это просто не соответствует нормативным требованиям небольшого окна, в котором размещается текст очень ограниченной длины.

Как я могу создать небольшое всплывающее окно, которое может содержать ссылку и две кнопки для «Принять» и «Отклонить» в SwiftUI?


person ChesterK2    schedule 16.11.2020    source источник


Ответы (1)


использовать настраиваемое оповещение

struct MyAlertView<Presenting>: View where Presenting: View {

@Binding var isShowing: Bool
    
    let presenting: () -> Presenting
    
    var message: String
    var url: URL
    var onAcceptClicked: () -> Void
    
    var body: some View {
        GeometryReader { geometry in
            self.presenting()
                .blur(radius: self.isShowing ? 4 : 0)
                .disabled(self.isShowing)
            
            HStack {
                Spacer()
                VStack (alignment: .center) {
                    Spacer()
                        .frame(width: 0, height: 120)
                    
                    VStack (alignment: .center, spacing: 2){
                        Image(systemName: "doc")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 20, height: 20)
                            .offset(x: 0, y: 35)
                            .zIndex(1)
                        MyLink(message: message, url: url)
                            .padding()
                            .background(Rectangle().foregroundColor(.white).cornerRadius(15).opacity(1))
                            .padding(30)
                            .shadow(radius: 8)
                        
                    }
                    VStack {
                        Button(action: self.accept){
                            Text("Accept", comment: "")
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
                        }
                        Divider()
                            .frame(height: 1)
                        Button(action: {
                                isShowing.toggle()
                        }){
                            Text("cancel", comment: "")
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
                        }
                    }
                    .frame(maxWidth: geometry.size.width * 0.60, maxHeight: 100)
                    .background(Rectangle().foregroundColor(.white).cornerRadius(15).opacity(1))
                    .shadow(radius: 8)
                    Spacer()
                }
                Spacer()
            }
            .contentShape(Rectangle())//per far cliccare anche al centro
            //.offset(x: 0, y: -60)
            .opacity(self.isShowing ? 1 : 0)
            .onTapGesture {
                self.isShowing.toggle()
            }
        }
        
    }
    
    func accept() {
        onAcceptClicked()
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: {
            self.isShowing.toggle()
        })
        
    }
}

extension View {
    func myAlertView(isShowing: Binding<Bool>, message: String, url:URL, onAcceptClicked: @escaping () -> Void) -> some View {
        MyAlertView(isShowing: isShowing, presenting: { self }, message: message, url: url, onAcceptClicked: onAcceptClicked)
           
    }
}
struct TestView: View {
            
    @State var isShowing: Bool = false
    
    var body: some View {
                          
        Button("click me") {
            isShowing.toggle()
        }
        .myAlertView(isShowing: $isShowing, message: "link message", url: URL(string: "https://www.google.com")!, onAcceptClicked: {
        print("Agreements accepted")})
           
    }

   
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
    }
}

public struct MyLink: View {
    
    var message: String
    var url: URL
    
    public var body: some View {
        if #available(iOS 14.0, *) {
            Link(message, destination: url)
        } else {
            Text(message)
                .foregroundColor(.blue)
                .underline()
                .onTapGesture {
                    UIApplication.shared.open(url)
                }
            
        }
    }
    }
person Simone Pistecchia    schedule 16.11.2020
comment
У меня это не работает, я использую SwiftUI 1 для поддержки устройств iOS 13. Это мешает расположению элементов управления представления хостинга (даже если сообщение еще не представлено). Кроме того, окно выскакивает в правом нижнем углу экрана. - person ChesterK2; 16.11.2020
comment
Пришлось убрать .modifier(fillButtonCircle(foregroundColor: .white, backgroundColor: .blue, размерность: 15)) и использовать Button(self.message){UIApplication.shared.open(self.url)} вместо Link, но я не уверен, что это причина - person ChesterK2; 16.11.2020
comment
пожалуйста, проверьте новую структуру MyLink, чтобы иметь поддержку iOS 13 - person Simone Pistecchia; 20.11.2020