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:
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()
}
}
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:
Related Topics
How to Mask a Square Image into an Image with Round Corners in iOS
Get Device Location (Only Country) in iOS
Duplicate Symbol Error in Nsmanagedobject Subclass
Realmswift: Convert Results to Swift Array
Uiscreen Mainscreen Bounds Returning Wrong Size
Swift - Saving Highscore Using Nsuserdefaults
Missing Private Key in the Distribution Certificate on Keychain
How to Compile for Arm Rather Than Thumb in Xcode 4
Class Is Implemented in Both, One of the Two Will Be Used. Which One Is Undefined
App Rejected Because of Advertisingidentifier in Facebook Sdk and Flurry Sdk
iOS Enterprise Distribution Through Ota
Identify New iPhone Model on Xcode (5, 5C, 5S)
Xcode 7 Swift 2 Impossible to Instantiate Uiviewcontroller Subclass of Generic Uitableviewcontroller
Swift - Which Types to Use? Nsstring or String
Set Default iOS Local Notification Style for Application
Presentviewcontroller from Custom Tablecell in Xib
"Do Not Embed", "Embed & Sign", "Embed Without Signing". What Are They. What They Do