How to add a bottom border in swift ios? - ios

I am trying to add a bottom border to my tabs. Here is the code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .systemBackground
self.navigationItem.titleView = UIImageView(
image: UIImage(named: "Twitter")!.resize(25, 25)
)
let leftBarImage = UIImageView(
image: UIImage(named: "Profile")!.resize(35, 35)
)
leftBarImage.layer.borderWidth = 1
leftBarImage.layer.borderColor = UIColor.systemGray4.cgColor
leftBarImage.layer.cornerRadius = leftBarImage.frame.width / 2
leftBarImage.clipsToBounds = true
self.navigationItem.leftBarButtonItem = UIBarButtonItem(
customView: leftBarImage
)
let segmentedControl = UIStackView()
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.axis = .horizontal
segmentedControl.alignment = .center
segmentedControl.distribution = .fillEqually
segmentedControl.backgroundColor = .green
segmentedControl.addBorder(
for: .Bottom,
color: UIColor.red.cgColor,
thickness: 20
)
for menuLabelText in ["For you", "Following"] {
let menuLabel = UILabel()
menuLabel.text = menuLabelText
menuLabel.textAlignment = .center
menuLabel.font = UIFont.boldSystemFont(ofSize: 16)
segmentedControl.addArrangedSubview(menuLabel)
}
self.view.addSubview(segmentedControl)
NSLayoutConstraint.activate([
segmentedControl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
segmentedControl.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor)
])
}
}
And the border logic,
import UIKit
extension UIView {
enum BorderSide {
case Left, Right, Top, Bottom
}
func addBorder(for side: BorderSide, color: CGColor, thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color
switch side {
case .Left:
border.frame = CGRect(
x: frame.minX,
y: frame.minY,
width: thickness,
height: frame.height
)
break
case .Right:
border.frame = CGRect(
x: frame.maxX,
y: frame.minY,
width: thickness,
height: frame.height
)
break
case .Top:
border.frame = CGRect(
x: frame.minX,
y: frame.minY,
width: frame.width,
height: thickness
)
break
case .Bottom:
border.frame = CGRect(
x: frame.minX,
y: frame.maxY,
width: frame.width,
height: thickness
)
break
}
layer.addSublayer(border)
}
}
The border is not showing at all. Here is a screenshot:
You can see the green background but not the red border beneath. Any help would be appreciated. Thanks!

First, let's look at what's wrong with the code...
The addBorder(...) func in your UIView extension uses the view's frame -- so, let's put a print() statement right before we try to add the border, to see the the view's frame:
segmentedControl.backgroundColor = .green
// print the frame of segmentedControl to debug console
print("segmentedControl Frame in viewDidLoad():", segmentedControl.frame)
segmentedControl.addBorder(
for: .Bottom,
color: UIColor.red.cgColor,
thickness: 20
)
You will see this in the debug console:
segmentedControl Frame in viewDidLoad(): (0.0, 0.0, 0.0, 0.0)
So your extension tries to set the frame of the layer:
border.frame = CGRect(
x: frame.minX, // minX == 0
y: frame.maxY, // maxY == 0
width: frame.width, // width == 0
height: thickness. // thickness == 20 (passed in call)
)
As we see, we end up with a layer frame of (x: 0.0, y: 0.0, width: 0.0, height: 20.0) ... we won't see anything, because it has no width.
So, let's try adding the border in viewDidLayoutSubviews().
Note that we'll move the segmentedControl creation outside of viewDidLoad() so we can reference it elsewhere. And, we'll leave the addBorder() with red where it was, then call it again with blue in viewDidLayoutSubviews():
class ViewController: UIViewController {
// create it here, so we can reference it outside of viewDidLoad()
let segmentedControl = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .systemBackground
self.title = "Bad Layout"
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.axis = .horizontal
segmentedControl.alignment = .center
segmentedControl.distribution = .fillEqually
segmentedControl.backgroundColor = .green
// print the frame of segmentedControl to debug console
print("segmentedControl Frame in viewDidLoad():", segmentedControl.frame)
segmentedControl.addBorder(
for: .Bottom,
color: UIColor.red.cgColor,
thickness: 20
)
for menuLabelText in ["For you", "Following"] {
let menuLabel = UILabel()
menuLabel.text = menuLabelText
menuLabel.textAlignment = .center
menuLabel.font = UIFont.boldSystemFont(ofSize: 16)
segmentedControl.addArrangedSubview(menuLabel)
}
self.view.addSubview(segmentedControl)
NSLayoutConstraint.activate([
segmentedControl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
segmentedControl.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor)
])
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// print the frame of segmentedControl to debug console
print("segmentedControl Frame in viewDidLayoutSubviews():", segmentedControl.frame)
segmentedControl.addBorder(
for: .Bottom,
color: UIColor.blue.cgColor,
thickness: 20
)
}
}
extension UIView {
enum BorderSide {
case Left, Right, Top, Bottom
}
func addBorder(for side: BorderSide, color: CGColor, thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color
switch side {
case .Left:
border.frame = CGRect(
x: frame.minX,
y: frame.minY,
width: thickness,
height: frame.height
)
break
case .Right:
border.frame = CGRect(
x: frame.maxX,
y: frame.minY,
width: thickness,
height: frame.height
)
break
case .Top:
border.frame = CGRect(
x: frame.minX,
y: frame.minY,
width: frame.width,
height: thickness
)
break
case .Bottom:
border.frame = CGRect(
x: frame.minX,
y: frame.maxY,
width: frame.width,
height: thickness
)
break
}
layer.addSublayer(border)
}
}
Now, we see two "print frame" outputs:
segmentedControl Frame in viewDidLoad(): (0.0, 0.0, 0.0, 0.0)
segmentedControl Frame in viewDidLayoutSubviews(): (0.0, 97.66666666666667, 393.0, 19.333333333333332)
Unfortunately, this is the result:
The blue layer is positioned way below the bottom of the stack view / labels.
That's happening because the extension is using frame.maxY -- which is frame.origin.y + frame.size.height -- and the frame's origin.y is 97.66666666666667 (it's top is below the navigation bar).
You could use the same addBorder() approach, by calling it after the views have been laid out (that is, after the frames have been set), and modifying the extension to use the view's bounds instead of frame:
case .Bottom:
border.frame = CGRect(
x: bounds.minX,
y: bounds.maxY,
width: bounds.width,
height: thickness
)
break
and we get this:
However... as should be obvious, this is really not a good approach. Worth noting also is that the layer appears outside the bounds of the view. So, if you were to add a subview constrained to the bottom of segmentedControl, the top of that view would be covered by the 20-point tall "border" layer.
My guess is that you are also going to want to be able to tap the labels... possible you also want to move that "border" to show only under the selected label... etc.
Do some searching / exploring how to subclass UIView so it handles all of that by itself.

Related

how to programmatically show a colored disk behind a UIImageView, in swift on an iOS device

I have an icon that I programmatically display.
How can I display a solid, colored disk behind the icon, at the same screen position?
Icon is opaque.
I will sometimes programmatically change screen position and disk's diameter and color.
Here's how I programmatically display the icon now.............
DispatchQueue.main.async
{
ViewController.wrist_band_UIImageView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
}
UPDATE #1 for D.Mika below...
UPDATE #2 for D.Mika below...
import UIKit
import Foundation
class ViewController: UIViewController
{
static var circleView: UIView!
static let wrist_band_UIImageView: UIImageView = {
let theImageView = UIImageView()
theImageView.image = UIImage( systemName: "applewatch" )
theImageView.translatesAutoresizingMaskIntoConstraints = false
return theImageView
}()
override func viewDidLoad()
{
super.viewDidLoad()
view.addSubview( ViewController.wrist_band_UIImageView )
// Init disk image:
ViewController.circleView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
ViewController.circleView.backgroundColor = .red
ViewController.circleView.layer.cornerRadius = view.bounds.size.height / 2.0
ViewController.circleView.clipsToBounds = true
// Add view to view hierarchy below image view
ViewController.circleView.insertSubview(view, belowSubview: ViewController.wrist_band_UIImageView)
App_class.display_single_wearable()
}
}
class App_class
{
static var is_communication_established = false
static var total_packets = 0
static func display_single_wearable()
{
ViewController.wrist_band_UIImageView.frame = CGRect(x: 0, y: 0,
width: 100, height: 100)
ViewController.circleView.frame = CGRect( x: 0,
y: 0,
width: 100,
height: 100)
ViewController.circleView.layer.cornerRadius = 100
}
static func process_location_xy(text_location_xyz: String)
{}
} // App_class
You can display a colored circle using the following view:
circleView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
circleView.backgroundColor = .red
circleView.layer.cornerRadius = view.bounds.size.height / 2.0
circleView.clipsToBounds = true
// Add view to view hierarchy below image view
view.insertSubview(circleView, belowSubview: wrist_band_UIImageView)
You can change it's position and size by applying a new frame. But you have to change the layer's cornerRadius accordingly.
This is a simple example in a playground:
Edit:
I've modified the sample code to add the view the view hierarchy.
BUT, you still need to adjust the circle's frame, when you modify the image view's frame. (and the cornerRadius accordingly). For example
DispatchQueue.main.async
{
ViewController.wrist_band_UIImageView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
circleView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
circleView.layer.cornerRadius = App_class.screen_width
}
And you need to add a variable to the viewController holding the reference to the circle view, like:
var circleView: UIView!
The following answer works.
The answers from d.mika above did not work. Plus, he was insulting. ;-)
// Show red circle
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 200, y: 400), radius: CGFloat(40), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
// Change the fill color
shapeLayer.fillColor = UIColor.red.cgColor
// You can change the stroke color
shapeLayer.strokeColor = UIColor.red.cgColor
// You can change the line width
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)

How to make the width of the border the same after scaling?

I set "borderwidth = 3" to the view. After I scaling, the border either became thicker or thinner.
before scaling (yellow border on the left photo)
after scaling( yellow border on the right photo)
enter image description here
How can I keep the width of the border fixed after I scale it?
I user this source on the GitHub
https://github.com/yokurin/DragRotateScaleView
And just add v.layer.borderWidth = 5
lazy var rect1: DragRotateScaleView = {
let v = DragRotateScaleView(frame: CGRect(x: 20, y: 100, width: 200, height: 200))
v.delegate = self
v.backgroundColor = UIColor.cyan
v.layer.borderColor = UIColor(red: 22/255, green: 22/255, blue: 22/255, alpha: 1).cgColor
v.layer.borderWidth = 5
return v
}()
Thank You!!
Just divide the border width by the scale and set that value to the borderWidth again.
Try this in a playground:
import UIKit
import PlaygroundSupport
// Save this values, you will use them.
let border: CGFloat = 3
let scale: CGFloat = 5
// Example views.
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = .red
let secondView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
secondView.layer.borderColor = UIColor.yellow.cgColor
secondView.layer.borderWidth = border
view.addSubview(secondView)
// View scale transformation.
secondView.transform = CGAffineTransform(scaleX: scale, y: scale)
// IMPORTANT: Change the width of the border after the transformation.
secondView.layer.borderWidth = border / scale
// This is only for the playground.
PlaygroundPage.current.liveView = view

Multiple shadows under UIView iOS Swift

I am trying to make a UIButton with rounded corners that has 2 colored shadows. Why is the red (and at this point also the blue "shadow" layer covering the button? How to get the shadows below the button canvas). I thought it was helping to insert sublayers instead of just adding them.
I have made a playground illustrating the issue
import UIKit
import PlaygroundSupport
This is the button I'm trying to implement
class PrimaryButton: UIButton {
required init(text: String = "Test 1", hasShadow: Bool = true) {
super.init(frame: .zero)
setTitle(text, for: .normal)
backgroundColor = UIColor.blue
layer.cornerRadius = 48 / 2
layer.masksToBounds = false
if hasShadow {
insertShadow()
}
}
fileprivate func insertShadow() {
let layer2 = CALayer(layer: layer), layer3 = CALayer(layer: layer)
layer2.applySketchShadow(color: UIColor.red, alpha: 0.5, x: 0, y: 15, blur: 35, spread: -10)
layer3.applySketchShadow(color: UIColor.blue, alpha: 0.5, x: 0, y: 10, blur: 21, spread: -9)
layer.insertSublayer(layer2, at: 0)
layer.insertSublayer(layer3, at: 0)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
layer.sublayers?.forEach { (sublayer) in
sublayer.shadowPath = UIBezierPath(rect: bounds).cgPath
}
}
}
This is an extension that helps adding the shadow from Sketch specification:
extension CALayer {
func applySketchShadow(
color: UIColor = .black,
alpha: Float = 0.5,
x: CGFloat = 0,
y: CGFloat = 2,
blur: CGFloat = 4,
spread: CGFloat = 0)
{
shadowColor = color.cgColor
shadowOpacity = alpha
shadowOffset = CGSize(width: x, height: y)
shadowRadius = blur / 2.0
if spread == 0 {
shadowPath = nil
} else {
let dx = -spread
let rect = bounds.insetBy(dx: dx, dy: dx)
shadowPath = UIBezierPath(rect: rect).cgPath
}
masksToBounds = false
}
}
class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let button = PrimaryButton()
button.frame = CGRect(x: 150, y: 200, width: 200, height: 48)
view.addSubview(button)
self.view = view
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
It seems legit to me. layer1 & layer2 are sublayers of the button layer.
You could add a third layer that will serve as a background. Here is an example based on your code:
class PrimaryButton: UIButton {
let layer1 = CALayer(), layer2 = CALayer(), layer3 = CALayer()
override func layoutSubviews() {
super.layoutSubviews()
layer1.backgroundColor = UIColor.blue.cgColor
layer1.cornerRadius = 48 / 2
[layer1, layer2, layer3].forEach {
$0.masksToBounds = false
$0.frame = layer.bounds
layer.insertSublayer($0, at: 0)
}
layer2.applySketchShadow(color: UIColor.red, alpha: 0.5, x: 0, y: 15, blur: 35, spread: -10)
layer3.applySketchShadow(color: UIColor.blue, alpha: 0.5, x: 0, y: 10, blur: 21, spread: -9)
}
}
Note that I put most of the code inside layoutSubviews because most of your methods use the actual bounds of the button.
Change your insertions to:
layer.insertSublayer(layer2, at: 1)
layer.insertSublayer(layer3, at: 2)
That should do it.
Another way is to add double buttons without change your class.
let button = PrimaryButton()
button.frame = CGRect(x: 150, y: 200, width: 200, height: 48)
button.backgroundColor = UIColor.clear
view.addSubview(button)
self.view = view
let button1 = PrimaryButton()
button1.frame = CGRect(x: 0, y: 0, width: 200, height: 48)
button.addSubview(button1)
button1.layer.sublayers?.forEach{$0.removeFromSuperlayer()}

IOS - How to create Facebook reaction bar with blur background?

Although it may not be the week to replicate some design of Facebook, I would like to be able to design my own version of the reaction indicator view below.
I have three UIImageViews lined in the same positions as above. The problem is that, unlike Facebook, the background color may change (i.e is on top of a UIBlurEffect) and therefore I am unable to set the border color to white.
I thought it would make sense to set the borderColor like so:
imageViewOne.layer.borderColor = UIColor.clear.cgColor
imageViewOne.layer.borderWidth = 2
However, the underlying imageViewTwo is displayed in the border instead of the background color.
So far, I have this:
Would appreciate some help/ideas on how to make this work - I'm thinking of masks but not sure whether a. this is the correct solution and b. how to achieve the desired effect. To clarify, I am not able to set the border color as a constant as it will change with the UIBlurEffect.
In my opinion, there are 2 way to resolve your problem.
Create and use clipped image for Wow and Love like below Love image.
Another way is using mask property of UIView. Creating a mask image and apply it for mask property.
Mask image looks like.
Code for applying mask.
let imvLoveMask = UIImageView.init(image: UIImage.init(named: "MASK_IMAGE_NAME"));
imvLoveMask.frame = CGRect.init(x: 0, y: 0, width: imvLove.frame.size.width, height: imvLove.frame.size.height);
imvLove.mask = imvLoveMask;
Both of 2 above way can help you achieve what you want in the question. Background of icons in below image is an UIVisualEffectView.
In my opinion, the first way with clipped image is better and faster because you don't need to apply mask for your imageView. But if you don't want to create a clipped image for some reason, you can use the second way.
For more detail, you can take a look at my demo repo
You need to clip part of the image in order to let underlying content be visible in the gaps between images. See playground sample.
Add smile_1, smile_2, smile_3 images to playground resources. I took emoji images from https://emojipedia.org/facebook/.
import UIKit
import PlaygroundSupport
class EmojiView: UIView {
var imageView = UIImageView()
var imageInset = UIEdgeInsets(top: 3.0, left: 3.0, bottom: 3.0, right: 3.0)
var shapeLayer = CAShapeLayer()
var overlap: CGFloat = 0.0 {
didSet {
self.updateShape()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// MARK: UIView
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
override func layoutSubviews() {
super.layoutSubviews()
self.imageView.frame = UIEdgeInsetsInsetRect(self.bounds, self.imageInset)
self.shapeLayer.frame = self.bounds
self.updateShape()
}
// MARK: Private
private func setup() {
self.addSubview(self.imageView)
self.layer.mask = self.shapeLayer
}
private func updateShape() {
let frame = self.bounds
let path = UIBezierPath(rect: frame)
// Cut off part of the image if overlap more then > 0
if 0 < self.overlap {
path.usesEvenOddFillRule = true
path.append(UIBezierPath(ovalIn: CGRect(x: -frame.width + self.overlap, y: 0.0, width: frame.width, height: frame.height)).reversing())
}
self.shapeLayer.path = path.cgPath
}
}
let overlap: CGFloat = 10 // Amount of pixels emojis overlap each other
// Create emoji views
let emojiView_1 = EmojiView(frame: CGRect(x: 5.0, y: 5.0, width: 40.0, height: 40.0))
emojiView_1.imageView.image = UIImage(named: "smile_1")
let emojiView_2 = EmojiView(frame: CGRect(x: emojiView_1.frame.maxX - overlap, y: 5.0, width: 40.0, height: 40.0))
emojiView_2.imageView.image = UIImage(named: "smile_2")
emojiView_2.overlap = overlap
let emojiView_3 = EmojiView(frame: CGRect(x: emojiView_2.frame.maxX - overlap, y: 5.0, width: 40.0, height: 40.0))
emojiView_3.imageView.image = UIImage(named: "smile_3")
emojiView_3.overlap = overlap
let holderView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: emojiView_3.frame.maxX + 5, height: 50.0))
// Add gradient layer
let gradientLayer = CAGradientLayer()
gradientLayer.frame = holderView.bounds
gradientLayer.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
holderView.layer.addSublayer(gradientLayer)
// Add emoji views
holderView.addSubview(emojiView_1)
holderView.addSubview(emojiView_2)
holderView.addSubview(emojiView_3)
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = holderView
use this :
self.imageViewOne.layer.cornerRadius = self.imageViewOne.layer.bounds.width/2
self.imageViewOne.layer.masksToBounds = true
Simple suggestion: As you are setting border color programatically, you have a control to change it, according to background color (if background color is solid (not a gradient)).
imageViewOne.layer.borderColor = imageViewOne.superview?.backgroundColor ?? UIColor.white
imageViewOne.layer.borderWidth = 2.0
Actually instead of masking, you can put your images in a view which has white background and round(set corner radius). Then you can put these views (which has white background and images in it) via settings their zPosition or on storyboard with view hierarchy.
I've prepared a little playground for you. You can see the result in the screenshot. I've put a view inside the containerViews instead you can use uiimageview etc. It's a bit ugly but solves your issue I guess it's up to you to decide how use it.
Here is the code, you can just copy and paste it to a new playground and test it.
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
var mainContainerView = UIView(frame: CGRect(x: 0, y: 0, width: 140, height: 80))
mainContainerView.backgroundColor = UIColor.white
var containerView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
containerView.backgroundColor = UIColor.white
containerView.layer.cornerRadius = containerView.frame.width / 2
var innerView = UIView(frame: CGRect(x: 10, y: 10, width: 60, height: 60))
innerView.backgroundColor = UIColor.red
innerView.layer.cornerRadius = innerView.frame.width / 2
containerView.addSubview(innerView)
var containerView2 = UIView(frame: CGRect(x: 60, y: 0, width: 80, height: 80))
containerView2.backgroundColor = UIColor.yellow
containerView2.layer.cornerRadius = containerView2.frame.width / 2
var innerView2 = UIView(frame: CGRect(x: 10, y: 10, width: 60, height: 60))
innerView2.backgroundColor = UIColor.green
innerView2.layer.cornerRadius = innerView2.frame.width / 2
containerView2.addSubview(innerView2)
containerView.layer.zPosition = 2
containerView2.layer.zPosition = 1
mainContainerView.addSubview(containerView)
mainContainerView.addSubview(containerView2)
PlaygroundPage.current.liveView = mainContainerView

Custom progress view

I want to do a custom progress view for my iOS app, with 2 dots. Here is my code:
import UIKit
#IBDesignable
class StepProgressView: UIView {
#IBInspectable var progress: Float = 0
var progressColor = UIColor.blackColor()
var bgColor = UIColor.whiteColor()
override func layoutSubviews() {
self.backgroundColor = UIColor.clearColor()
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
let height = frame.height-8
let circle1 = UIView(frame: CGRect(x: frame.width*(1/3), y: 0, width: frame.height, height: frame.height))
circle1.backgroundColor = bgColor
circle1.layer.cornerRadius = frame.height/2
addSubview(circle1)
let circle2 = UIView(frame: CGRect(x: frame.width*(2/3), y: 0, width: frame.height, height: frame.height))
circle2.backgroundColor = bgColor
circle2.layer.cornerRadius = frame.height/2
addSubview(circle2)
let bgView = UIView(frame: CGRect(x: height/2, y: 4, width: frame.width-height/2, height: height))
bgView.backgroundColor = bgColor
bgView.layer.cornerRadius = height/2
addSubview(bgView)
let progressView = UIView(frame: CGRect(x: 0, y: 4, width: frame.width*CGFloat(progress), height: height))
progressView.backgroundColor = progressColor
progressView.layer.cornerRadius = height/2
addSubview(progressView)
}
}
The result:
However, as you can see, the circles aren't "filled" when the progression pass over one of them, and I don't know how to do that. I could create another view but I don't know how to handle the corner radius.
Can you help me ?
Thanks

Resources