ios 绘制虚线(不是虚线!)线,2017 年使用 IBDesignable

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26018302/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:46:10  来源:igfitidea点击:

Draw dotted (not dashed!) line, with IBDesignable in 2017

iosswiftuiviewuikit

提问by Fattie

It's easy to draw a dashedline with UIKit. So:

使用 UIKit绘制虚线很容易。所以:

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

enter image description here

在此处输入图片说明

Is there any way way to draw a genuine dotted line?

有没有办法画出真正的虚线?

enter image description here

在此处输入图片说明

Any ideas?

有任何想法吗?



Since this question is really old and nobody put in a full @IBDesignablesolution, here it is...

由于这个问题真的很老而且没有人提出完整的@IBDesignable解决方案,所以这里是......

Hope it saves someone some typing.

希望它可以为某人节省一些打字时间。

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

I made it vertical, you can easily change.

我把它做成垂直的,你可以很容易地改变。

enter image description here

在此处输入图片说明

Just put a UIView in the scene; make it whatever width you wish and that will be the width of the dotted line.

只需在场景中放置一个 UIView;使它成为您想要的任何宽度,这将是虚线的宽度。

Simply change the class to DottedVerticaland you're done. It will render like that properly in storyboard.

只需将类更改为即可DottedVertical。它将在故事板中正确呈现。

enter image description here

在此处输入图片说明

Note that the example code given for the height of the blocks ("totalCount" and so on...) results in the blocks perfectly, to the pixel, matching with the ends of the UIView that is creating the line.

请注意,为块的高度(“totalCount”等...)给出的示例代码导致块与像素完美匹配,与创建线条的 UIView 的末端相匹配。

Be sure to tick RobMayoff's answer below which gives the two needed lines of code for dots-not-blocks.

一定要勾选下面 RobMayoff 的答案,它给出了点非块所需的两行代码。

回答by rob mayoff

Set the line cap style to round and set the “on” length to a tiny number.

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

Swift playground example:

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

Result:

结果:

dots

点



For objective-C, using the same example class as in the question, simply add

对于objective-C,使用与问题中相同的示例类,只需添加

CGContextSetLineCap(cx, kCGLineCapRound);

before the call to CGContextStrokePath, and change the raarray values to match my Swift code.

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

回答by devgeek

Objective-C version of the Swift example above:

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

回答by Alex

Using a UIView extension, compatible with Swift 3.0 the following should work:

使用与 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)
    }

}

Then in a function that runs after viewDidLoad, like viewDidLayoutSubviews, run the addDashedBorderfunction on the view in question:

然后在一个在 之后运行的函数中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)
    }

}

回答by Vadims Krutovs

Hello guys this solution worked for me fine. I found somewhere and changed a bit to prevent console warnings.

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

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

This is the result:

这是结果:

result

结果

回答by Bogy

I work a bit on rob mayoff accepted solution to easily customize the dotted line:

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

  • change the radius of each circle.
  • change the number of spaces between 2 circles.
  • change the number of patterns to generate.
  • 改变每个圆的半径。
  • 更改 2 个圆圈之间的空格数。
  • 更改要生成的模式数。

The function return an UIImage:

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

    }
}

And here is how to get the image:

这是获取图像的方法:

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

回答by Womble

Not a full answer, just a very important gotchathat James P raised in a comment on the favourite answer:

不是完整的答案,只是James P 在评论最喜欢的答案时提出的一个非常重要的问题

He wrote:

他写了:

I've found setting the on length to 0.01gives you a circular dot, whereas they are slightly elongated when using 0.

我发现将 on length 设置为0.01会为您提供一个圆点,而使用 0 时它们会略微拉长。

For example,

例如,

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

回答by Vineesh TP

Working fine with the below code,

使用以下代码可以正常工作,

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

回答by Bahri Eskander

Hey it's maybe too late to answer on that question. but if you agree I would like to share an easy way to resolve that to the developers that will maybe face that problem in the future. so I guess that the easiest solution using @IBDesignable. You need just to create that class

嘿,现在回答这个问题可能为时已晚。但如果您同意,我想与开发人员分享一个简单的方法来解决这个问题,他们可能会在未来面临这个问题。所以我猜这是使用@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()
    }
}

And then append it to your view in the storyboard like that enter image description here

然后像这样将它附加到故事板中的视图中 在此处输入图片说明

Once you've done you cold customize the space between the layers from this line let dashes: [CGFloat] = [0.0, itemLength * 1.1]--> Line 39 in the DottedVertical class. or if you want to customize the width of the layer you need just to edit your line view width from your storyboard

完成后,您可以从let dashes: [CGFloat] = [0.0, itemLength * 1.1]DottedVertical 类中的这一行--> 第 39行冷自定义层之间的空间。或者,如果您想自定义图层的宽度,则只需从故事板编辑线视图宽度

回答by shujucn

In swift 3.1 you can use below code:

在 swift 3.1 中,您可以使用以下代码:

context.setLineCap(.round)

Have three styles:

拥有三种风格:

 /* Line cap styles. */

public enum CGLineCap : Int32 {

    case butt

    case round

    case square
}

回答by iAkshay

I have implemented following piece of code to add border with dotted style at bottom of titleLabel(UILabel) in viewDidAppear:

我已经实现了以下代码,在titleLabel( UILabel) in 的底部添加带有虚线样式的边框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];

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

参考:https: //gist.github.com/kaiix/4070967