Как сохранить кортеж для NSGradient (colorsAndLocations:) в Swift

Чтобы применить градиент к NSView, лучше всего создать класс, наследуемый от NSView, и переопределить метод рисования, который задает путь и рисует градиент.

class GradientView: NSView {

var startColor = NSColor.red
var startPosition: CGFloat = 0
var endColor = NSColor.white
var endPosition: CGFloat = 1
var rotation: CGFloat = 0


override func draw(_ dirtyRect: NSRect) {
    super.draw(dirtyRect)

    let bgGradient = NSGradient(colorsAndLocations: (startColor, startPosition), (endColor, endPosition))
    let path = NSBezierPath.init(rect: self.bounds)
    bgGradient?.draw(in: path, angle: rotation)
}
}

(Дайте мне знать, если есть лучший/более простой способ...)

Это прекрасно работает, но теперь я хочу отправить собственную коллекцию цветов и цветовых остановок. Примечание. *С помощью этого вышеприведенного метода я ограничен определением только двух (startColor и startPosition и endColor и endPosition).

Я хотел бы использовать (массив?) кортежей (содержащих несколько цветов и их стоп-значения). API для установки цвета и местоположения — NSGradient(colorsAndLocations:) и использует кортеж (NSColor, CGFloat).

Я могу добавить такой параметр, как var colorStopArray: [(color: NSColor, stop: CGFloat)] = [], который создает массив (таких) кортежей. Также я могу добавлять значения с помощью: colorStopArray.append((startColor, startPosition)).

Но как я могу назначить это API?

Я пробовал много методов, и все они вызывают ошибки (например, пробовал NSGradient(colorsAndLocations: colorStopArray.flatMap{return ($0.color, $0.stop)}) )

Итак, как можно отправить много пользовательских цветов и местоположений в вышеуказанный класс (или, надеюсь, лучшее предложение) для создания пользовательского градиента (который затем будет отображаться в моем NSView)?


person Yuma Technical Inc.    schedule 26.08.2020    source источник
comment
@matt Ты действительно можешь помочь? Предложение кода хорошее...   -  person Yuma Technical Inc.    schedule 26.08.2020
comment
Непонятно даже в чем проблема. Вы можете объяснить?   -  person matt    schedule 26.08.2020
comment
Примечание: пользовательские представления, которые непосредственно являются подклассами NSView, не должны вызывать super для draw(_:).   -  person liquid    schedule 26.08.2020


Ответы (2)


С помощью этого вышеприведенного метода я ограничен определением только двух (startColor и startPosition и endColor и endPosition).

Нет, это не так. Это вариатив; вы можете добавить столько кортежей, сколько пожелаете. Это отлично работает:

let startColor = NSColor.red
let startPosition: CGFloat = 0
let middleColor = NSColor.blue
let middlePosition: CGFloat = 0.5
var endColor = NSColor.white
var endPosition: CGFloat = 1
let bgGradient = NSGradient(colorsAndLocations: 
    (startColor, startPosition), 
    (middleColor, middlePosition), 
    (endColor, endPosition))

Если вопрос в том, могу ли я превратить массив в переменную?, то ответ, к сожалению, нет. Эта функция (разбрызгивание) отсутствует в языке Swift. Единственный способ вызвать variadic в Swift — это variadic.

Инициализатор, который позволяет указать массив цветов и мест остановки, называется init(colors:atLocations:colorSpace:). Поэтому, если это то, что вы хотите предоставить, вместо этого вызовите этот инициализатор.

person matt    schedule 26.08.2020

Используя подсказки Мэтта, я заменил строку let (используя более подходящий API init(colors:atLocations:colorSpace:)):

let bgGradient = NSGradient(colorsAndLocations: (startColor, startPosition), (endColor, endPosition))

с участием

let bgGradient = NSGradient(colors: colorStopArray.map { $0.color }, atLocations: colorStopArray.map { $0.stop }, colorSpace: NSColorSpace.genericRGB)

Теперь он работает так, как я хотел.

person Yuma Technical Inc.    schedule 26.08.2020
comment
@matt Вы упоминали о сопоставлении внутренних компонентов? Пожалуйста, не расстраивайтесь, я дал ответ, который включает ваше имя. Теперь, если кто-то с одним и тем же запросом, может получить ряд решений с разных точек зрения. Я считаю, что одной из целей StackOverflow является продвижение методов кодирования с обменом мнениями. - person Yuma Technical Inc.; 26.08.2020