SwiftUI: ViewModifier, где контент - это форма

Следующий код работает нормально. Так что, действительно, у меня все хорошо ... Но я хотел узнать о ViewModifiers ... поэтому моя цель - отделить неизменяемый материал от динамического, чтобы создать настраиваемый .cardify () модификатор для вызова представлений форм.

struct SetCard: View {
    
    let pips: Int
    let shape: SetCardShape
    let color: Color
    let shading: Double
    let isSelected: Bool
    
    var body: some View {
        
        ZStack {
            VStack {
                ForEach( 0..<pips ) { _ in
                    ZStack {
                        getShape(self.shape).opacity(self.shading).foregroundColor(self.color)
                        getShape(self.shape).stroke().foregroundColor(self.color)
                    }
                }
            }
            .padding() // for shape in RoundedRect
            RoundedRectangle(cornerRadius: 10).stroke(lineWidth: isSelected ? 3.0 : 1.0).foregroundColor(.orange)
        }
        .scaleEffect(isSelected ? 0.60 : 1.0 )
        .padding() // for spacing between cards 
    }
}

Опять же, по академическим / учебным причинам я хотел упростить эту структуру и использовать настраиваемый модификатор для преобразования основного содержимого в стандартную карточку.

Приведенный ниже блок кода работает только тогда, когда я закомментировал вторую content строку в структуре Cardify ViewModifier. Все карты, которые использовали закрашенные фигуры для точек, отображаются нормально. Карточки, которые требуют обводки формы (т. Е. Не заполнения), нуждаются в этом втором content в моем Cardify ViewModifer для работы.

Вторая строка содержимого выдает ошибку:

Значение типа Cardify.Content (также известное как _ViewModifier_Content) не имеет члена foregroundColor.

комментирование .foregroundColor () вызывает ошибку: значение типа Cardify.Content (также известное как _ViewModifier_Content) не имеет обводки элемента

struct SetCardWithCardify: View {
    
    let pips: Int
    let shape: SetCardShape
    let color: Color
    let shading: Double
    let isSelected: Bool
    
    var body: some View {
        ZStack {
            getShape(shape)
            .modifier(Cardify(pips: pips, shape: shape, color: color, shading: shading, isSelected: isSelected))
        }
    .scaleEffect(isSelected ? 0.60 : 1.0 )
        .padding() // for spacing between cards 
    }
}


struct Cardify: ViewModifier {
    
    var pips: Int
    var shape: SetCardShape
    var color: Color
    var shading: Double
    var isSelected: Bool
    
    func body(content: Content)  -> some View {
    
        ZStack {
            VStack {
                ForEach( 0..<pips ) { _ in
                    ZStack {
                        content.opacity(self.shading).foregroundColor(self.color)
                        content.stroke().foregroundColor(self.color)
                    }
                }
            }
            .padding() // for shape in RoundedRect
            RoundedRectangle(cornerRadius: 10).stroke(lineWidth: isSelected ? 3.0 : 1.0).foregroundColor(.orange)
        }
    }
}

На всякий случай, если это важно, следующий код является источником getShape(), который является источником content в Cardify ViewModifier.

func getShape(_ shape: SetCardShape ) -> some Shape {
    switch shape {
    case .circle:
        return AnyShape( Circle() )
    case .diamond:
        return AnyShape( SetDiamond() )
    case .squiggle:
        return AnyShape( SetSquiggle() )
    }
}


struct AnyShape: Shape {
    
    func path(in rect: CGRect) -> Path {
        return _path(rect)
    }
    
    init<S: Shape>(_ wrapped: S) {
        _path = { rect in
            let path = wrapped.path(in: rect)
            return path
        }
    }
    private let _path: (CGRect) -> Path
}

Diamond () и Squiggle () - это структуры, которые соответствуют протоколу Shape, правильно возвращая путь из `func path (в rect: CGRect) -› Path в этих структурах.

Я попытался снизить вторую строку контента с помощью:

(content as! Shape).blah blah blah, который вызывает ошибку:

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

Я также пробовал:

(content as! Path)

Это не генерирует никаких ошибок времени компиляции, но при его выполнении происходит сбой с ошибкой:

Во время работы возникла проблема, проверьте свой код на наличие ошибок в этой строке. (с указанием второй строки содержимого).

Что я могу сделать, чтобы компилятор узнал, какой это тип содержимого, и что stroke () и foregroundColor () будут работать?


person RichWalt    schedule 01.07.2020    source источник


Ответы (1)


Я не уверен, что вы можете, но вы можете приблизиться к этому, используя расширение Shape:

extension Shape {
    func modified() -> some View {
        self
            .foregroundColor(Color.secondary.opacity(0.5))
    }
}

// Usage example
struct ContentView: View {
    var body: some View {
        VStack {
            Rectangle().modified()
            Capsule().modified()
        }
    }
}

Однако, в отличие от модификатора представления, вы не можете получить доступ к среде, поэтому она несколько ограничена.

person Wil Gieseler    schedule 11.09.2020