Frage Zeichne gestrichelte (nicht gestrichelte!) Linie, mit IBDesignable in 2017


Es ist einfach, ein zu zeichnen gestrichelt Linie mit UIKit. Damit:

CGFloat dashes[] = {4, 2};
[path setLineDash:dashes count:2 phase:0];
[path stroke];

enter image description here

Gibt es eine Möglichkeit, eine echte gepunktete Linie zu zeichnen?

enter image description here

Irgendwelche Ideen?


Da diese Frage wirklich alt ist und niemand voll ausfüllt @IBDesignable Lösung, hier ist es ...

Hoffe es rettet jemanden beim Tippen.

@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()
    }
}

Ich habe es vertikal gemacht, du kannst es leicht ändern.

enter image description here

Setzen Sie einfach eine UIView in die Szene. mach es so, wie du willst, und das ist die Breite der gepunkteten Linie.

Ändern Sie einfach die Klasse in DottedVertical und du bist fertig. Es wird so im Storyboard richtig dargestellt.

enter image description here

Beachten Sie, dass der angegebene Beispielcode für die Höhe der Blöcke ("totalCount" usw.) dazu führt, dass die Blöcke perfekt zum Pixel passen und mit den Enden der UIView übereinstimmen, die die Linie erzeugt.

Achten Sie darauf, RobMayoffs Antwort unten ankreuzen, die die zwei benötigten Codezeilen für Punkte-nicht-Blöcke gibt.


76
2017-09-24 13:34


Ursprung


Antworten:


Legen Sie den Linienbegrenzungsstil auf rund und stellen Sie die "Ein" -Länge auf eine kleine Zahl ein.

Swift Spielplatz Beispiel:

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()

Ergebnis:

dots


Für objective-C, verwenden Sie dieselbe Beispielklasse wie in der Frage, fügen Sie einfach hinzu

CGContextSetLineCap(cx, kCGLineCapRound);

vor dem Anruf zu CGContextStrokePathund ändere die ra Array-Werte, die meinem Swift-Code entsprechen.


84
2017-09-24 14:41



Objective-C-Version des obigen Swift-Beispiels:

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();

13
2017-07-29 10:54



Mit einer UIView-Erweiterung, die mit Swift 3.0 kompatibel ist, sollte folgendes funktionieren:

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)
    }

}

Dann in einer Funktion, die danach läuft viewDidLoad, mögen viewDidLayoutSubviews, renn den addDashedBorder Funktion auf der fraglichen Ansicht:

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)
    }

}

10
2017-09-28 15:58



Hallo Leute, diese Lösung hat gut funktioniert. Ich habe irgendwo etwas gefunden und etwas verändert, um Konsolenwarnungen zu vermeiden.

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
    }
}

Dies ist das Ergebnis:

result


3
2018-01-20 08:48



Ich arbeite ein wenig an rob mayoff akzeptierte Lösung, um die gepunktete Linie leicht anzupassen:

  • Ändere den Radius jedes Kreises.
  • Ändern Sie die Anzahl der Leerzeichen zwischen 2 Kreisen.
  • Ändern Sie die Anzahl der zu generierenden Muster.

Die Funktion gibt ein UIImage zurück:

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

    }
}

Und hier ist, wie man das Bild bekommt:

UIImage.dottedLine(radius: 100, space: 2, numberOfPattern: 1)

2
2018-05-12 17:03



Keine vollständige Antwort, nur eine sehr wichtige Gotcha dass James P in einem Kommentar auf die Lieblingsantwort angesprochen hat:

Er schrieb:

Ich habe festgestellt, auf die Länge zu 0,01 gibt dir einen kreisförmigen Punkt,   während sie bei Verwendung von 0 leicht verlängert sind.

Beispielsweise,

   let dashes: [CGFloat] = [0.001, path.lineWidth * 2]

1
2018-02-24 02:42



In swift 3.1 können Sie den folgenden Code verwenden:

context.setLineCap(.round)

Habe drei Stile:

 /* Line cap styles. */

public enum CGLineCap : Int32 {

    case butt

    case round

    case square
}

0
2018-05-22 06:50



Ich habe folgendes Stück Code implementiert, um den Rahmen mit dem gepunkteten Stil unten hinzuzufügen titleLabel (UILabel) im viewDidAppear:

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];

Referenz: https://gist.github.com/kaiix/4070967


-1
2018-04-29 07:16