градиент для многоуровневой UIBezierPath - PullRequest
0 голосов
/ 02 декабря 2018

Я должен создать это .Я выполнил поиск в Google, YouTube и StackOverflow, и приведенный ниже код является результатом моего исследования.

 @IBDesignable class TriangleView2: UIView {

override init(frame: CGRect) {
    super.init(frame: frame)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}
let gradient = CAGradientLayer()
override func draw(_ rect: CGRect) {

    //draw the line of UIBezierPath

    let path1 = UIBezierPath()
    path1.move(to: CGPoint(x: rect.minX - 100, y: rect.maxY - 80))
    path1.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
    path1.addLine(to: CGPoint(x: (rect.maxX + 90  ), y: rect.minY/2 ))
    path1.close()

    // add clipping path. this draws an imaginary line (to create bounds) from the
    //ends of the UIBezierPath line down to the bottom of the screen
    let clippingPath = path1.copy() as! UIBezierPath
    clippingPath.move(to: CGPoint(x: rect.minX - 100, y: rect.maxY - 80))
    clippingPath.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
    clippingPath.addLine(to: CGPoint(x: (rect.maxX + 90  ), y: rect.minY/2 ))
    clippingPath.close()

    clippingPath.addClip()

    // create and add the gradient
    let colors = [theme.current.profile_start_view1.cgColor, theme.current.profile_end_view1.cgColor]

    let colorSpace = CGColorSpaceCreateDeviceRGB()        
    let colorLocations:[CGFloat] = [0.0, 1.0]        
    let gradient = CGGradient(colorsSpace: colorSpace,
                              colors: colors as CFArray,
                              locations: colorLocations)

    let context = UIGraphicsGetCurrentContext()
    let startPoint = CGPoint(x: 1, y: 1)
    let endPoint = CGPoint(x: 1, y: bounds.maxY)
    // and lastly, draw the gradient.
    context!.drawLinearGradient(gradient!, start: startPoint, end: 
  endPoint, options: CGGradientDrawingOptions.drawsAfterEndLocation)
    }
}

верно, у меня нет 2 просмотров (будет 3, если я смогу завершить) с некоторыми отличиями,в результате this

эти 2 вида не имеют одинакового цвета, но, как вы можете видеть, оба вида имеют одинаковый градиент с одинаковым направлением

есть ли у кого-нибудьЛюбое предложение?

Ответы [ 3 ]

0 голосов
/ 02 декабря 2018

Вот пример, который вы можете запустить прямо на игровой площадке.

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

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

import UIKit
import PlaygroundSupport


class TriangleView2: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func draw(_ rect: CGRect) {

        let colors = [UIColor(red: 50/255.0, green: 242/255.0, blue: 111/255.0, alpha: 1).cgColor,
                      UIColor(red: 29/255.0, green: 127/255.0, blue: 60/255.0, alpha: 1).cgColor]
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let colorLocations:[CGFloat] = [0.0, 1.0]
        let gradient = CGGradient(colorsSpace: colorSpace,
                                  colors: colors as CFArray,
                                  locations: colorLocations)!
        let options: CGGradientDrawingOptions = [CGGradientDrawingOptions.drawsBeforeStartLocation, CGGradientDrawingOptions.drawsAfterEndLocation]

        let p1 = CGPoint(x: 0, y: 0)
        let p2 = CGPoint(x: bounds.width, y: 0)
        let p3 = CGPoint(x: bounds.width, y: 20)
        let p4 = CGPoint(x: bounds.width / 3, y: 140)
        let p5 = CGPoint(x: 0, y: 200)
        let p6 = CGPoint(x: bounds.width * 5 / 8, y: 260)
        let p7 = CGPoint(x: 0, y: 230)
        let p8 = CGPoint(x: bounds.width, y: 280)

        let context = UIGraphicsGetCurrentContext()!

        context.saveGState()
        let path1 = UIBezierPath()
        path1.move(to: p1)
        path1.addLine(to: p2)
        path1.addLine(to: p3)
        path1.addLine(to: p4)
        path1.close()
        path1.addClip()
        context.drawLinearGradient(gradient, start: p3, end: p1, options: options)
        context.restoreGState()

        context.saveGState()
        let path2 = UIBezierPath()
        path2.move(to: p1)
        path2.addLine(to: p4)
        path2.addLine(to: p5)
        path2.close()
        path2.addClip()
        context.drawLinearGradient(gradient, start: p1, end: p5, options: options)
        context.restoreGState()

        context.saveGState()
        let path3 = UIBezierPath()
        path3.move(to: p3)
        path3.addLine(to: p8)
        path3.addLine(to: p6)
        path3.addLine(to: p4)
        path3.close()
        path3.addClip()
        context.drawLinearGradient(gradient, start: p8, end: p3, options: options)
        context.restoreGState()

        context.saveGState()
        let path4 = UIBezierPath()
        path4.move(to: p5)
        path4.addLine(to: p4)
        path4.addLine(to: p6)
        path4.addLine(to: p7)
        path4.close()
        path4.addClip()
        context.drawLinearGradient(gradient, start: p7, end: p6, options: options)
        context.restoreGState()
    }
}

let main = TriangleView2(frame: CGRect(x: 0, y: 0, width: 320, height: 500))
PlaygroundPage.current.liveView = main

Обновление

Еще одна вещь: сделатьне используйте параметр rect для получения геометрии ваших фигур. rect не относится к размеру или положению вида.Вместо этого это область, которая должна быть перерисована.Если iOS решит, что нужно перерисовать только часть вашего представления, ваш код будет иметь неправильную форму.

0 голосов
/ 02 декабря 2018

Это немного похоже на ответ Кодо, но вам нужно всего 4 балла.

class FourGradientsView: UIView {
    override func draw(_ rect: CGRect) {
        let ctx = UIGraphicsGetCurrentContext()!

        // Points of area to draw - adjust these 4 variables as needed
        let tl = CGPoint(x: 0, y: 0)
        let tr = CGPoint(x: bounds.width * 1.3, y: 0)
        let bl = CGPoint(x: -bounds.width * 1.8, y: bounds.height * 1.4)
        let br = CGPoint(x: bounds.width * 1.3, y: bounds.height * 2)

        // Find the intersection of the two crossing diagonals
        let s1x = br.x - tl.x
        let s1y = br.y - tl.y
        let s2x = tr.x - bl.x
        let s2y = tr.y - bl.y
        //let s = (-s1y * (tl.x - bl.x) + s1x * (tl.y - bl.y)) / (-s2x * s1y + s1x * s2y)
        let t = ( s2x * (tl.y - bl.y) - s2y * (tl.x - bl.x)) / (-s2x * s1y + s1x * s2y)
        let center = CGPoint(x: tl.x + (t * s1x), y: tl.y + (t * s1y))

        // Create clipping region to avoid drawing where we don't want any gradients
        ctx.saveGState()
        let clip = CGPoint(x: 0, y: bounds.height * 0.7)
        let clipPath = UIBezierPath()
        clipPath.move(to: CGPoint(x: 0, y: 0))
        clipPath.addLine(to: clip)
        clipPath.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
        clipPath.addLine(to: CGPoint(x: bounds.width, y: 0))
        clipPath.close()
        clipPath.addClip()

        // Use these two colors for all 4 gradients (adjust as needed)
        let colors = [
            UIColor(hue: 120/360, saturation: 1, brightness: 0.85, alpha: 1).cgColor,
            UIColor(hue: 120/360, saturation: 1, brightness: 0.3, alpha: 1).cgColor
        ] as CFArray

        // The common gradient
        let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors, locations: nil)!

        // Top gradient
        ctx.saveGState()
        let pathTop = UIBezierPath()
        pathTop.move(to: tl)
        pathTop.addLine(to: tr)
        pathTop.addLine(to: center)
        pathTop.close()
        pathTop.addClip()

        ctx.drawLinearGradient(gradient, start: CGPoint(x: bounds.width, y: 0), end: CGPoint(x: 0, y: 0), options: [])
        ctx.restoreGState()

        // Right gradient
        ctx.saveGState()
        let pathRight = UIBezierPath()
        pathRight.move(to: tr)
        pathRight.addLine(to: br)
        pathRight.addLine(to: center)
        pathRight.close()
        pathRight.addClip()

        ctx.drawLinearGradient(gradient, start: CGPoint(x: bounds.width, y: bounds.height), end: CGPoint(x: bounds.width, y: 0), options: [])
        ctx.restoreGState()

        // Bottom gradient
        ctx.saveGState()
        let pathBottom = UIBezierPath()
        pathBottom.move(to: br)
        pathBottom.addLine(to: bl)
        pathBottom.addLine(to: center)
        pathBottom.close()
        pathBottom.addClip()

        ctx.drawLinearGradient(gradient, start: CGPoint(x: 0, y: bounds.height), end: CGPoint(x: bounds.width, y: bounds.height), options: [])
        ctx.restoreGState()

        // Left gradient
        ctx.saveGState()
        let pathLeft = UIBezierPath()
        pathLeft.move(to: tl)
        pathLeft.addLine(to: bl)
        pathLeft.addLine(to: center)
        pathLeft.close()
        pathLeft.addClip()

        ctx.drawLinearGradient(gradient, start: CGPoint(x: 0, y: 0), end: CGPoint(x: 0, y: bounds.height), options: [])
        ctx.restoreGState()

        ctx.restoreGState()
    }
}

let grView = FourGradientsView(frame: CGRect(x: 0, y: 0, width: 320, height: 320))
grView.backgroundColor = .black
0 голосов
/ 02 декабря 2018

Вы написали код, который всегда использует один и тот же начальный и конечный цвета, всегда использует одни и те же цвета и всегда использует одни и те же начальную и конечную точки.Конечно, градиенты имеют один и тот же градиент с одинаковым направлением.

Придайте своим свойствам начальную и конечную точки градиента вида, а также начальный и конечный цвета.Установите начальные точки градиента для градиентных видов в методе layoutDidChange() контроллера вида, основываясь на границах видов.(Таким образом вы правильно обрабатываете поворот устройства и устройства разных размеров.

...