2017'de IBDesignable ile noktalı (kesiksiz!) Çizgi çizin


86

UIKit ile kesikli bir çizgi çizmek kolaydır . Yani:

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

görüntü açıklamasını buraya girin

Gerçek bir noktalı çizgi çizmenin bir yolu var mı?

görüntü açıklamasını buraya girin

Herhangi bir fikir?


Bu soru gerçekten eski olduğu ve kimse tam bir @IBDesignableçözüm getirmediği için, işte burada ...

Umarım birisini yazarken kurtarır.

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

Dikey yaptım, kolayca değiştirebilirsiniz.

görüntü açıklamasını buraya girin

Sadece sahneye bir UIView koyun; istediğiniz genişlikte olmasını sağlayın ve bu noktalı çizginin genişliği olacaktır.

Basitçe sınıfı olarak değiştirin DottedVerticalve bitirdiniz. Film şeridinde böyle düzgün bir şekilde işlenecektir.

görüntü açıklamasını buraya girin

Blokların yüksekliği için verilen örnek kodun ("totalCount" vb.), Çizgiyi oluşturan UIView uçlarıyla eşleşen piksele mükemmel bir şekilde bloklarla sonuçlandığına dikkat edin.

Aşağıdaki RobMayoff'un cevabını işaretlediğinizden emin olun, bu da blok olmayan noktalar için gereken iki kod satırını verir.


işte çapraz çizgiler çizmenin harika bir yolu! :) stackoverflow.com/a/45228178/294884
Fattie

Teşekkürler Fattie, noktaların görüş yüksekliğine göre sayılması için çok az değişiklikle kullandım, let totalDynamicDots = bounds.size.height / CGFloat (3); let itemLength = fullHeight / totalDynamicDots
Nitesh

bunun yatay bir versiyonunu alabilir miyiz? @Fattie
Mohmmad S

Yanıtlar:


97

Çizgi sınırı stilini yuvarlatın ve "açık" uzunluğu küçük bir sayıya ayarlayın.

Hızlı oyun alanı örneği:

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

Sonuç:

noktalar


Amaç-C için, sorudakiyle aynı örnek sınıfı kullanarak, basitçe

CGContextSetLineCap(cx, kCGLineCapRound);

çağrılmadan önce ve dizi değerlerini Swift koduma uyacak şekilde CGContextStrokePathdeğiştirin ra.


9
Anahtar bilgiler, cevabımın ilk (İngilizce metin) satırında. Gerisi sos.
rob mayoff

5
0.01Kullanırken biraz uzarken, size dairesel bir nokta verecek şekilde açık uzunluğu ayarlamayı buldum 0.
James P

Bu görüntüyü bir ekran görüntüsü alarak oluşturdum (varsayılan sistem genelinde kısayol: ⌘⇧4). Xcode'da bildiğim yerleşik bir yakalama tesisi hiç olmadı.
2016

2
James P'nin tavsiyesi paha biçilemez. Bu hata bende çok fazla kalp ağrısına ve çalışmaya neden oldu. Teşekkür ederim James. Yarı Cevap oluşturacağım, böylece insanlar onu daha net görebilecek.
Womble

1
Cevabımı hata geçici çözümü ve en son Swift sözdizimi ile güncelledim.
rob mayoff

13

Yukarıdaki Swift örneğinin Objective-C versiyonu:

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

11

Swift 3.0 ile uyumlu bir UIView uzantısı kullanarak aşağıdakiler çalışmalıdır:

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

}

Sonra bir işlevde çalışır sonra bu viewDidLoadgibi viewDidLayoutSubviewsçalıştırmak addDashedBordersöz konusu görünümde işlevi:

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

}

1
Bu, kesikli bir çizgi (yani dikdörtgenler) oluşturur, ancak noktalı (yani daireler) bir çizgiyi nasıl yaratırsınız?
Crashalot

4

Merhaba arkadaşlar bu çözüm benim için iyi çalıştı. Konsol uyarılarını önlemek için bir yer buldum ve biraz değiştirdim.

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

Sonuç şu:

sonuç


3

Noktalı çizgiyi kolayca özelleştirmek için rob mayoff tarafından kabul edilen çözüm üzerinde biraz çalışıyorum:

  • her dairenin yarıçapını değiştirin.
  • 2 daire arasındaki boşlukların sayısını değiştirin.
  • üretilecek desen sayısını değiştirin.

İşlev bir UIImage döndürür:

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

    }
}

Ve işte görüntüyü nasıl elde edeceğiniz:

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

2

Tam bir cevap değil, sadece çok önemli bir şey , James P'nin favori cevaba yaptığı bir yorumda ortaya bir konu:

O yazdı:

Açık uzunluğu 0.01 olarak ayarlamanın size dairesel bir nokta verdiğini, oysa 0 kullanırken biraz uzadığını buldum .

Örneğin,

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

0

Swift 3.1'de aşağıdaki kodu kullanabilirsiniz:

context.setLineCap(.round)

Üç stile sahip olun:

 /* Line cap styles. */

public enum CGLineCap : Int32 {

    case butt

    case round

    case square
}

0

Aşağıdaki kodla iyi çalışıyor,

layer.path = linePath.cgPath
layer.lineWidth = 3
layer.lineDashPattern = [1,layer.lineWidth*2] as [NSNumber]
layer.lineCap = "round"

0

Hey, bu soruya cevap vermek için çok geç olabilir. ancak kabul ederseniz, gelecekte bu sorunla karşılaşabilecek geliştiricilerle bunu çözmenin kolay bir yolunu paylaşmak istiyorum. bu yüzden @IBDesignable kullanarak en kolay çözüm olduğunu tahmin ediyorum. Sadece o sınıfı yaratmalısın

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

Ve sonra bunu film şeridindeki görünümünüze ekleyin görüntü açıklamasını buraya girin

Bir kez yaptıktan sonra, bu satırdan katmanlar arasındaki boşluğu özelleştirin let dashes: [CGFloat] = [0.0, itemLength * 1.1] -> DottedVertical sınıfındaki 39. Satır. veya katman genişliğini özelleştirmek istiyorsanız, yalnızca film şeridinizden çizgi görünümü genişliğinizi düzenlemeniz gerekir


-1

titleLabel( UILabel) Öğesinin altında noktalı stille kenarlık eklemek için aşağıdaki kod parçasını uyguladım 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];

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


bu, kodunuzu kullandığımda daire değil, kareler üretiyor.
merhabaB

İhtiyaçlarınıza göre moveToPoint, addLineToPoint, linewidth ve lineDashPattern değerlerini değiştirmeyi deneyin
iAkshay
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.