在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); 让itemLength = fullHeight / totalDynamicDots
Nitesh

我们可以对此进行横向介绍吗?@Fattie
Mohmmad S

Answers:


97

将线帽样式设置为圆形,并将“ on”长度设置为一个很小的数字。

斯威夫特游乐场示例:

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

调用之前CGContextStrokePath,并更改ra数组值以匹配我的Swift代码。


9
关键信息在答案的第一行(英文文本)中。剩下的是肉汁。
rob mayoff

5
我发现将on长度设置为0.01会给您一个圆点,而使用时它们会稍微拉长0
James P

我通过截屏来创建该图像(系统范围的默认快捷键:: 4)。据我所知,从来没有Xcode中内置的捕获工具。
rob mayoff

2
詹姆斯·P的建议是无价的。这个错误使我感到非常痛苦和工作。谢谢詹姆斯。我将创建一个半答案,以便人们可以更清楚地看到它。
Womble

1
我已经通过错误解决方法和最新的Swift语法更新了答案。
抢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)
    }

}

然后,在viewDidLoadviewDidLayoutSubviews之后运行的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

3

我对rob mayoff接受的解决方案进行了一些工作,以轻松自定义虚线:

  • 更改每个圆的半径。
  • 更改2个圆圈之间的空格数。
  • 更改要生成的图案数量。

该函数返回一个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)

3

大家好,这个解决方案对我来说很好。我在某个地方找到了,并做了一些更改以防止控制台警告。

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

结果如下:

结果


2

这不是一个完整的答案,只是James P在最喜欢的答案的评论中提出的一个非常重要的陷阱

他写了:

我发现将on长度设置为0.01会给您一个圆点,而使用0时它们会稍微拉长。

例如,

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

0

在Swift 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

我已实现以下代码,以在titleLabelUILabel)底部的虚线处添加边框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];

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


当我使用您的代码时,这将产生正方形而不是圆形。
helloB

尝试根据您的要求更改moveToPoint,addLineToPoint,linewidth和lineDashPattern值
iAkshay
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.