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 UIView
and 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 CALayer
and 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 draw
method.
好的,所以我需要的“唯一”是在UIView
. 我知道我可以使用 Quartz2D 做到这一点(一种简单的方法可以在这里找到)。但我想通过操纵CALayer
而不是去绘制方法来做到这一点。为什么?由于我对我的 进行了转换UIView
,我无法使用该draw
方法正确绘制。
Edit 1:
编辑1:
Just to illustrate my problem:
只是为了说明我的问题:
Normally what you have is UIView
and 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 UIView
itself. 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 apath
property. - 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 UIBezierPath
instead of CAShapeLayer
, here is how to achieve it
对于那些使用UIBezierPath
而不是CAShapeLayer
,这里是如何实现它
As said many times in this thread, you can play with the pattern
and the phase
to achieve a complex dotted line.
正如在此线程中多次说过的,您可以使用pattern
和phase
来实现复杂的虚线。
Hope this helps
希望这可以帮助