私が持っているもの:
この行を作成するには、基本的に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);
}
注:このコードはstackoverflowでここに見つかったので、誰かが私にそれへの参照を与えることができれば感謝します。
欲しいもの:
わかりましたので、必要な「唯一の」ことは、UIView
でこのパターンを作成することです。 Quartz2Dを使用してこれを行うことができることを知っています(簡単な方法は here にあります)。しかし、私はCALayer
を操作することでそれを行いたいのですが、drawメソッドには行きません。どうして? UIView
で変換を行っているため、draw
メソッドを使用して正しく描画できません。
編集1:
私の問題を説明するために:
通常、あなたが持っているのはUIView
で、基本的にそこに何かを描画します(この場合は単純な行です)。 「グレー」領域を取り除くために私が見つけた解決策は、何かを描画する代わりに、UIView
自体を変換することでした。うまく機能します。完全に塗りつぶされた線が必要な場合は、破線が必要なときに問題が発生します。
注:Princeのコードは本当に助けてくれたので、ヒントとして+10を差し上げます。しかし、最終的には、独自のコードを追加します。コンテキストもいくつか追加するので、将来の読者に役立つ可能性があります
最終的なコードは次のようになりました。
-(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];
}
私の場合、beginPointとendPointは、ユーザーがKVOを使用して移動できます。そのため、それらの1つが移動すると:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqual:@"position"])
{
[self updateLine];
}
}
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
UIBezierPath setLineDash:count:phase:
メソッド :
- (void)setLineDash:(const CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase` method.
これにより、破線を描くことができます。
CAShapeLayer
を追加します。 UIView
にサブレイヤーとして追加します。 path
プロパティがあります。UIBezierPath
のオブジェクトを作成します。 setLineDash
を使用して線を描画します。例:
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;
注:この回答は、要件に応じて即興で演奏できるようにヒントを提供します。
ダッシュラインSwift4•Xcode 9
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)
}
}
使用法:
dashView.addDashedBorder()
出力:
Swift 3バージョンのAlexandre Gの答え https://stackoverflow.com/ a/38194152/1800489
extension UIView {
func addDashedLine(color: UIColor = .lightGray) {
layer.sublayers?.filter({ $0.name == "DashedTopLine" }).map({ $0.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)
}
}
Swift 2.2
これをここにドロップすると、他の人の時間を節約できます。
extension UIView {
func addDashedLine(color: UIColor = UIColor.lightGrayColor()) {
layer.sublayers?.filter({ $0.name == "DashedTopLine" }).map({ $0.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)
}
}
受け入れられた答えには座標の問題があります。下にある距離だけ線が引かれます。また、Y座標上で距離と距離が増加する理由と量を把握できません。
正しい座標で破線を描く方法があります:
-(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);
}
この答えは 2017年にIBDesignableを使用して点線(破線ではない!)で描いてください です。黒い破線が必要な場合は、背景色を白に設定することを忘れないでください!!デフォルトでは、ビューの背景色は黒で、線の色も黒なので、実線であると思いました。見つけるのに半日かかりました。 T_T
最初にすべてのクレジットはRuiAAPeresとPrinceに送られます、私は彼らの答えをUIViewオブジェクトにカプセル化し、他の人がプロジェクトにドロップして使用できるようにします
#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
更新Swift 5&IBezierPath
UIBezierPath
の代わりにCAShapeLayer
で作業している人のために、ここにそれを達成する方法があります
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()
}
}
このスレッドで何度も言ったように、pattern
とphase
を使って複雑な点線を作成できます。
お役に立てれば