Draw Dotted (Not Dashed!) Line, with Ibdesignable in 2017

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

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

Swift playground example:

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

CGContextSetLineCap(cx, kCGLineCapRound);

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

Dashed horizontal line using IBDesignable

You can achieve as below,

@IBDesignable class DottedHorizontal: UIView {

@IBInspectable var dotColor: UIColor = UIColor.red
@IBInspectable var lowerHalfOnly: Bool = false

override func draw(_ rect: CGRect) {

let fullHeight = bounds.size.height
let width = bounds.size.width

let path = UIBezierPath()

path.move(to: CGPoint(x: 0, y: fullHeight/2))
path.addLine(to: CGPoint(x: width, y: fullHeight/2))

path.lineWidth = 5

let dashes: [CGFloat] = [4, 2]
path.setLineDash(dashes, count: dashes.count, phase: 0)

dotColor.setStroke()
path.stroke()
}
}

Sample Image

Dotted line in drawing not works when I draw line slowly

I solved the problem,
I have updated the code of move with my custom logic,

//MOVING
else if (recognizer.state == UIGestureRecognizerStateChanged) {

dw_mouseSwiped = YES;
CGPoint currentPoint = [recognizer locationInView:self.tempDrawImage];
BOOL dw_addThisPointInLine = YES;


if( ([dw_brushType isEqual: DRAWING_DASHED_LINE] || [dw_brushType isEqual: DRAWING_DOTTED_LINE]) && !([dw_drawingLayerMode isEqualToString:DRAWING_LAYER_MODE_ERASER]) ) {

CGFloat dw_points_distance = 0.0;
dw_points_distance = [self distanceBtwPoints:currentPoint p2:dw_lastPoint];

if( dw_points_distance < dw_brush)
dw_addThisPointInLine = NO;

if( !(dw_addThisPointInLine) ) {
if( dw_points_distance > 30 && dw_brush < 50)
dw_addThisPointInLine = YES;
else if( dw_points_distance > 40 && dw_brush < 80)
dw_addThisPointInLine = YES;
else if( dw_points_distance > 50 && dw_brush < 100)
dw_addThisPointInLine = YES;
}
}

if( dw_addThisPointInLine ) {
//shif the code of move inside this condition.
}


}//move code end

iOS draw dotted line from one view's center to another view's center animating second view using CGAffineTransformMakeTranslationg

I made an app a while ago that did something similar to what you want, so I modified it do what you're trying to do. I have a class called NodeView, that's just a UIView subclass with one property, called line, which is a UIBezierPath (you could subclass UIImageView to do the same thing). I use a timer to move the nodes, and observe the node's center property so I can call drawRect to stroke the node's line. This version moves the nodes one by one. I set the controller's view to a subclass of UIView, and here's the code in that subclass,

#import "RDView.h"
#import "NodeView.h"

@interface RDView ()
@property (weak, nonatomic) IBOutlet UIView *bigView; // this is equivalent to your large image view from which the other image views drop
@property (strong,nonatomic) NSMutableArray *paths;
@end

@implementation RDView


-(void)didMoveToWindow {
self.bigView.layer.cornerRadius = self.bigView.frame.size.width/2.0;
self.paths = [NSMutableArray new];
self.nodes = [NSMutableArray new];
for (int i = 0; i<5; i++) {
NodeView *aNode = [NodeView new];
CGFloat hue = arc4random_uniform(1000)/1000.0;
aNode.backgroundColor = [UIColor colorWithHue:hue saturation:1 brightness:1 alpha:1.0];
aNode.frame = CGRectMake(0, 0, 40, 40);
[self.bigView layoutIfNeeded];
aNode.center = self.bigView.center;
[self addSubview:aNode];
[self.nodes addObject:aNode];

aNode.line = [UIBezierPath bezierPath];
CGFloat dashes[] = {0, aNode.line.lineWidth * 4};
[aNode.line setLineDash:dashes count:2 phase:0];
aNode.line.lineCapStyle = kCGLineCapRound;
[aNode.line moveToPoint:[self.bigView center]];
}
[self bringSubviewToFront:self.bigView];
for (NodeView *aNode in self.nodes) {
[aNode addObserver:self forKeyPath:@"center" options:NSKeyValueObservingOptionNew context:nil];
}

[self performSelector:@selector(dropNodes) withObject:nil afterDelay:1];
}

-(void)dropNodes {
static int i = 0;
[NSTimer scheduledTimerWithTimeInterval:.005 target:self selector:@selector(dropNode:) userInfo:@{@"nodeIndex":@(i)} repeats:YES];
i++;
}

-(void)dropNode:(NSTimer *) timer {
NSInteger i = [timer.userInfo[@"nodeIndex"] integerValue];
NodeView *node = self.nodes[i];
[node setCenter: CGPointMake(node.center.x + (i-2)*.25, node.center.y + 1)]; // spread the nodes out horizontally and move down
[node.line addLineToPoint:node.center];
if (node.center.y > 400) {
[timer invalidate];
if (i < self.nodes.count-1) {
[self dropNodes];
}
}
}


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


- (void)drawRect:(CGRect)rect {
for (NodeView *aNode in self.nodes) {
[aNode.line stroke];
}
}

You can find a link to my project here, http://jmp.sh/lIl5MXp

UIView with a Dashed line

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


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:

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

<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

Xamarin IOS - Insert a dotted line between 2 UIButtons

Use a UIView subclass to contain your line drawing so you can apply constraints and align it to the other Views.

In a UIView subclass, override the Draw method:

public override void Draw(CGRect rect)
{
var path = new UIBezierPath();
path.MoveTo(new CGPoint(Bounds.Size.Width / 2, 0));
path.AddLineTo(new CGPoint(Bounds.Size.Width / 2, Bounds.Size.Height));
path.LineWidth = 6;

var dashes = new []{ 0 , path.LineWidth * 2 };
path.SetLineDash(dashes, 0, dashes.Length, 0);
path.LineCapStyle = CGLineCap.Round;

(UIColor.White).SetStroke();
path.Stroke();
}

Re: I've been using dotted-line technique for awhile, it is from this SO Answer

In combining this View with the answer from this SO question, you can create:

Sample Image



Related Topics



Leave a reply



Submit