ios 带有虚线的 UIView
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12091916/
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
UIView with a Dashed line
提问by Rui Peres
What I have:
我拥有的:


To create this line, I basically have an UIViewand I do the following:
要创建这条线,我基本上有一个UIView,我执行以下操作:
void setLayerToLineFromAToB(CALayer *layer, CGPoint a, CGPoint b, CGFloat lineWidth)
{
CGPoint center = { 0.5 * (a.x + b.x), 0.5 * (a.y + b.y) };
CGFloat length = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
CGFloat angle = atan2(a.y - b.y, a.x - b.x);
layer.position = center;
layer.bounds = (CGRect) { {0, 0}, { length + lineWidth, lineWidth } };
layer.transform = CATransform3DMakeRotation(angle, 0, 0, 1);
}
Note: This code was found here on stackoverflow, so if someone can give me the reference to it I would appreciate.
注意:此代码是在 stackoverflow 上找到的,因此如果有人能给我参考,我将不胜感激。
What I want:
我想要的是:


Ok so the "only" thing I need is to create this pattern on the UIView. I know I am able to do this using Quartz2D (a simple way to do it can be found here). But I want to do it by manipulating the CALayerand not going to to the draw method. Why? Because of the transformation I am making on my UIView, I am not able to draw correctly using the drawmethod.
好的,所以我需要的“唯一”是在UIView. 我知道我可以使用 Quartz2D 做到这一点(一种简单的方法可以在这里找到)。但我想通过操纵CALayer而不是去绘制方法来做到这一点。为什么?由于我对我的 进行了转换UIView,我无法使用该draw方法正确绘制。
Edit 1:
编辑1:
Just to illustrate my problem:
只是为了说明我的问题:


Normally what you have is UIViewand then you basically just draw something in it (in this case a simple line). The solution I found to get rid of the "gray" area, was to instead of drawing something, just transform the UIViewitself. It work well, if you want a fully filled line, the problem comes when you want a dashed one.
通常你拥有的是UIView,然后你基本上只是在其中画一些东西(在这种情况下是一条简单的线)。我找到的摆脱“灰色”区域的解决方案是不绘制某些东西,而是改变它UIView本身。它工作得很好,如果你想要一条完全填充的线,那么当你想要一条虚线时问题就来了。
采纳答案by Rui Peres
Note: The code from Prince did really help me out, so I will give him +10 for the tips. But in the end, I add to come with my own code. I will also add some context to it, so it can be useful for future readers
注意:Prince 的代码确实帮了我大忙,所以我会给他 +10 的提示。但最后,我添加了我自己的代码。我还将为其添加一些上下文,以便对未来的读者有用
The final code was like this:
最终的代码是这样的:
-(void)updateLine{
// Important, otherwise we will be adding multiple sub layers
if ([[[self layer] sublayers] objectAtIndex:0])
{
self.layer.sublayers = nil;
}
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setBounds:self.bounds];
[shapeLayer setPosition:self.center];
[shapeLayer setFillColor:[[UIColor clearColor] CGColor]];
[shapeLayer setStrokeColor:[[UIColor blackColor] CGColor]];
[shapeLayer setLineWidth:3.0f];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setLineDashPattern:
[NSArray arrayWithObjects:[NSNumber numberWithInt:10],
[NSNumber numberWithInt:5],nil]];
// Setup the path
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, beginPoint.center.x, beginPoint.center.y);
CGPathAddLineToPoint(path, NULL, endPoint.center.x, endPoint.center.y);
[shapeLayer setPath:path];
CGPathRelease(path);
[[self layer] addSublayer:shapeLayer];
}
In my case, the beginPoint and endPoint are movable by the user, by using KVO. So when one of them moves:
就我而言,beginPoint 和 endPoint 可由用户使用 KVO 移动。因此,当其中一个移动时:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqual:@"position"])
{
[self updateLine];
}
}
I did play a lot with Prince's code. I tried on the draw:method, which add a thin line between the dashed line (a bit weird...) and I also tried on initWithFrame:. By itself his code, without any modifications, would give me this kind of errors on the console:
我确实玩了很多 Prince 的代码。我尝试了draw:在虚线之间添加一条细线(有点奇怪......)的方法,我也尝试了initWithFrame:. 他的代码本身未经任何修改,就会在控制台上给我这种错误:
<Error>: CGContextSaveGState: invalid context 0x0
<Error>: CGContextSetLineWidth: invalid context 0x0
<Error>: CGContextSetLineJoin: invalid context 0x0
<Error>: CGContextSetLineCap: invalid context 0x0
<Error>: CGContextSetMiterLimit: invalid context 0x0
<Error>: CGContextSetFlatness: invalid context 0x0
<Error>: CGContextAddPath: invalid context 0x0
<Error>: CGContextDrawPath: invalid context 0x0
<Error>: CGContextRestoreGState: invalid context 0x0
回答by Paresh Navadiya
Check UIBezierPath setLineDash:count:phase:method:
检查 UIBezierPathsetLineDash:count:phase:方法:
- (void)setLineDash:(const CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase` method.
This allows you to draw dashed lines.
这允许您绘制虚线。
- First add a
CAShapeLayer. Add it as sublayer to yourUIView. It has apathproperty. - Now make an object of
UIBezierPath. Draw the line usingsetLineDash.
- 首先添加一个
CAShapeLayer. 将其作为子层添加到您的UIView. 它有一个path属性。 - 现在创建一个对象
UIBezierPath。使用 绘制线条setLineDash。
For example:
例如:
UIBezierPath *path = [UIBezierPath bezierPath];
//draw a line
[path moveToPoint:yourStartPoint]; //add yourStartPoint here
[path addLineToPoint:yourEndPoint];// add yourEndPoint here
[path stroke];
CGFloat dashPattern[] = {2.0f,6.0f,4.0f,2.0f}; //make your pattern here
[path setLineDash:dashPattern count:4 phase:3];
UIColor *fill = [UIColor blueColor];
shapelayer.strokeStart = 0.0;
shapelayer.strokeColor = fill.CGColor;
shapelayer.lineWidth = 5.0;
shapelayer.lineJoin = kCALineJoinMiter;
shapelayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:10],[NSNumber numberWithInt:7], nil];
shapelayer.lineDashPhase = 3.0f;
shapelayer.path = path.CGPath;
Note:This answer provides a hint so you can improvise accordingly to your requirement(s).
注意:此答案提供了一个提示,因此您可以根据自己的要求即兴创作。
回答by Hyman
Dash Line in Swift4 ? Xcode 9
Swift4中的虚线?Xcode 9
Crate a CAShapeLayer & use lineDashPattern
创建一个 CAShapeLayer 并使用lineDashPattern
extension UIView {
func addDashedBorder() {
//Create a CAShapeLayer
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 2
// passing an array with the values [2,3] sets a dash pattern that alternates between a 2-user-space-unit-long painted segment and a 3-user-space-unit-long unpainted segment
shapeLayer.lineDashPattern = [2,3]
let path = CGMutablePath()
path.addLines(between: [CGPoint(x: 0, y: 0),
CGPoint(x: self.frame.width, y: 0)])
shapeLayer.path = path
layer.addSublayer(shapeLayer)
}
}
Usage:
用法:
dashView.addDashedBorder()
Output:
输出:
回答by Alexandre G
Swift 2.2
斯威夫特 2.2
dropping this in here to save others time..
把它放在这里是为了节省其他人的时间..
extension UIView {
func addDashedLine(color: UIColor = UIColor.lightGrayColor()) {
layer.sublayers?.filter({ extension UIView {
func addDashedLine(color: UIColor = .lightGray) {
layer.sublayers?.filter({ -(void)drawRect:(CGRect)rect
{
CGContextBeginPath(cx);
CGContextRef cx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(cx, _thickness);
CGContextSetStrokeColorWithColor(cx, _color.CGColor);
CGFloat dash[] = {_dashedLength,_dashedGap};
CGContextSetLineDash(cx, 0, dash, 2); // nb "2" == ra count
// CGContextSetLineCap(cx, kCGLineCapRound);
CGContextMoveToPoint(cx, 0, _thickness);
CGContextAddLineToPoint(cx, self.bounds.size.width, _thickness);
CGContextStrokePath(cx);
CGContextClosePath(cx);
}
.name == "DashedTopLine" }).map({ #import <UIKit/UIKit.h>
/**
* Simple UIView for a dotted line
*/
@interface H3DottedLine : UIView
/**
* Set the line's thickness
*/
@property (nonatomic, assign) CGFloat thickness;
/**
* Set the line's color
*/
@property (nonatomic, copy) UIColor *color;
/**
* Set the length of the dash
*/
@property (nonatomic, assign) CGFloat dashedLength;
/**
* Set the gap between dashes
*/
@property (nonatomic, assign) CGFloat dashedGap;
@end
@implementation H3DottedLine
#pragma mark - Object Lifecycle
- (instancetype)init {
self = [super init];
if (self) {
// Set Default Values
_thickness = 1.0f;
_color = [UIColor whiteColor];
_dashedGap = 1.0f;
_dashedLength = 5.0f;
}
return self;
}
#pragma mark - View Lifecycle
- (void)layoutSubviews {
// Note, this object draws a straight line. If you wanted the line at an angle you simply need to adjust the start and/or end point here.
[self updateLineStartingAt:self.frame.origin andEndPoint:CGPointMake(self.frame.origin.x+self.frame.size.width, self.frame.origin.y)];
}
#pragma mark - Setters
- (void)setThickness:(CGFloat)thickness {
_thickness = thickness;
[self setNeedsLayout];
}
- (void)setColor:(UIColor *)color {
_color = [color copy];
[self setNeedsLayout];
}
- (void)setDashedGap:(CGFloat)dashedGap {
_dashedGap = dashedGap;
[self setNeedsLayout];
}
- (void)setDashedLength:(CGFloat)dashedLength {
_dashedLength = dashedLength;
[self setNeedsLayout];
}
#pragma mark - Draw Methods
-(void)updateLineStartingAt:(CGPoint)beginPoint andEndPoint:(CGPoint)endPoint {
// Important, otherwise we will be adding multiple sub layers
if ([[[self layer] sublayers] objectAtIndex:0]) {
self.layer.sublayers = nil;
}
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setBounds:self.bounds];
[shapeLayer setPosition:self.center];
[shapeLayer setFillColor:[UIColor clearColor].CGColor];
[shapeLayer setStrokeColor:self.color.CGColor];
[shapeLayer setLineWidth:self.thickness];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setLineDashPattern:@[@(self.dashedLength), @(self.dashedGap)]];
// Setup the path
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, beginPoint.x, beginPoint.y);
CGPathAddLineToPoint(path, NULL, endPoint.x, endPoint.y);
[shapeLayer setPath:path];
CGPathRelease(path);
[[self layer] addSublayer:shapeLayer];
}
@end
.removeFromSuperlayer() })
backgroundColor = .clear
let shapeLayer = CAShapeLayer()
shapeLayer.name = "DashedTopLine"
shapeLayer.bounds = bounds
shapeLayer.position = CGPoint(x: frame.width / 2, y: frame.height / 2)
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = color.cgColor
shapeLayer.lineWidth = 1
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.lineDashPattern = [4, 4]
let path = CGMutablePath()
path.move(to: CGPoint.zero)
path.addLine(to: CGPoint(x: frame.width, y: 0))
shapeLayer.path = path
layer.addSublayer(shapeLayer)
}
}
.name == "DashedTopLine" }).map({ class MyView: UIView {
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
// >> define the pattern & apply it
let dashPattern: [CGFloat] = [4.0, 4.0]
path.setLineDash(dashPattern, count: dashPattern.count, phase: 0)
// <<
path.lineWidth = 1
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 100, y: 100))
path.stroke()
}
}
.removeFromSuperlayer() })
self.backgroundColor = UIColor.clearColor()
let cgColor = color.CGColor
let shapeLayer: CAShapeLayer = CAShapeLayer()
let frameSize = self.frame.size
let shapeRect = CGRect(x: 0, y: 0, width: frameSize.width, height: frameSize.height)
shapeLayer.name = "DashedTopLine"
shapeLayer.bounds = shapeRect
shapeLayer.position = CGPoint(x: frameSize.width / 2, y: frameSize.height / 2)
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = cgColor
shapeLayer.lineWidth = 1
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.lineDashPattern = [4, 4]
let path: CGMutablePathRef = CGPathCreateMutable()
CGPathMoveToPoint(path, nil, 0, 0)
CGPathAddLineToPoint(path, nil, self.frame.width, 0)
shapeLayer.path = path
self.layer.addSublayer(shapeLayer)
}
}
回答by moody
Here is Swift 3 version of Alexandre G's answer https://stackoverflow.com/a/38194152/1800489
这是 Swift 3 版本的Alexandre G的回答https://stackoverflow.com/a/38194152/1800489
##代码##回答by DianeZhou
The accepted answer has a coordinate problem. The line will be drawn some distance below. And I cannot figure out why and how much distance it increases on Y coordinate.
接受的答案有一个坐标问题。该线将在下方绘制一段距离。而且我无法弄清楚它在 Y 坐标上增加的距离和增加的原因。
There's a way to draw a dashed line with correct coordinate:
有一种方法可以绘制具有正确坐标的虚线:
##代码##This answer is from Draw dotted (not dashed!) line, with IBDesignable in 2017. DON'T DON'T DON'T forget to set the background color as white when you want a black dashed line!! By default the view has a black background color, and the line color is also black, so I thought it was a solid line. It cost me half a day to find out. T_T
这个答案来自Draw dotted (not dashed!) line, with IBDesignable in 2017。当您想要黑色虚线时,不要忘记将背景颜色设置为白色!!视图默认背景色是黑色,线条颜色也是黑色,所以我以为是实线。我花了半天时间才知道。T_T
回答by Shaheen Ghiassy
First all the credit goes to RuiAAPeres and Prince, I'm just encapsulating their answers into a UIView object that others can drop into their projects and use
首先,所有功劳都归功于 RuiAAPeres 和 Prince,我只是将他们的答案封装到一个 UIView 对象中,其他人可以将其放入他们的项目中并使用
##代码##回答by Olympiloutre
Update Swift 5& UIBezierPath
更新 Swift 5和UIBezierPath
For those working with UIBezierPathinstead of CAShapeLayer, here is how to achieve it
对于那些使用UIBezierPath而不是CAShapeLayer,这里是如何实现它
As said many times in this thread, you can play with the patternand the phaseto achieve a complex dotted line.
正如在此线程中多次说过的,您可以使用pattern和phase来实现复杂的虚线。
Hope this helps
希望这可以帮助

