1

How to draw about three circle in horizontally area with main and ring color in rectangle. I need to create custom button with this circles, something like this:

enter image description here

Is there any good way to do this?

Robert Dresler
  • 10,580
  • 2
  • 22
  • 40
  • Can you share what you have tried to achieve this? – Satish Dec 06 '18 at 09:05
  • 2
    That is a [UIPageControl](https://developer.apple.com/documentation/uikit/uipagecontrol?language=swift) my friend. Why do you need to make your button look like that? Is it possible that this is a XY problem? If elaborate on why do you need to make it look like that, that might clarify your position and expand your options – NSNoob Dec 06 '18 at 09:22

5 Answers5

4

We can design such kind of views with UIStackView in very ease manner. Take a stackView, set its alignment to center, axis to horizontal and distribution to fill. Create a UILabel/UIButton/UIImageView or even UIView and add rounded radius and border to it. Finally, add those views to the main stackView. Try this.

override func viewDidLoad() {
    super.viewDidLoad()

    //Setup stackView
    let myStackView = UIStackView()
    myStackView.axis = .horizontal
    myStackView.alignment = .center
    myStackView.distribution = .fillEqually
    myStackView.spacing = 8
    view.addSubview(myStackView)

    //Setup circles
    let circle_1 = circleLabel()
    let circle_2 = circleLabel()
    let circle_3 = circleLabel()

    myStackView.addArrangedSubview(circle_1)
    myStackView.addArrangedSubview(circle_2)
    myStackView.addArrangedSubview(circle_3)

    myStackView.translatesAutoresizingMaskIntoConstraints = false
    myStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0).isActive = true
    myStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0).isActive = true
}

func circleLabel() -> UILabel {

    let label = UILabel()
    label.backgroundColor = UIColor.red
    label.layer.cornerRadius = 12.5
    label.layer.masksToBounds = true
    label.layer.borderColor = UIColor.orange.cgColor
    label.layer.borderWidth = 3.0

    label.widthAnchor.constraint(equalToConstant: 25.0).isActive = true
    label.heightAnchor.constraint(equalToConstant: 25.0).isActive = true

    return label
}

enter image description here

Sateesh Yemireddi
  • 4,289
  • 1
  • 20
  • 37
1

To make a Single Circle like that, you need to make use of UIBezierPath and CAShapeLayer .

 let outerCirclePath = UIBezierPath(arcCenter: CGPoint(x: 100,y: 100), radius: CGFloat(50), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)

    let outerCircleShapeLayer = CAShapeLayer()
    outerCircleShapeLayer.path = outerCirclePath.cgPath

    outerCircleShapeLayer.fillColor = UIColor.white.cgColor

    outerCircleShapeLayer.lineWidth = 3.0

    view.layer.addSublayer(outerCircleShapeLayer)

    // Drawing the inner circle
    let innerCirclePath = UIBezierPath(arcCenter: CGPoint(x: 100,y: 100), radius: CGFloat(40), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)

    let innerCircleShapeLayer = CAShapeLayer()
    innerCircleShapeLayer.path = innerCirclePath.cgPath

    innerCircleShapeLayer.fillColor = UIColor.blue.cgColor

    view.layer.addSublayer(innerCircleShapeLayer)

I have attached an image below for the Playground version of it .

enter image description here

Just play around with arcCenter and radius values and you will get the desired output

Shubham Bakshi
  • 552
  • 3
  • 10
1

My team helped me and here is solution to create this with dynamically changing state of circles (with different stroke and fill colors):

import UIKit

@IBDesignable
class CirclesButton: UIControl {

@IBInspectable
var firstCircle: Bool = false {
    didSet {
        setNeedsDisplay()
    }
}

@IBInspectable
var secondCircle: Bool = false {
    didSet {
        setNeedsDisplay()
    }
}

@IBInspectable
var thirdCircle: Bool = false {
    didSet {
        setNeedsDisplay()
    }
}

override func draw(_ rect: CGRect) {
    // get context
    guard let context = UIGraphicsGetCurrentContext() else { return }
    
    // make configurations
    context.setLineWidth(1.0);
    context.setStrokeColor(UIColor.white.cgColor)
    context.setFillColor(red: 0.0, green: 0.58, blue: 1.0, alpha: 1.0)
    
    // find view center
    let dotSize:CGFloat = 11.0
    let viewCenter = CGPoint(x: rect.midX, y: rect.midY)
    
    // find personal dot rect
    var dotRect = CGRect(x: viewCenter.x - dotSize / 2.0, y: viewCenter.y - dotSize / 2.0, width: dotSize, height: dotSize)
    
    if secondCircle {
        context.fillEllipse(in: dotRect)
    }
    context.strokeEllipse(in: dotRect)
    
    
    // find global notes rect
    dotRect = CGRect(x: viewCenter.x - dotSize * 1.5 - 4.0, y: viewCenter.y - dotSize / 2.0, width: dotSize, height: dotSize)
    if firstCircle {
        context.fillEllipse(in: dotRect)
    }
    context.strokeEllipse(in: dotRect)
    
    // find music rect
    dotRect = CGRect(x: viewCenter.x + dotSize / 2.0 + 4.0, y: viewCenter.y - dotSize / 2.0, width: dotSize, height: dotSize)
    if thirdCircle {
        context.setFillColor(red: 0.0, green: 1.0, blue: 0.04, alpha: 1.0)
        context.fillEllipse(in: dotRect)
    }
    context.strokeEllipse(in: dotRect)
}
}

It will looks like: CirclesButton

0

Сode:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let buttonSize: CGFloat = 80

        let firstButton = CustomButton(position: CGPoint(x: 0, y: 0), size: buttonSize, color: .blue)
        self.view.addSubview(firstButton)

        let secondButton = CustomButton(position: CGPoint(x: firstButton.frame.maxX, y: 0), size: buttonSize, color: .blue)
        self.view.addSubview(secondButton)

        let thirdButton = CustomButton(position: CGPoint(x: secondButton.frame.maxX, y: 0), size: buttonSize, color: .green)
        self.view.addSubview(thirdButton) 
    }

}


class CustomButton: UIButton {

    init(position: CGPoint, size: CGFloat, color: UIColor) {
        super.init(frame: CGRect(x: position.x, y: position.y, width: size, height: size))
        self.backgroundColor = color
        self.layer.cornerRadius = size / 2
        self.clipsToBounds = true
        self.layer.borderWidth = 4.0 // make it what ever you want
        self.layer.borderColor = UIColor.white.cgColor
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }
}

You can handle button tapped like:

override func viewDidLoad() {
    super.viewDidLoad()
    firstButton.addTarget(self, action: #selector(handleFirstButton), for: .touchUpInside)
}
@objc func handleFirstButton(sender: UIButton) {
    print("first button tapped")
}
vpoltave
  • 1,612
  • 3
  • 14
  • 31
mazen
  • 438
  • 1
  • 4
  • 13
0

Best and Universal Solution for **Button or Label creation (Fully Dynamic)**

var x = 10
    var y = 5
    var buttonHeight = 40
    var buttonWidth = 40

    for i in 0..<3  {
        let roundButton = UIButton(frame: CGRect(x: x, y: y, width: buttonWidth, height: buttonHeight))
        roundButton.setTitle("Butt\(i)", for: .normal)
        roundButton.layer.cornerRadius = roundButton.bounds.size.height/2
        yourButtonBackView.addSubview(roundButton)
        x = x + buttonWidth + 10
        if x >= Int(yourButtonBackView.frame.width - 30) {
            y = y + buttonHeight + 10
            x = 10
        }
    }
Abdul Hoque Nuri
  • 1,105
  • 1
  • 9
  • 18