iOS Progettare e disegnare un percorso di Bezier

Esempio

Questo esempio mostra il processo dalla progettazione della forma che si desidera disegnare su una vista. Viene usato uno shap specifico ma i concetti che impari possono essere applicati a qualsiasi forma.

Come disegnare un tracciato di Bézier in una vista personalizzata

Questi sono i passaggi principali:

  1. Progetta il contorno della forma che desideri.
  2. Dividere il tracciato del contorno in segmenti di linee, archi e curve.
  3. Costruisci quel percorso a livello di codice.
  4. Disegna il percorso in drawRect o utilizzando un CAShapeLayer .

Disegna il contorno della forma

Potresti fare qualsiasi cosa, ma come esempio ho scelto la forma qui sotto. Potrebbe essere un tasto popup su una tastiera.

inserisci la descrizione dell'immagine qui

Dividere il percorso in segmenti

Osserva il design della tua forma e scomporlo in elementi di linee più semplici (per linee rette), archi (per cerchi e angoli arrotondati) e curve (per qualsiasi altra cosa).

Ecco come sarà il nostro esempio di design:

inserisci la descrizione dell'immagine qui

  • Il nero sono segmenti di linea
  • Blu chiaro sono segmenti di arco
  • Il rosso sono curve
  • I punti arancioni sono i punti di controllo per le curve
  • I punti verdi sono i punti tra i segmenti del percorso
  • Le linee tratteggiate mostrano il rettangolo di delimitazione
  • I numeri blu scuro sono i segmenti nell'ordine in cui verranno aggiunti a livello di codice

Costruisci il percorso a livello di programmazione

Iniziamo arbitrariamente nell'angolo in basso a sinistra e lavoriamo in senso orario. Userò la griglia nell'immagine per ottenere i valori xey per i punti. Farò un hardcode di tutto qui, ma ovviamente non lo faresti in un vero progetto.

Il processo di base è:

  1. Creare un nuovo UIBezierPath
  2. Scegli un punto di partenza sul percorso con moveToPoint
  3. Aggiungi segmenti al percorso
  • linea: addLineToPoint
  • arc: addArcWithCenter
  • curva: addCurveToPoint
  1. Chiudi il percorso con closePath

Ecco il codice per rendere il percorso nell'immagine sopra.

func createBezierPath() -> UIBezierPath {
    
    // create a new path
    let path = UIBezierPath()
    
    // starting point for the path (bottom left)
    path.moveToPoint(CGPoint(x: 2, y: 26))
    
    // *********************
    // ***** Left side *****
    // *********************
    
    // segment 1: line
    path.addLineToPoint(CGPoint(x: 2, y: 15))
    
    // segment 2: curve
    path.addCurveToPoint(CGPoint(x: 0, y: 12), // ending point
        controlPoint1: CGPoint(x: 2, y: 14),
        controlPoint2: CGPoint(x: 0, y: 14))
    
    // segment 3: line
    path.addLineToPoint(CGPoint(x: 0, y: 2))
    
    // *********************
    // ****** Top side *****
    // *********************
    
    // segment 4: arc
    path.addArcWithCenter(CGPoint(x: 2, y: 2), // center point of circle
        radius: 2, // this will make it meet our path line
        startAngle: CGFloat(M_PI), // π radians = 180 degrees = straight left
        endAngle: CGFloat(3*M_PI_2), // 3π/2 radians = 270 degrees = straight up
        clockwise: true) // startAngle to endAngle goes in a clockwise direction
    
    // segment 5: line
    path.addLineToPoint(CGPoint(x: 8, y: 0))
    
    // segment 6: arc
    path.addArcWithCenter(CGPoint(x: 8, y: 2),
        radius: 2,
        startAngle: CGFloat(3*M_PI_2), // straight up
        endAngle: CGFloat(0), // 0 radians = straight right
        clockwise: true)
    
    // *********************
    // ***** Right side ****
    // *********************
    
    // segment 7: line
    path.addLineToPoint(CGPoint(x: 10, y: 12))
    
    // segment 8: curve
    path.addCurveToPoint(CGPoint(x: 8, y: 15), // ending point
        controlPoint1: CGPoint(x: 10, y: 14),
        controlPoint2: CGPoint(x: 8, y: 14))
    
    // segment 9: line
    path.addLineToPoint(CGPoint(x: 8, y: 26))
    
    // *********************
    // **** Bottom side ****
    // *********************
    
    // segment 10: line
    path.closePath() // draws the final line to close the path
    
    return path
}

Nota: alcuni dei codici precedenti possono essere ridotti aggiungendo una linea e un arco in un singolo comando (poiché l'arco ha un punto di partenza implicito). Vedi qui per maggiori dettagli.

Disegna il percorso

Possiamo tracciare il percorso sia in layer che in drawRect .

Metodo 1: traccia il percorso in un livello

La nostra classe personalizzata sembra così. Aggiungiamo il nostro percorso Bezier a un nuovo CAShapeLayer quando la vista è inizializzata.

import UIKit
class MyCustomView: UIView {

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

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    
    func setup() {
        
        // Create a CAShapeLayer
        let shapeLayer = CAShapeLayer()
        
        // The Bezier path that we made needs to be converted to 
        // a CGPath before it can be used on a layer.
        shapeLayer.path = createBezierPath().CGPath
        
        // apply other properties related to the path
        shapeLayer.strokeColor = UIColor.blueColor().CGColor
        shapeLayer.fillColor = UIColor.whiteColor().CGColor
        shapeLayer.lineWidth = 1.0
        shapeLayer.position = CGPoint(x: 10, y: 10)
        
        // add the new layer to our custom view
        self.layer.addSublayer(shapeLayer)
    }

    func createBezierPath() -> UIBezierPath {
        
        // see previous code for creating the Bezier path
    }
}

E creando la nostra vista nel View Controller come questo

override func viewDidLoad() {
    super.viewDidLoad()
    
    // create a new UIView and add it to the view controller
    let myView = MyCustomView()
    myView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
    myView.backgroundColor = UIColor.yellowColor()
    view.addSubview(myView)
    
}

Noi abbiamo...

inserisci la descrizione dell'immagine qui

Hmm, è un po 'piccolo perché ho codificato tutti i numeri. Posso ridimensionare la dimensione del percorso, però, in questo modo:

let path = createBezierPath()
let scale = CGAffineTransformMakeScale(2, 2)
path.applyTransform(scale)
shapeLayer.path = path.CGPath

inserisci la descrizione dell'immagine qui

Metodo 2: tracciare il percorso in drawRect

L'uso di drawRect è più lento del disegno sul livello, quindi questo non è il metodo raccomandato se non ne hai bisogno.

Ecco il codice revisionato per la nostra visualizzazione personalizzata:

import UIKit
class MyCustomView: UIView {
    
    override func drawRect(rect: CGRect) {
        
        // create path (see previous code)
        let path = createBezierPath()
        
        // fill
        let fillColor = UIColor.whiteColor()
        fillColor.setFill()
        
        // stroke
        path.lineWidth = 1.0
        let strokeColor = UIColor.blueColor()
        strokeColor.setStroke()
        
        // Move the path to a new location
        path.applyTransform(CGAffineTransformMakeTranslation(10, 10))
        
        // fill and stroke the path (always do these last)
        path.fill()
        path.stroke()
        
    }
    
    func createBezierPath() -> UIBezierPath {
        
        // see previous code for creating the Bezier path
    }
}

che ci dà lo stesso risultato ...

inserisci la descrizione dell'immagine qui

Ulteriore studio

Articoli eccellenti per comprendere i percorsi di Bezier.

Gli appunti

  • Questo esempio deriva originariamente da questa risposta di Overflow dello stack .
  • Nei tuoi progetti attuali probabilmente non dovresti usare numeri codificati, ma piuttosto prendere le dimensioni dai limiti della tua vista.