Ajouter une bordure en dehors d'un UIView (au lieu de l'intérieur)

Si un append une bordure d'une vue en utilisant le code dans une vue comme

self.layer.borderColor = [UIColor yellowColor].CGColor; self.layer.borderWidth = 2.0f; 

la bordure est ajoutée à l'intérieur de la vue comme suit: entrez la description de l'image ici

la vue de droite est la vue originale, comme vous pouvez le voir, la zone noire de la vue encadrée est inférieure à celle d'origine. mais ce que je veux get est une bordure en dehors de la vue originale, comme ceci: entrez la description de l'image ici . la zone noire est égale à celle d'origine, comment puis-je l'implémenter?

    Malheureusement, il n'y a pas simplement une petite propriété que vous pouvez définir pour aligner la bordure à l'extérieur. Il dessine aligné à l'intérieur parce que les opérations de dessin par défaut UIViews dessiner dans ses limites.

    La solution la plus simple qui vient à l'esprit serait d'étendre l'UIView par la taille de la largeur de la bordure lors de l'application de la bordure:

     CGFloat borderWidth = 2.0f; self.frame = CGRectInset(self.frame, -borderWidth, -borderWidth); self.layer.borderColor = [UIColor yellowColor].CGColor; self.layer.borderWidth = borderWidth; 

    Eh bien, il n'y a pas de méthode directe pour le faire. Vous pouvez envisager quelques solutions de contournement.

    1. Changez et augmentez le cadre et ajoutez bordercolor comme vous l'avez fait
    2. Ajouter une vue derrière la vue actuelle avec la plus grande taille afin qu'elle apparaisse comme bordure.Peut être travaillé comme une class de vue personnalisée
    3. Si vous n'avez pas besoin d'une bordure définie (bordure de séparation), vous pouvez dépendre de l'ombre pour le but

       [view1 setBackgroundColor:[UIColor blackColor]]; UIColor *color = [UIColor yellowColor]; view1.layer.shadowColor = [color CGColor]; view1.layer.shadowRadius = 10.0f; view1.layer.shadowOpacity = 1; view1.layer.shadowOffset = CGSizeZero; view1.layer.masksToBounds = NO; 

    Ok, il y a déjà une réponse acceptée mais je pense qu'il y a une meilleure façon de le faire, il vous suffit d'avoir un nouveau calque un peu plus grand que votre vue et de ne pas le masquer aux limites du calque de la vue le comportement par défaut). Voici l exemple de code :

     CALayer * externalBorder = [CALayer layer]; externalBorder.frame = CGRectMake(-1, -1, myView.frame.size.width+2, myView.frame.size.height+2); externalBorder.borderColor = [UIColor blackColor].CGColor; externalBorder.borderWidth = 1.0; [myView.layer addSublayer:externalBorder]; myView.layer.masksToBounds = NO; 

    Bien sûr, c'est si vous voulez que votre frontière soit grande d'une unité, si vous voulez plus, vous adaptez la borderWidth et le cadre de la couche en conséquence. C'est mieux que d'utiliser une seconde vue un peu plus grande car un CALayer est plus léger qu'un UIView et vous n'avez pas à modifier le frame de myView , ce qui est bien par exemple si myView est un UIImageView

    NB: Pour moi le résultat n'était pas parfait sur simulateur (la couche n'était pas exactement à la bonne position donc la couche était parfois plus épaisse d'un côté) mais c'était exactement ce qui était demandé sur un vrai appareil.

    MODIFIER

    En fait le problème dont je parle dans le NB était juste parce que j'avais réduit l'écran du simulateur, sur la taille normale il n'y a absolument aucun problème

    J'espère que cela aide

    Pour une implémentation Swift, vous pouvez l'append en tant qu'extension UIView.

     extension UIView { struct Constants { static let ExternalBorderName = "externalBorder" } func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.whiteColor()) -> CALayer { let externalBorder = CALayer() externalBorder.frame = CGRectMake(-borderWidth, -borderWidth, frame.size.width + 2 * borderWidth, frame.size.height + 2 * borderWidth) externalBorder.borderColor = borderColor.CGColor externalBorder.borderWidth = borderWidth externalBorder.name = Constants.ExternalBorderName layer.insertSublayer(externalBorder, atIndex: 0) layer.masksToBounds = false return externalBorder } func removeExternalBorders() { layer.sublayers?.filter() { $0.name == Constants.ExternalBorderName }.forEach() { $0.removeFromSuperlayer() } } func removeExternalBorder(externalBorder: CALayer) { guard externalBorder == Constants.ExternalBorderName else { return } externalBorder.removeFromSuperlayer() } } 

    Augmentez la largeur et la hauteur du cadre de la vue avec la largeur de la bordure avant d'append la bordure:

     float borderWidth = 2.0f CGRect frame = self.frame; frame.width += borderWidth; frame.height += borderWidth; self.layer.borderColor = [UIColor yellowColor].CGColor; self.layer.borderWidth = 2.0f; 

    Avec la meilleure réponse acceptée ci-dessus j'ai fait des expériences avec de tels résultats pas agréables et des bords disgracieux:

    frontière sans Bézier chemin

    Donc, je vais partager avec vous mon extension UIView Swift , qui utilise un UIBezierPath à la place comme contour de la bordure – sans bords disgracieux (inspiré par @Fattie ):

    frontière avec le chemin bezier

     // UIView+BezierPathBorder.swift import UIKit extension UIView { fileprivate var bezierPathIdentifier:Ssortingng { return "bezierPathBorderLayer" } fileprivate var bezierPathBorder:CAShapeLayer? { return (self.layer.sublayers?.filter({ (layer) -> Bool in return layer.name == self.bezierPathIdentifier && (layer as? CAShapeLayer) != nil }) as? [CAShapeLayer])?.first } func bezierPathBorder(_ color:UIColor = .white, width:CGFloat = 1) { var border = self.bezierPathBorder let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:self.layer.cornerRadius) let mask = CAShapeLayer() mask.path = path.cgPath self.layer.mask = mask if (border == nil) { border = CAShapeLayer() border!.name = self.bezierPathIdentifier self.layer.addSublayer(border!) } border!.frame = self.bounds let pathUsingCorrectInsetIfAny = UIBezierPath(roundedRect: border!.bounds, cornerRadius:self.layer.cornerRadius) border!.path = pathUsingCorrectInsetIfAny.cgPath border!.fillColor = UIColor.clear.cgColor border!.strokeColor = color.cgColor border!.lineWidth = width * 2 } func removeBezierPathBorder() { self.layer.mask = nil self.bezierPathBorder?.removeFromSuperlayer() } } 

    Exemple:

     let view = UIView(frame: CGRect(x: 20, y: 20, width: 100, height: 100)) view.layer.cornerRadius = view.frame.width / 2 view.backgroundColor = .red //add white 2 pixel border outline view.bezierPathBorder(.white, width: 2) //remove border outline (optional) view.removeBezierPathBorder()