2017 년 IBDesignable을 사용하여 점선 (점선이 아님)을 그립니다.


86

UIKit 으로 파선 을 그리는 것은 쉽습니다 . 그래서:

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

여기에 이미지 설명 입력

진짜 점선을 그리는 방법은 없나요?

여기에 이미지 설명 입력

어떤 아이디어?


이 질문은 정말 오래되었고 아무도 완전한 @IBDesignable해결책을 제시 하지 못했기 때문에 여기에 ...

누군가가 타이핑을 할 수 있기를 바랍니다.

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

수직으로 만들어서 쉽게 바꿀 수 있습니다.

여기에 이미지 설명 입력

장면에 UIView를 넣으십시오. 원하는 너비로 만들면 점선의 너비가됩니다.

클래스를로 변경하면 DottedVertical완료됩니다. 스토리 보드에서 제대로 렌더링됩니다.

여기에 이미지 설명 입력

블록 높이에 대해 제공된 예제 코드 ( "totalCount"등 ...)는 라인을 생성하는 UIView의 끝과 일치하는 픽셀에 대해 블록을 완벽하게 생성합니다.

점이 아닌 블록에 필요한 두 줄의 코드를 제공하는 RobMayoff의 답변을 선택하십시오.


여기에 대각선을 그리는 환상적인 방법이 있습니다! :) stackoverflow.com/a/45228178/294884
Fattie

고마워요 Fattie, 나는 점을 뷰 높이에 따라 계산하도록 약간의 수정을 사용했습니다. totalDynamicDots = bounds.size.height / CGFloat (3); let itemLength = fullHeight / totalDynamicDots
Nitesh

이것의 수평 버전을 가질 수 있습니까? @Fattie
Mohmmad S에게

답변:


97

선 끝 스타일을 둥글게 설정하고 "켜기"길이를 작은 숫자로 설정합니다.

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

결과:

도트


Objective-C의 경우 질문에서와 동일한 예제 클래스를 사용하여 간단히

CGContextSetLineCap(cx, kCGLineCapRound);

에 대한 호출 전에 Swift 코드와 일치 CGContextStrokePath하도록 ra배열 값을 변경하십시오 .


9
주요 정보는 내 답변의 첫 번째 (영어 텍스트) 줄에 있습니다. 나머지는 육즙입니다.
rob mayoff

5
나는 길이를 설정하여 0.01원형 점 을 제공하는 반면을 사용할 때 약간 길다 는 것을 발견했습니다 0.
James P

스크린 샷을 찍어 이미지를 만들었습니다 (기본 시스템 단축키 : ⌘⇧4). 내가 아는 Xcode에는 내장 캡처 기능이 없었습니다.
rob mayoff

2
James P의 조언은 매우 중요합니다. 이 버그로 인해 너무 많은 가슴이 아프고 일했습니다. 제임스 감사합니다. 사람들이 더 명확하게 볼 수 있도록 세미 답변을 만들겠습니다.
Womble

1
버그 해결 방법과 최신 Swift 구문으로 답변을 업데이트했습니다.
rob mayoff

13

위 Swift 예제의 Objective-C 버전 :

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과 호환되는 UIView 확장을 사용하면 다음이 작동합니다.

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

}

그런 다음 다음 viewDidLoad과 같이 viewDidLayoutSubviews실행되는 addDashedBorder함수에서 해당 뷰에서 함수를 실행합니다 .

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
이렇게하면 점선 (예 : 직사각형)이 생성되지만 점선 (예 : 원)을 어떻게 생성합니까?
Crashalot

4

안녕하세요 여러분이 솔루션이 저에게 잘 맞았습니다. 나는 어딘가를 발견하고 콘솔 경고를 방지하기 위해 약간 변경했습니다.

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

결과는 다음과 같습니다.

결과


3

점선을 쉽게 사용자 정의하기 위해 rob mayoff 허용 솔루션에 대해 약간 작업합니다.

  • 각 원의 반경을 변경합니다.
  • 두 원 사이의 간격 수를 변경합니다.
  • 생성 할 패턴 수를 변경합니다.

이 함수는 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

    }
}

이미지를 얻는 방법은 다음과 같습니다.

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

2

완전한 답변은 아니지만 James P가 좋아하는 답변에 대한 의견에서 제기 한 매우 중요한 문제 입니다.

그가 썼어:

on length를 0.01로 설정하면 원형 점이 생기는 반면 0을 사용하면 약간 늘어납니다.

예를 들면

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

0

신속한 3.1에서는 아래 코드를 사용할 수 있습니다.

context.setLineCap(.round)

세 가지 스타일이 있습니다.

 /* Line cap styles. */

public enum CGLineCap : Int32 {

    case butt

    case round

    case square
}

0

아래 코드로 잘 작동합니다.

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

0

이 질문에 답하기에는 너무 늦었을 것입니다. 하지만 동의하신다면, 앞으로 그 문제에 직면하게 될 개발자들에게 쉽게 해결할 수있는 방법을 공유하고 싶습니다. 그래서 @IBDesignable을 사용하는 가장 쉬운 솔루션이라고 생각합니다. 그 클래스를 생성하기 만하면됩니다.

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

그런 다음 스토리 보드의 뷰에 다음과 같이 추가합니다. 여기에 이미지 설명 입력

일단 완료되면 let dashes: [CGFloat] = [0.0, itemLength * 1.1] DottedVertical 클래스 의이 라인 -> 라인 39에서 레이어 사이의 공간을 사용자 지정합니다 . 또는 레이어의 너비를 사용자 지정하려면 스토리 보드에서 선보기 너비를 편집하기 만하면됩니다.


-1

다음 코드를 구현하여 titleLabel( UILabel) 하단에 점선 스타일로 테두리를 추가 했습니다 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];

참조 : https://gist.github.com/kaiix/4070967


이것은 내가 당신의 코드를 사용할 때 원이 아닌 사각형을 생성합니다.
helloB

귀하의 요구 사항에 따라 moveToPoint, addLineToPoint, linewidth 및 lineDashPattern 값을 변경해보십시오
iAkshay
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.