Il est facile de tracer une ligne pointillée avec UIKit. Donc:
CGFloat dashes[] = {4, 2};
[path setLineDash:dashes count:2 phase:0];
[path stroke];
Existe-t-il un moyen de dessiner une véritable ligne pointillée?
Des idées?
Puisque cette question est vraiment ancienne et que personne n'a apporté de @IBDesignable
solution complète , la voici ...
J'espère que cela permet à quelqu'un d'économiser de la frappe.
@IBDesignable class DottedVertical: UIView {
@IBInspectable var dotColor: UIColor = UIColor.etc
@IBInspectable var lowerHalfOnly: Bool = false
override func draw(_ rect: CGRect) {
// say you want 8 dots, with perfect fenceposting:
let totalCount = 8 + 8 - 1
let fullHeight = bounds.size.height
let width = bounds.size.width
let itemLength = fullHeight / CGFloat(totalCount)
let path = UIBezierPath()
let beginFromTop = CGFloat(0.0)
let top = CGPoint(x: width/2, y: beginFromTop)
let bottom = CGPoint(x: width/2, y: fullHeight)
path.move(to: top)
path.addLine(to: bottom)
path.lineWidth = width
let dashes: [CGFloat] = [itemLength, itemLength]
path.setLineDash(dashes, count: dashes.count, phase: 0)
// for ROUNDED dots, simply change to....
//let dashes: [CGFloat] = [0.0, itemLength * 2.0]
//path.lineCapStyle = CGLineCap.round
dotColor.setStroke()
path.stroke()
}
}
Je l'ai fait verticalement, vous pouvez facilement changer.
Mettez simplement un UIView dans la scène; faites-en la largeur que vous souhaitez et ce sera la largeur de la ligne pointillée.
Changez simplement la classe en DottedVertical
et vous avez terminé. Il sera rendu comme ça correctement dans le storyboard.
Notez que l'exemple de code donné pour la hauteur des blocs ("totalCount" et ainsi de suite ...) donne les blocs parfaitement, au pixel, en correspondance avec les extrémités de l'UIView qui crée la ligne.
Assurez-vous de cocher la réponse de RobMayoff ci-dessous, qui donne les deux lignes de code nécessaires pour les points-pas-blocs.
Réponses:
Définissez le style de la casquette de ligne sur arrondi et définissez la longueur «on» sur un petit nombre.
Exemple de terrain de jeu Swift:
import UIKit import PlaygroundSupport let path = UIBezierPath() path.move(to: CGPoint(x:10,y:10)) path.addLine(to: CGPoint(x:290,y:10)) path.lineWidth = 8 let dashes: [CGFloat] = [0.001, path.lineWidth * 2] path.setLineDash(dashes, count: dashes.count, phase: 0) path.lineCapStyle = CGLineCap.round UIGraphicsBeginImageContextWithOptions(CGSize(width:300, height:20), false, 2) UIColor.white.setFill() UIGraphicsGetCurrentContext()!.fill(.infinite) UIColor.black.setStroke() path.stroke() let image = UIGraphicsGetImageFromCurrentImageContext() let view = UIImageView(image: image) PlaygroundPage.current.liveView = view UIGraphicsEndImageContext()
Résultat:
Pour objective-C, en utilisant le même exemple de classe que dans la question, ajoutez simplement
CGContextSetLineCap(cx, kCGLineCapRound);
avant l'appel à
CGContextStrokePath
, et modifiez lesra
valeurs du tableau pour qu'elles correspondent à mon code Swift.la source
0.01
vous donne un point circulaire, alors qu'ils sont légèrement allongés lors de l'utilisation0
.Version Objective-C de l'exemple Swift ci-dessus:
UIBezierPath * path = [[UIBezierPath alloc] init]; [path moveToPoint:CGPointMake(10.0, 10.0)]; [path addLineToPoint:CGPointMake(290.0, 10.0)]; [path setLineWidth:8.0]; CGFloat dashes[] = { path.lineWidth, path.lineWidth * 2 }; [path setLineDash:dashes count:2 phase:0]; [path setLineCapStyle:kCGLineCapRound]; UIGraphicsBeginImageContextWithOptions(CGSizeMake(300, 20), false, 2); [path stroke]; UIImage * image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
la source
En utilisant une extension UIView, compatible avec Swift 3.0, les éléments suivants devraient fonctionner:
extension UIView { func addDashedBorder(strokeColor: UIColor, lineWidth: CGFloat) { self.layoutIfNeeded() let strokeColor = strokeColor.cgColor let shapeLayer:CAShapeLayer = CAShapeLayer() let frameSize = self.frame.size let shapeRect = CGRect(x: 0, y: 0, width: frameSize.width, height: frameSize.height) shapeLayer.bounds = shapeRect shapeLayer.position = CGPoint(x: frameSize.width/2, y: frameSize.height/2) shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.strokeColor = strokeColor shapeLayer.lineWidth = lineWidth shapeLayer.lineJoin = kCALineJoinRound shapeLayer.lineDashPattern = [5,5] // adjust to your liking shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: shapeRect.width, height: shapeRect.height), cornerRadius: self.layer.cornerRadius).cgPath self.layer.addSublayer(shapeLayer) } }
Ensuite, dans une fonction qui s'exécute après
viewDidLoad
, commeviewDidLayoutSubviews
, exécutez laaddDashedBorder
fonction sur la vue en question:class ViewController: UIViewController { var someView: UIView! override func viewDidLoad() { super.viewDidLoad() someView = UIView() someView.layer.cornerRadius = 5.0 view.addSubview(someView) someView.translatesAutoresizingMaskIntoConstraints = false someView.widthAnchor.constraint(equalToConstant: 200).isActive = true someView.heightAnchor.constraint(equalToConstant: 200).isActive = true someView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true someView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true } override func viewDidLayoutSubviews() { someView.addDashedBorder(strokeColor: UIColor.red, lineWidth: 1.0) } }
la source
Bonjour les gars, cette solution a bien fonctionné pour moi. J'ai trouvé quelque part et j'ai changé un peu pour éviter les avertissements de la console.
extension UIImage { static func drawDottedImage(width: CGFloat, height: CGFloat, color: UIColor) -> UIImage { let path = UIBezierPath() path.move(to: CGPoint(x: 1.0, y: 1.0)) path.addLine(to: CGPoint(x: width, y: 1)) path.lineWidth = 1.5 let dashes: [CGFloat] = [path.lineWidth, path.lineWidth * 5] path.setLineDash(dashes, count: 2, phase: 0) path.lineCapStyle = .butt UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, 2) color.setStroke() path.stroke() let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return image } }
Voici le résultat:
la source
Je travaille un peu sur la solution acceptée par rob mayoff pour personnaliser facilement la ligne pointillée:
La fonction renvoie une UIImage:
extension UIImage { class func dottedLine(radius radius: CGFloat, space: CGFloat, numberOfPattern: CGFloat) -> UIImage { let path = UIBezierPath() path.moveToPoint(CGPointMake(radius/2, radius/2)) path.addLineToPoint(CGPointMake((numberOfPattern)*(space+1)*radius, radius/2)) path.lineWidth = radius let dashes: [CGFloat] = [path.lineWidth * 0, path.lineWidth * (space+1)] path.setLineDash(dashes, count: dashes.count, phase: 0) path.lineCapStyle = CGLineCap.Round UIGraphicsBeginImageContextWithOptions(CGSizeMake((numberOfPattern)*(space+1)*radius, radius), false, 1) UIColor.whiteColor().setStroke() path.stroke() let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } }
Et voici comment obtenir l'image:
UIImage.dottedLine(radius: 100, space: 2, numberOfPattern: 1)
la source
Pas une réponse complète, juste un truc très important que James P a soulevé dans un commentaire sur la réponse préférée:
Il a écrit:
Par exemple,
let dashes: [CGFloat] = [0.001, path.lineWidth * 2]
la source
Dans swift 3.1, vous pouvez utiliser le code ci-dessous:
Avoir trois styles:
/* Line cap styles. */ public enum CGLineCap : Int32 { case butt case round case square }
la source
Fonctionnant bien avec le code ci-dessous,
layer.path = linePath.cgPath layer.lineWidth = 3 layer.lineDashPattern = [1,layer.lineWidth*2] as [NSNumber] layer.lineCap = "round"
la source
Hé, il est peut-être trop tard pour répondre à cette question. mais si vous êtes d'accord, j'aimerais partager un moyen simple de résoudre ce problème avec les développeurs qui seront peut-être confrontés à ce problème à l'avenir. donc je suppose que la solution la plus simple en utilisant @IBDesignable. Vous avez juste besoin de créer cette classe
import UIKit @IBDesignable class DottedVertical: UIView { @IBInspectable var dotColor: UIColor = UIColor.red @IBInspectable var lowerHalfOnly: Bool = false override func draw(_ rect: CGRect) { // say you want 8 dots, with perfect fenceposting: let totalCount = 8 + 8 - 1 let fullHeight = bounds.size.height let width = bounds.size.width let itemLength = fullHeight / CGFloat(totalCount) let path = UIBezierPath() let beginFromTop = CGFloat(0.0) let top = CGPoint(x: width/2, y: beginFromTop) let bottom = CGPoint(x: width/2, y: fullHeight) path.move(to: top) path.addLine(to: bottom) path.lineWidth = width //DASHED SIMPLE LINE //let dashes: [CGFloat] = [itemLength, itemLength] //path.setLineDash(dashes, count: dashes.count, phase: 0) // for ROUNDED dots, simply change to.... let dashes: [CGFloat] = [0.0, itemLength * 1.1] path.lineCapStyle = CGLineCap.round path.setLineDash(dashes, count: dashes.count, phase: 0) dotColor.setStroke() path.stroke() } }
Et puis ajoutez-le à votre vue dans le storyboard comme ça
Une fois que vous avez terminé, personnalisez à froid l'espace entre les calques de cette ligne
let dashes: [CGFloat] = [0.0, itemLength * 1.1]
-> Ligne 39 dans la classe DottedVertical. ou si vous souhaitez personnaliser la largeur du calque, il vous suffit de modifier la largeur de votre vue en ligne à partir de votre storyboardla source
J'ai implémenté le morceau de code suivant pour ajouter une bordure avec un style pointillé en bas de
titleLabel
(UILabel
) dansviewDidAppear
:CAShapeLayer *shapelayer = [CAShapeLayer layer]; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(0.0, titileLabel.frame.size.height-2)]; [path addLineToPoint:CGPointMake(SCREEN_WIDTH, titileLabel.frame.size.height-2)]; UIColor *fill = [UIColor colorWithRed:0.80f green:0.80f blue:0.80f alpha:1.00f]; shapelayer.strokeStart = 0.0; shapelayer.strokeColor = fill.CGColor; shapelayer.lineWidth = 2.0; shapelayer.lineJoin = kCALineJoinRound; shapelayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:2],[NSNumber numberWithInt:3 ], nil]; shapelayer.path = path.CGPath; [titileLabel.layer addSublayer:shapelayer];
Réfrence: https://gist.github.com/kaiix/4070967
la source