david
david

Reputation: 3360

How to add circles to rectangle ? UIBezierPath

I need to draw this shape using bezeirPath: enter image description here

I did the following:

  1. I created rectangle path.

  2. then i have added five circles.

as you could see in the code bellow:

let stickLayerBezeirPath = UIBezierPath(rect: rectangleFrame)
  for(var i = 0 ;i < circlesNumber ; i++){



            stickLayerBezeirPath.addArcWithCenter(
                                                  centerPoint,
                                                  radius: CIRCLE_RADIUS,
                                                  startAngle:       CGFloat(0).degreesToRadians,
                                                  endAngle: CGFloat(360).degreesToRadians,
                                                  clockwise: true)



        }

stickLayer = CAShapeLayer()
self.stickLayer.path = stickLayerBezeirPath.CGPath

but i got a layer which doest join the circles with the rectangle correctly : enter image description here

I've expected a layer which doesn't have lines in.

How to fix that ?

Upvotes: 1

Views: 1033

Answers (2)

Den
Den

Reputation: 3591

In my Case, I have to draw indicators when user log-in or log-out.

I tested in Swift 4 (Playground)

 let rewardIndicatorView = UIView(frame: CGRect(x: 0, y: 0, width: 3500, height: 120.0))
 rewardIndicatorView.backgroundColor = #colorLiteral(red: 0.08978033811, green: 0.3079419136, blue: 0.8895353675, alpha: 1)


func updateRewardIndicator(nights: UInt) {
// !! Change the values if you want to change offsets !!
let border: CGFloat    = 10.0
let radius: CGFloat    = 50.5
let lineWidth: CGFloat = border


let line = { (frame: CGRect, isDashed: Bool, isEnabled: Bool) -> CAShapeLayer in
    let path = UIBezierPath()
    path.move(to: frame.origin)
    path.addLine(to: CGPoint(x: frame.origin.x + frame.size.width, y: frame.origin.y))

    let layer         = CAShapeLayer()
    layer.path        = path.cgPath
    layer.lineWidth   = frame.size.height
    layer.strokeColor = isEnabled ? #colorLiteral(red: 0.9803921569, green: 0.6823529412, blue: 0.2156862745, alpha: 1).cgColor : #colorLiteral(red: 0.9058823529, green: 0.9058823529, blue: 0.9058823529, alpha: 1).cgColor

    if (isDashed && isEnabled) == true {
        layer.lineDashPattern = [border*2.0 as NSNumber, border*2.0 as NSNumber]
    }
    return layer
}

let circle = { (origin: CGPoint, radius: CGFloat, border: CGFloat, isEnabled: Bool) -> CALayer in
    // Inner circle
    let innerCircleDiameter = max(0, radius - border*2.0) * 2.0
    let outerCircleDiameter = max(0, radius) * 2.0
    let offset = (outerCircleDiameter - innerCircleDiameter + border) / 2.0
    let layer             = CALayer()
    layer.frame           = CGRect(x: origin.x + offset, y: origin.y + offset, width: innerCircleDiameter, height: innerCircleDiameter)
    layer.cornerRadius    = innerCircleDiameter/2.0
    layer.backgroundColor = isEnabled ? #colorLiteral(red: 0.9803921569, green: 0.6823529412, blue: 0.2156862745, alpha: 1).cgColor : #colorLiteral(red: 0.9058823529, green: 0.9058823529, blue: 0.9058823529, alpha: 1).cgColor

    // Border
    guard (0 < border) && (isEnabled == true) else { return layer }
    let shapeLayer         = CAShapeLayer()
    shapeLayer.path        = UIBezierPath(roundedRect: CGRect(x: origin.x + border/2.0, y: origin.y +  border/2.0, width: outerCircleDiameter, height: outerCircleDiameter), cornerRadius: radius).cgPath
    shapeLayer.strokeColor = layer.backgroundColor
    shapeLayer.fillColor   = UIColor.clear.cgColor
    shapeLayer.lineWidth   = border
    shapeLayer.addSublayer(layer)
    return shapeLayer
}


// Accomplished
var distance = (rewardIndicatorView.bounds.size.width - radius*2.0 * CGFloat(RewardInfo.totalNights) - border*2.0) / CGFloat(RewardInfo.totalNights - 1) + radius*2.0
distance = (logIn == true) ? distance : distance + border / CGFloat(RewardInfo.totalNights)

// Circle
let circleLayer = circle(CGPoint(x: 0, y: 0), radius, (logIn ? 0 : border), true)
let accomplishedCircleLayer               = CAReplicatorLayer()
accomplishedCircleLayer.frame             = rewardIndicatorView.bounds
accomplishedCircleLayer.instanceCount     = Int(nights)
accomplishedCircleLayer.preservesDepth    = false
accomplishedCircleLayer.instanceTransform = CATransform3DMakeTranslation(distance, 0, 0)



// Animation
if logIn == false {
    /*
     let duration              = 0.5 * CFTimeInterval(nights)
    let fadeAnimation         = CABasicAnimation(keyPath: "opacity")
    fadeAnimation.fromValue   = 1.0
    fadeAnimation.toValue     = 0.0
    fadeAnimation.duration    = duration
    fadeAnimation.repeatCount = Float.greatestFiniteMagnitude

    circleLayer.opacity = 0.0
    circleLayer.add(fadeAnimation, forKey: "FadeAnimation")

    accomplishedCircleLayer.instanceDelay = duration / CFTimeInterval(nights)
     */
}
accomplishedCircleLayer.addSublayer(circleLayer)


// Line
var lineOrigin = CGPoint(x: radius*2.0 + (logIn == true ? 0 : border*3.0), y: (logIn == true ? radius : radius + border/2.0))
var lineDistance = (logIn == true) ? distance - radius*2.0 : distance - radius*2.0 - border*2.0

// Check the count of dash is odd or even. If the count is odd, adjust the border to fit
let dashCount = Int((lineDistance - lineOrigin.x)/border - 1.0)
if logIn == false {
    lineOrigin.x += (dashCount%2 != 0) ? border*2.0 : border
    lineDistance -= (dashCount%2 != 0) ? border*5.0 : border*4.0
}

let accomplishedLineLayer               = CAReplicatorLayer()
accomplishedLineLayer.frame             = rewardIndicatorView.bounds
accomplishedLineLayer.instanceCount     = max(0, Int(nights) - 1)
accomplishedLineLayer.preservesDepth    = false
accomplishedLineLayer.instanceTransform = CATransform3DMakeTranslation(distance, 0, 0)
accomplishedLineLayer.addSublayer(line(CGRect(x: lineOrigin.x, y: lineOrigin.y, width: lineDistance, height: lineWidth), !logIn, true))


// Not accompished
// Circle
let notAccomplishedNights = max(0, Int(nights) - 1)
let notAccomplishedCircleRadius = ((logIn == true) ? radius : radius - border/2.0)
let circleOrigin = CGPoint(x: distance * CGFloat(nights) + ((logIn == true) ? 0 : border), y: (logIn == true) ? 0 : border)

let notAccomplishedCircleLayer               = CAReplicatorLayer()
notAccomplishedCircleLayer.frame             = rewardIndicatorView.bounds
notAccomplishedCircleLayer.instanceCount     = Int(RewardInfo.totalNights - nights)
notAccomplishedCircleLayer.preservesDepth    = false
notAccomplishedCircleLayer.instanceTransform = CATransform3DMakeTranslation(distance, 0, 0)
notAccomplishedCircleLayer.addSublayer(circle(CGPoint(x: circleOrigin.x, y: circleOrigin.y), notAccomplishedCircleRadius, 0, false))


// Line
lineOrigin.x = distance * CGFloat(notAccomplishedNights) + radius*2.0
let length   = distance - radius*2.0 + ((logIn == true) ? 0 : border)

let notAccomplishedLineLayer               = CAReplicatorLayer()
notAccomplishedLineLayer.frame             = rewardIndicatorView.bounds
notAccomplishedLineLayer.instanceCount     = min(Int(RewardInfo.totalNights - nights), Int(RewardInfo.totalNights - 1))
notAccomplishedLineLayer.preservesDepth    = false
notAccomplishedLineLayer.instanceTransform = CATransform3DMakeTranslation(distance, 0, 0)
notAccomplishedLineLayer.addSublayer(line(CGRect(x: lineOrigin.x, y: lineOrigin.y, width: length, height: lineWidth), !logIn, false))

// Add Layers
rewardIndicatorView.layer.addSublayer(notAccomplishedLineLayer)
rewardIndicatorView.layer.addSublayer(notAccomplishedCircleLayer)
rewardIndicatorView.layer.addSublayer(accomplishedLineLayer)
rewardIndicatorView.layer.addSublayer(accomplishedCircleLayer)
}

Check the screenShot enter image description here

Upvotes: 0

Teja Nandamuri
Teja Nandamuri

Reputation: 11201

You can try this: h:29 w:197

    let bezier3Path = UIBezierPath()
bezier3Path.moveToPoint(CGPointMake(217, 51.5))
bezier3Path.addCurveToPoint(CGPointMake(201.97, 66), controlPoint1: CGPointMake(217, 59.51), controlPoint2: CGPointMake(210.27, 66))
bezier3Path.addCurveToPoint(CGPointMake(187.66, 55.98), controlPoint1: CGPointMake(195.28, 66), controlPoint2: CGPointMake(189.62, 61.8))
bezier3Path.addCurveToPoint(CGPointMake(161.34, 55.98), controlPoint1: CGPointMake(187.66, 55.98), controlPoint2: CGPointMake(168.57, 55.98))
bezier3Path.addCurveToPoint(CGPointMake(147.03, 66), controlPoint1: CGPointMake(159.38, 61.8), controlPoint2: CGPointMake(153.72, 66))
bezier3Path.addCurveToPoint(CGPointMake(132.74, 56), controlPoint1: CGPointMake(140.36, 66), controlPoint2: CGPointMake(134.7, 61.81))
bezier3Path.addCurveToPoint(CGPointMake(104.26, 56), controlPoint1: CGPointMake(132.74, 56), controlPoint2: CGPointMake(116.69, 56))
bezier3Path.addCurveToPoint(CGPointMake(89.97, 66), controlPoint1: CGPointMake(102.3, 61.81), controlPoint2: CGPointMake(96.64, 66))
bezier3Path.addCurveToPoint(CGPointMake(75.66, 55.98), controlPoint1: CGPointMake(83.28, 66), controlPoint2: CGPointMake(77.62, 61.8))
bezier3Path.addCurveToPoint(CGPointMake(49.34, 55.98), controlPoint1: CGPointMake(75.66, 55.98), controlPoint2: CGPointMake(56.57, 55.98))
bezier3Path.addCurveToPoint(CGPointMake(35.03, 66), controlPoint1: CGPointMake(47.38, 61.8), controlPoint2: CGPointMake(41.72, 66))
bezier3Path.addCurveToPoint(CGPointMake(20, 51.5), controlPoint1: CGPointMake(26.73, 66), controlPoint2: CGPointMake(20, 59.51))
bezier3Path.addCurveToPoint(CGPointMake(29.43, 38.04), controlPoint1: CGPointMake(20, 45.4), controlPoint2: CGPointMake(23.9, 40.19))
bezier3Path.addCurveToPoint(CGPointMake(35.03, 37), controlPoint1: CGPointMake(31.16, 37.37), controlPoint2: CGPointMake(33.05, 37))
bezier3Path.addCurveToPoint(CGPointMake(49.34, 47.02), controlPoint1: CGPointMake(41.72, 37), controlPoint2: CGPointMake(47.38, 41.2))
bezier3Path.addLineToPoint(CGPointMake(75.66, 47.02))
bezier3Path.addCurveToPoint(CGPointMake(77.66, 43.17), controlPoint1: CGPointMake(76.13, 45.63), controlPoint2: CGPointMake(76.81, 44.34))
bezier3Path.addCurveToPoint(CGPointMake(81.92, 39.25), controlPoint1: CGPointMake(78.8, 41.61), controlPoint2: CGPointMake(80.25, 40.27))
bezier3Path.addCurveToPoint(CGPointMake(89.97, 37), controlPoint1: CGPointMake(84.25, 37.83), controlPoint2: CGPointMake(87.01, 37))
bezier3Path.addCurveToPoint(CGPointMake(104.26, 47), controlPoint1: CGPointMake(96.64, 37), controlPoint2: CGPointMake(102.3, 41.19))
bezier3Path.addLineToPoint(CGPointMake(132.74, 47))
bezier3Path.addCurveToPoint(CGPointMake(141.43, 38.04), controlPoint1: CGPointMake(134.12, 42.92), controlPoint2: CGPointMake(137.33, 39.63))
bezier3Path.addCurveToPoint(CGPointMake(147.03, 37), controlPoint1: CGPointMake(143.16, 37.37), controlPoint2: CGPointMake(145.05, 37))
bezier3Path.addCurveToPoint(CGPointMake(161.34, 47.02), controlPoint1: CGPointMake(153.72, 37), controlPoint2: CGPointMake(159.38, 41.2))
bezier3Path.addLineToPoint(CGPointMake(187.66, 47.02))
bezier3Path.addCurveToPoint(CGPointMake(188.61, 44.83), controlPoint1: CGPointMake(187.92, 46.26), controlPoint2: CGPointMake(188.24, 45.53))
bezier3Path.addCurveToPoint(CGPointMake(189.66, 43.17), controlPoint1: CGPointMake(188.92, 44.25), controlPoint2: CGPointMake(189.27, 43.7))
bezier3Path.addCurveToPoint(CGPointMake(201.97, 37), controlPoint1: CGPointMake(192.38, 39.44), controlPoint2: CGPointMake(196.88, 37))
bezier3Path.addCurveToPoint(CGPointMake(217, 51.5), controlPoint1: CGPointMake(210.27, 37), controlPoint2: CGPointMake(217, 43.49))
bezier3Path.closePath()
UIColor.grayColor().setFill()
bezier3Path.fill()

Which gives the result:

enter image description here

How is this Done:

  • First Create a circle using bezier path:

enter image description here

let ovalPath = UIBezierPath(ovalInRect: CGRectMake(31, 24, 47, 49))
UIColor.grayColor().setFill()
ovalPath.fill()

-Create another circle and draw it with a certain distance to the first circle: enter image description here

let oval2Path = UIBezierPath(ovalInRect: CGRectMake(157, 24, 47, 49))
    UIColor.grayColor().setFill()
    oval2Path.fill()

-Now draw a rectangle in between those two cicles: enter image description here

let rectanglePath = UIBezierPath(rect: CGRectMake(83, 44, 69, 9))
UIColor.grayColor().setFill()
rectanglePath.fill()

-Move the 3 bezier paths so that they look like they are merged: enter image description here

//// Oval Drawing
let ovalPath = UIBezierPath(ovalInRect: CGRectMake(32, 24, 47, 49))
UIColor.grayColor().setFill()
ovalPath.fill()


//// Oval 2 Drawing
let oval2Path = UIBezierPath(ovalInRect: CGRectMake(143, 24, 47, 49))
UIColor.grayColor().setFill()
oval2Path.fill()


//// Rectangle Drawing
let rectanglePath = UIBezierPath(rect: CGRectMake(76, 44, 69, 9))
UIColor.grayColor().setFill()
rectanglePath.fill()

-Now merge the three bezier paths into one,resulting: enter image description here

//// Bezier Drawing
let bezierPath = UIBezierPath()
bezierPath.moveToPoint(CGPointMake(190, 48.5))
bezierPath.addCurveToPoint(CGPointMake(166.5, 73), controlPoint1: CGPointMake(190, 62.03), controlPoint2: CGPointMake(179.48, 73))
bezierPath.addCurveToPoint(CGPointMake(143.4, 53), controlPoint1: CGPointMake(155, 73), controlPoint2: CGPointMake(145.42, 64.38))
bezierPath.addCurveToPoint(CGPointMake(78.6, 53), controlPoint1: CGPointMake(143.4, 53), controlPoint2: CGPointMake(91, 53))
bezierPath.addCurveToPoint(CGPointMake(55.5, 73), controlPoint1: CGPointMake(76.58, 64.38), controlPoint2: CGPointMake(67, 73))
bezierPath.addCurveToPoint(CGPointMake(32, 48.5), controlPoint1: CGPointMake(42.52, 73), controlPoint2: CGPointMake(32, 62.03))
bezierPath.addCurveToPoint(CGPointMake(43.8, 27.25), controlPoint1: CGPointMake(32, 39.41), controlPoint2: CGPointMake(36.75, 31.47))
bezierPath.addCurveToPoint(CGPointMake(55.5, 24), controlPoint1: CGPointMake(47.25, 25.18), controlPoint2: CGPointMake(51.24, 24))
bezierPath.addCurveToPoint(CGPointMake(78.6, 44), controlPoint1: CGPointMake(67, 24), controlPoint2: CGPointMake(76.58, 32.62))
bezierPath.addLineToPoint(CGPointMake(143.4, 44))
bezierPath.addCurveToPoint(CGPointMake(145.44, 37.61), controlPoint1: CGPointMake(143.8, 41.75), controlPoint2: CGPointMake(144.49, 39.6))
bezierPath.addCurveToPoint(CGPointMake(166.5, 24), controlPoint1: CGPointMake(149.29, 29.54), controlPoint2: CGPointMake(157.27, 24))
bezierPath.addCurveToPoint(CGPointMake(190, 48.5), controlPoint1: CGPointMake(179.48, 24), controlPoint2: CGPointMake(190, 34.97))
bezierPath.closePath()
UIColor.grayColor().setFill()
bezierPath.fill()

Upvotes: 1

Related Questions