web-dev-qa-db-fra.com

UIBezierPath: Comment ajouter une bordure autour d'une vue aux angles arrondis?

J'utilise UIBezierPath pour que mon imageview ait des coins arrondis, mais je souhaite également ajouter une bordure à l'imageview. Gardez à l'esprit que le haut est une uiimage et le bas est une étiquette.

L'utilisation actuelle de ce code produit:

let rectShape = CAShapeLayer()
rectShape.bounds = myCell2.NewFeedImageView.frame
rectShape.position = myCell2.NewFeedImageView.center
rectShape.path = UIBezierPath(roundedRect: myCell2.NewFeedImageView.bounds,
    byRoundingCorners: .TopRight | .TopLeft,
    cornerRadii: CGSize(width: 25, height: 25)).CGPath
myCell2.NewFeedImageView.layer.mask = rectShape

current

Je veux ajouter une bordure verte à cela, mais je ne peux pas utiliser

myCell2.NewFeedImageView.layer.borderWidth = 8
myCell2.NewFeedImageView.layer.borderColor = UIColor.greenColor().CGColor

car elle coupe le coin supérieur gauche et supérieur droit de la bordure, comme illustré dans cette image:

issue

Existe-t-il un moyen d’ajouter une bordure avec UIBezierPath avec mon code actuel?

14
gooberboobbutt

Vous pouvez réutiliser le chemin UIBezierPath et ajouter un calque de forme à la vue. Voici un exemple à l'intérieur d'un contrôleur de vue.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Create a view with red background for demonstration
        let v = UIView(frame: CGRectMake(0, 0, 100, 100))
        v.center = view.center
        v.backgroundColor = UIColor.redColor()
        view.addSubview(v)

        // Add rounded corners
        let maskLayer = CAShapeLayer()
        maskLayer.frame = v.bounds
        maskLayer.path = UIBezierPath(roundedRect: v.bounds, byRoundingCorners: .TopRight | .TopLeft, cornerRadii: CGSize(width: 25, height: 25)).CGPath
        v.layer.mask = maskLayer

        // Add border
        let borderLayer = CAShapeLayer()
        borderLayer.path = maskLayer.path // Reuse the Bezier path
        borderLayer.fillColor = UIColor.clearColor().CGColor
        borderLayer.strokeColor = UIColor.greenColor().CGColor
        borderLayer.lineWidth = 5
        borderLayer.frame = v.bounds
        v.layer.addSublayer(borderLayer)   
    }

}

Le résultat final ressemble à ceci.

 Simulator screenshot

Notez que cela ne fonctionne comme prévu que lorsque la taille de la vue est corrigée. Lorsque la vue peut être redimensionnée, vous devez créer une classe d'affichage personnalisée et redimensionner les calques dans layoutSubviews.

38
hennes

Comme je le commente ci-dessus, il est 

en fait, ce n'est pas facile de le faire absolument.

Voici la "solution OCD", il s'agit d'un code totalement inscriptible.


Voici un exemple complet. Ce

  • répond correctement/explique le problème qui se pose lorsque vous faites cela, vous tracez LA DEMI-LIGNE DE LA FRONTIÈRE

  • est totalement utilisable en autolayout

  • se remanie complètement lorsque la taille de la vue change ou s'anime

  • est totalement IBDesignable - vous pouvez le voir en temps réel dans votre story-board

pour 2017 ...

@IBDesignable
class RoundedCornersAndTrueBorder: UIView {
    @IBInspectable var cornerRadius: CGFloat = 10 {
        didSet { setup() }
    }
    @IBInspectable var borderColor: UIColor = UIColor.black {
        didSet { setup() }
    }
    @IBInspectable var trueBorderWidth: CGFloat = 2.0 {
        didSet { setup() }
    }

    override func layoutSubviews() {
        setup()
    }

    var border:CAShapeLayer? = nil

    func setup() {
        // make a path with round corners
        let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:cornerRadius)

        // note that it is >exactly< the size of the whole view

        // mask the whole view to that shape
        // note that you will ALSO be masking the border we'll draw below
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        self.layer.mask = mask

        // add another layer, which will be the border as such

        if (border == nil) {
            border = CAShapeLayer()
            self.layer.addSublayer(border!)
        }
        // IN SOME APPROACHES YOU would INSET THE FRAME
        // of the border-drawing layer by the width of the border
        // border.frame = bounds.insetBy(dx: borderWidth, dy: borderWidth)
        // so that when you draw the line, ALL of the WIDTH of the line
        // DOES fall within the actual mask.

        // here, we will draw the border-line LITERALLY ON THE Edge
        // of the path. that means >HALF< THE LINE will be INSIDE
        // the path and HALF THE LINE WILL BE OUTSIDE the path
        border!.frame = bounds
        let pathUsingCorrectInsetIfAny =
          UIBezierPath(roundedRect: border!.bounds, cornerRadius:cornerRadius)

        border!.path = pathUsingCorrectInsetIfAny.cgPath
        border!.fillColor = UIColor.clear.cgColor

        // the following is not what you want:
        // it results in "half-missing corners"
        // (note however, sometimes you do use this approach):
        //border.borderColor = borderColor.cgColor
        //border.borderWidth = borderWidth

        // this approach will indeed be "inside" the path:
        border!.strokeColor = borderColor.cgColor
        border!.lineWidth = trueBorderWidth * 2.0
        // HALF THE LINE will be INSIDE the path and HALF THE LINE
        // WILL BE OUTSIDE the path. so MAKE IT >>TWICE AS THICK<<
        // as requested by the consumer class.

    }
}

Aide débutant à la question ci-dessous ...

  1. Créez un "nouveau fichier Swift" appelé "Fattie.Swift". (Notez que cela ne change rien à votre façon de parler. Si vous en êtes au stade "je ne sais pas comment créer un nouveau fichier", recherchez des didacticiels Xcode de base.

  2. Mettez tout le code ci-dessus dedans

  3. Vous venez d'ajouter une classe "RoundedCornersAndTrueBorder" à votre projet.

  4. Sur votre story board. Ajoutez un UIView ordinaire à votre scène. Faites-en réellement n'importe quelle taille/forme que vous préférez.

  5. Dans l'inspecteur identity (recherchez un didacticiel de base si vous ne savez pas ce que c'est, c'est simple), changez simplement le cours en "RoundedCornersAndTrueBorder". (Une fois que vous aurez commencé à taper "Roun ...", il devinera de quelle classe vous parlez.

  6. Vous avez terminé, lancez le projet.

Notez que vous devez bien sûr ajouter des contraintes complètes à UIView, comme pour tout ce que vous faites dans Xcode. Prendre plaisir!

5
Fattie

Il est sûr! Chaque vue a une propriété layer (que vous connaissez en donnant à votre calque des angles arrondis). Les deux autres propriétés de layer sont borderColor et borderWidth. En les définissant, vous pouvez ajouter une bordure à votre vue! (La bordure suivra les coins arrondis.) Assurez-vous d'utiliser UIColor.CGColor pour borderColor car un UIColor ordinaire ne correspondra pas au type.

0
Clay Ellis