Как передать фигуру SwiftUI в качестве аргумента

#swift #swift-package-manager #swift5.5

Вопрос:

Я создаю пакет Swift, который будет отображать некоторый текст в течение определенного времени (например, реализация тостов). Я хочу, чтобы у пользователя была возможность указать фоновую форму при вызове элемента, но когда я просто пытаюсь создать параметр формы, я получаю ошибку компиляции в строке объявления (ошибка 1).:

Протокол «Форма» может использоваться только в качестве общего ограничения, поскольку он имеет собственные или связанные требования к типу

и где я пытаюсь его использовать (ошибка 2):

Форма протокола как тип не может соответствовать самому протоколу

 import SwiftUI

public struct Toast: View {
    
    @Binding var show: Bool

    var message: String = ""
    var duration: Double = 2.0
    var fontSize: Font = .title
    var textColor: Color = Color(.secondaryLabel)
    var backgroundColor : Color = Color (.clear)
    var encapsulate: Bool = false
    var shape: Shape = Capsule() //Error 1
    
    public init(show: Binding<Bool>,
                message: String,
                duration: Double = 2.0,
                fontSize: Font = .title,
                textColor: Color = Color(.secondaryLabel),
                backgroundColor: Color = Color (.clear),
                encapsulate: Bool = false,
                shape: Shape = Capsule()) { //same as error 1
        
        self._show = show
        self.message = message
        self.duration = duration
        self.fontSize = fontSize
        self.textColor = textColor
        self.backgroundColor = backgroundColor
        self.encapsulate = encapsulate
        self.shape = shape
    }
    
    
    public var body: some View {
        Text(message)
            .font(fontSize)
            .foregroundColor(textColor)
            .padding(.horizontal)
            .padding(.vertical, 2.0)
            .background(backgroundColor)
            .if(encapsulate, transform: { view in
                view.clipShape(shape) //error 2
            })
            .onAppear(){
                DispatchQueue.main.asyncAfter(deadline: .now()   duration) {
                    show = false
                }
            }
    }

}

public extension View {
    /// Applies the given transform if the given condition evaluates to `true`.
    /// - Parameters:
    ///   - condition: The condition to evaluate.
    ///   - transform: The transform to apply to the source `View`.
    /// - Returns: Either the original `View` or the modified `View` if the condition is `true`.
    @ViewBuilder func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
}
 

Я видел другие сообщения с ошибками такого типа, в которых используются @ViewBuilders, но я, похоже, не могу понять, как это реализовать здесь, если это действительно решение.

Любая помощь будет признательна.

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

1. Использовать Shape расширение вместо View расширения?

Ответ №1:

Вот необходимые изменения, чтобы он работал:

Для объявления класса:

 public struct Toast<Content: Shape>: View { ... }
 

Для декларации имущества:

 var shape: Content 
 

Для инициализации декларации:

 shape: Content
 

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

1. Также обратите внимание, что использование условного модификатора не является хорошей идеей: objc.io/blog/2021/08/24/conditional-view-modifiers

2. Спасибо! Похоже, это сделало свое дело.