top guidelines bar iphone ios uiview calayer quartz-2d

iphone - guidelines - ios top bar



UIView con una lĂ­nea discontinua (6)

Lo que tengo:

Para crear esta línea, básicamente tengo una UIView y hago lo siguiente:

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

Nota: Este código se encontró aquí en stackoverflow, así que si alguien puede darme la referencia, lo agradecería.

Lo que quiero:

Ok, entonces lo "único" que necesito es crear este patrón en UIView . Sé que puedo hacer esto usando Quartz2D (se puede encontrar una forma sencilla de hacerlo aquí ). Pero quiero hacerlo manipulando el CALayer y no yendo al método de sorteo. ¿Por qué? Debido a la transformación que estoy haciendo en mi UIView , no puedo dibujar correctamente usando el método de draw .

Editar 1:

Solo para ilustrar mi problema:

Normalmente, lo que tienes es UIView y luego básicamente UIView algo (en este caso, una línea simple). La solución que encontré para deshacerme del área "gris" fue, en lugar de dibujar algo, simplemente transformar UIView . Funciona bien, si quieres una línea completamente llena, el problema viene cuando quieres una línea punteada.


Nota : El código de Prince realmente me ayudó, así que le daré +10 para las sugerencias. Pero al final, agrego para venir con mi propio código. También agregaré un contexto para que pueda ser útil para futuros lectores

El código final fue así:

-(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]; }

En mi caso, beginPoint y endPoint son movibles por el usuario, utilizando KVO. Entonces, cuando uno de ellos se mueve:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqual:@"position"]) { [self updateLine]; } }

Jugué mucho con el código de Prince. Intenté el método draw: que agrega una línea delgada entre la línea punteada (un poco raro ...) y también lo intenté con initWithFrame: Por sí mismo, su código, sin ninguna modificación, me daría este tipo de errores en la consola:

<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


Compruebe UIBezierPath''s método de UIBezierPath''s tiene:

- (void)setLineDash:(const CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase` method.

Esto le permite draw lines dashed .

1) Primero agregue CAShapeLayer . UIView layer como sublayer a su UIView layer . CAShapeLayer tiene una path property .

2) Ahora haz un objeto de UIBezierPath . Draw la línea usando setLineDash .

Por ejemplo

UIBezierPath *path = [UIBezierPath bezierPath]; //draw a line [path moveToPoint:yourStartPoint]; //add yourStartPoint here [path addLineToPoint:yourEndPoint];// add yourEndPoint here [path stroke]; float dashPattern[] = {2,6,4,2}; //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;

Nota: Esta respuesta proporciona una pista para que pueda improvisar de acuerdo con sus requisitos.


En primer lugar, todo el mérito recae en RuiAAPeres y Prince, solo estoy encapsulando sus respuestas en un objeto UIView que otros pueden incluir en sus proyectos y usar

#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 2.2

dejando esto aquí para ahorrarle tiempo a otros ...

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


Aquí está la versión de Swift 3 de la respuesta de Alexandre G https://.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) } }


La respuesta aceptada tiene un problema de coordenadas. La línea se dibujará a cierta distancia más abajo. Y no puedo entender por qué y cuánta distancia aumenta en la coordenada Y.

Hay una forma de dibujar una línea punteada con la coordenada correcta:

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

Esta respuesta proviene de la línea Dibujar puntos (¡no discontinua!), Con IBDesignable en 2017 . ¡¡¡NO OLVIDE establecer el color de fondo en blanco cuando quiera una línea discontinua negra !! Por defecto, la vista tiene un color de fondo negro, y el color de la línea también es negro, así que pensé que era una línea continua. Me costó medio día descubrirlo. T_T