layer rounded corners on a Swift - swift

I tried to get a rounded corner with layer.cornerRadius for my segmented control but it does not work for me actually I want to get cornerRadius depending on the frame
here is my code
func setupView(){
layer.masksToBounds = true
// here my corner radius
layer.cornerRadius = frame.height / 2.0
layer.borderColor = UIColor.walkthroughOrangeAccent.cgColor
layer.borderWidth = 2
backgroundColor = UIColor.clear
setupImageView()
addIndividualItemConstraints(items: imageViewList, mainView: self, padding: 0)
insertSubview(thumbView, at: 0)
}

I suspect you're not seeing the corner radius because of the layout constraints. Try subclassing the segmented control and setting the corner radius in layoutSubviews:
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = frame.height / 2.0
}
Or, if you're in the view controller:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
segmentedControl.layer.cornerRadius = segmentedControl.frame.width / 2.0
}

Related

How to dynamically set the corner radius of a UIButton?

I have a UIButton in a storyboard that automatically resizes based on the device's current orientation. I have a 1:1 aspect ratio constraint on the button, and the button's corner radius should always be half its width so that it displays as a circle.
I have tried to update the corner radius in viewDidLayoutSubviews as follows:
override func viewDidLayoutSubviews() {
bigButton.layer.cornerRadius = 0.5 * bigButton.bounds.size.width
}
I would expect this to update the corner radius based on the button's width after it resizes. I think what it's actually doing is updating the corner radius based on the button's previous width, causing it to display incorrectly.
Is there an easy way to get the button's width after it resizes? Or is there a different approach to achieve my desired effect? Thanks for the help!
You can make a subclass of UIButton and set the layer.cornerRadius in layoutSubviews.
class RoundButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = bounds.height / 2
}
}
Here is a simple example could be tested in the Playground. You can see the corner radius is reactive every time it changes the size by clicking.
import UIKit
import PlaygroundSupport
class MyViewController: UIViewController {
private var button: RoundButton!
override func loadView() {
let view = UIView()
view.backgroundColor = .white
button = RoundButton()
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(tapButton), for: .touchUpInside)
button.setTitle("Round", for: .normal)
button.backgroundColor = .red
view.addSubview(button)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
self.view = view
}
#objc private func tapButton(_ sender: Any) {
button.contentEdgeInsets.top += 5
button.contentEdgeInsets.bottom += 5
}
}
class RoundButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = bounds.height / 2
}
}
PlaygroundPage.current.liveView = MyViewController()
I was able to achieve the desired effect by setting the corner radius asynchronously:
override func viewDidLayoutSubviews() {
DispatchQueue.main.asyncAfter(deadline: .now()) {
self.bigButton.layer.cornerRadius = 0.5 * self.bigButton.bounds.size.width
}
}
The rotation animation becomes a little clunky, but it should be sufficient for now.

Adding drop shadow to UIView on landscape and portrait mode

I am trying to add a drop shadow to a UIView. Here is my code for adding shadow.
func addDropShadow() {
layer.cornerRadius = 5.0
layer.masksToBounds = false
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowOpacity = 0.5
layer.shadowOffset = CGSize(width: 2, height: 2)
layer.shadowRadius = 4
layer.shadowPath = UIBezierPath(rect: bounds).cgPath
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
}
It works fine if device is in portrait mode, but on landscape mode shadow either gets clipped off
When I rotate device back again to landscape shadow path moves out of screen.
I thought this might be due to orientation change frame of view also gets updated. So I updated shadow path property in viewDidLayoutSubviews method.
But the behaviour remains the same.
Here is my code
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.dropShadowView.layer.shadowPath = UIBezierPath(rect: self.dropShadowView.bounds).cgPath
}
Am I doing something wrong here?.
You will find it much easier to manage the shadow if you make this a subclass of UIView and override layoutSubviews():
#IBDesignable
class SimpleShadowedView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = 5.0
layer.masksToBounds = false
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowOpacity = 0.5
layer.shadowOffset = CGSize(width: 2, height: 2)
layer.shadowRadius = 4
layer.shadowPath = UIBezierPath(rect: bounds).cgPath
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
}
}
Note also that, by adding the #IBDesignable designation you can also see the output during design-time.
Set the Custom Class of your view in Storyboard / Interface builder to SimpleShadowedView:
It will show at runtime:
If you select Editor -> Refresh All Views (or, Automatically Refresh Views), you'll also see it at design-time.

UIView with corner Radius and Shadow view doesn't clip subviews in corners

Below is the code for a custom Card View. The problem is, when I add the subviews to this in Interface builder it doesn't apply the corner radius to the subview. For the most part, I can get away with this by making subviews have a clear background color but I'm struggling with UIImageView. When I add that to a card it ends up with pointy corners and I've not been able to fix it.
Various solutions on here have suggested adding a second layer to display the shadow. I've attempted this but it still doesn't work as intended. What I'm trying to achieve is a view with rounded corners, drop shadow and adding any subviews (such as UIImageView) should also maintain the corner radius and not pointing out.
I've tried various settings with layer.masksToBounds and self.clipsToBounds and I always seem to get subviews with a corner radius but no shadow or the shadow visible and views not clipping.
#IBDesignable class CardView: UIView {
#IBInspectable dynamic var cornerRadius: CGFloat = 6
#IBInspectable dynamic var shadowOffsetWidth: Int = 2
#IBInspectable dynamic var shadowOffsetHeight: Int = 2
#IBInspectable dynamic var shadowColor: UIColor? = UIColor(netHex: 0x333333)
#IBInspectable dynamic var shadowOpacity: Float = 0.5
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
commonInit()
}
override func prepareForInterfaceBuilder() {
commonInit()
}
func commonInit() {
layer.cornerRadius = cornerRadius
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
layer.masksToBounds = false
layer.shadowColor = shadowColor?.cgColor
layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight)
layer.shadowOpacity = shadowOpacity
layer.shadowPath = shadowPath.cgPath
// This was how I tried to add a seperate shadow layer
// let shadowView = UIView(frame: self.frame)
// shadowView.layer.shadowColor = shadowColor?.cgColor
// shadowView.layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight)
// shadowView.layer.shadowOpacity = shadowOpacity
// shadowView.layer.shadowPath = shadowPath.cgPath
// shadowView.layer.masksToBounds = false
//
// self.addSubview(shadowView)
}
}
The way you were trying to implement a second view to handle shadows is almost correct, you just didn't keep the right order.
Your CardView class already handles displaying a shadow. Leave that view as it is and instead add a UIView called "ContentView" as a subview. That content view has the same frame and corner radius as your CardView.
On the "ContentView", you don't need to do any work with shadows. Instead, set its layer's masksToBounds property to true. Now add all the content you want to display in your Card to the "ContentView" and it should clip correctly.
func commonInit() {
layer.cornerRadius = cornerRadius
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
layer.masksToBounds = false
layer.shadowColor = shadowColor?.cgColor
layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight)
layer.shadowOpacity = shadowOpacity
layer.shadowPath = shadowPath.cgPath
let contentView = UIView()
contentView.frame = self.frame
contentView.layer.cornerRadius = cornerRadius
contentView.layer.masksToBounds = true
// any content you add should now be added to the contentView:
// contentView.addSubview(aView)
}
furthermore, you can specific corners.
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner]

How to set shadow outline (solid) around UIImageView text in Swift?

I want to set shadow outline (solid) around UIImageView text.
I tried below code: -
class BottomToolBarImageView: UIImageView {
override func layoutSubviews() {
super.layoutSubviews()
layer.shadowColor = UIColor.red.cgColor
layer.shadowOffset = CGSize(width: 5.0, height: 5.0)
layer.shadowOpacity = 1.0
layer.shadowRadius = 0.0
}
}
But this is not working as I required. Please suggest. Thanks in advance.
I required output like: -
To achieve this, you should add border to image view, instead of shadow.
class BottomToolBarImageView: UIImageView {
override func layoutSubviews() {
super.layoutSubviews()
layer.borderColor = UIColor.red.cgColor
layer.borderWidth = 4.0
layer.cornerRadius = self.frame.size.height/2
}
}
This should work.
P.S Kindly change cornerRadius according to required output.

image disappears when styling class to make a round image

class RoundImage: UIImageView {
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
...
func setupView() {
self.layer.borderWidth = borderWidth
self.layer.borderColor = borderColor
self.clipsToBounds = clip
self.layer.cornerRadius = self.frame.size.width / 2
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupView()
}
}
I am using the following class to style my UIImageViews. I want to make them circular. When I add the following line of code self.layer.cornerRadius = self.frame.size.width / 2 to make this possible, my entire image disappears.
When I use a hardcoded value like 50 (since the width of my image is 100) it works. But when I want to make it dynamic this way, it seems to fail.
What am I missing here?
I faced with this problem a few days ago.
You should add layoutIfNeeded() before layer modifications.
In your case:
func setupView() {
self.layoutIfNeeded()
self.layer.borderWidth = borderWidth
self.layer.borderColor = borderColor
self.clipsToBounds = clip
self.layer.cornerRadius = self.frame.size.width / 2
}
When this code gets run the view hasn't been sized yet, so the width is incorrect. Try putting a listener on frame:
override var frame : CGRect {
didSet {
layer.cornerRadius = frame.size.width / 2
}
}