Bezierpath button width issue - ios

func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
I am using this function to give corner radius from particular side for UIButton. I am calling this function into UITableViewCell but I am having issue like I gave constraint to button like its width is changing as per device width change for exa if device is iPhone 5 then its width is 159.5 acoordingly half of screen width. but it is not changing and button is cutting from its width.
I am calling this function in TableviewCell
override func layoutSubviews() {
super.layoutSubviews()
self.btnWithdraw.roundCorners([.bottomRight], radius: 4.0)
self.btnAddFund.roundCorners([.bottomLeft], radius: 4.0)
}
But here issue is like It is taking original frame as per given in storyboard viewcontroller and button is not taking width as per constraints.
Any help would appreciated.
Thank you

Perhaps the problem is that you are assuming that layoutSubviews will be called on the cell under all circumstances where the button is being laid out afresh. That might not be true.
To avoid that assumption, implement your entire masking in the button itself, along these lines:
class MyButton : UIButton {
var whatCorners : UIRectCorner = [.bottomRight]
var whatRadius : CGFloat = 4.0
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
override func layoutSubviews() {
super.layoutSubviews()
self.roundCorners(self.whatCorners, radius: self.whatRadius)
}
}
That way, you can give each button the desired values for whatCorners and whatRadius and the button will round itself.

Related

Error Specific RoundCorners on Old Devices?

I added round corners function extension inside UIView
it works perfectly on a new device like iPhone XR but the old device with 16:9 ratio like iPhone 8,iPhone 8 plus it corners in just the left
extension UIView{
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
When I implement the function. inside the UIViewController, I call the function inside viewDidLayoutSubviews
//ViewController
override func viewDidLayoutSubviews() {
exampleView.roundCorners([.topRight,.topLeft], radius: 20)
}
but when I implement in class with another type I couldn't find a solution,
I want a method to force take the corner always.
If you want a view to always have cornerradius you can use following snippet:
#IBDesignable extension UIView{
#IBInspectable var cornerRadius : CGFloat{
get{
return self.layer.cornerRadius
}set{
layer.cornerRadius = newValue
clipsToBounds = true
}
}
}
You can set the radius in the InterfaceBuilder or in code.

UIBezierPath not rendering properly

I have a tablviewcell which has uiview in it.
Based on some logic I change the background color and make the left and right corner rounded.
I make these view corner round from cellForRowat indexPath function.
Here is my extension.
extension UIView {
func roundCorners(corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
and how I use it
cell?.myCustomView.roundCorners(corners: [.bottomRight,.bottomLeft], radius: 10.0)
Its working fine when width of iphones is 375,
but it fails to update for device with width greater than 375.
And after scrolling the tableview, it again stretches back correctly to the desired width.
How to solve this problem ?
You want to update the path when the view changes size. In cellForRowAt the cell has not yet been fully laid-out by auto-layout.
So...
Create a UIView subclass for your "rounded corners" view (simple example):
class RoundedCornersView: UIView {
var corners: UIRectCorner = UIRectCorner()
var radius: CGFloat = 0.0
override func layoutSubviews() {
super.layoutSubviews()
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
Now, anytime the view changes size - such as on first use or device rotation, for example - the view will automatically update the path.
Here is how you would use it in a table cell. In Storyboard, set the class of the "background view" to RoundedCornersView
class RoundedCornersView: UIView {
var corners: UIRectCorner = UIRectCorner()
var radius: CGFloat = 0.0
override func layoutSubviews() {
super.layoutSubviews()
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
layer.mask = mask
}
}
class MyTestCell: UITableViewCell {
#IBOutlet var myCustomView: RoundedCornersView!
}
Then, in cellForRowAt:
let cell = tableView.dequeueReusableCell(withIdentifier: "MyTestCell", for: indexPath) as! MyTestCell
if shouldBeRounded {
cell.myCustomView.corners = [.bottomRight, .bottomLeft]
cell.myCustomView.radius = 10.0
cell.myCustomView.backgroundColor = .green
} else {
cell.myCustomView.corners = []
cell.myCustomView.radius = 0.0
cell.myCustomView.backgroundColor = .white
}
return cell
Use this:
override func draw(_ rect: CGRect) {
super.draw(rect)
selectedView.roundCorners(corners: [.topLeft, .topRight], radius: 12.0)
}

Custom Card View design in Table View Cell in XCode

Is it possible to create interaction enabled sidebar solely in the utility area of the storyboard, or does it need any custom UI class?
Related question: How to give shadow like card in iOS
Try this
Create two UIView like this
- Set corner radius to the backView
- Set corner radius to the frontView, only for rightBottom and rightTop portions by using below method
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
Refer my code
https://github.com/leninsmannath/CardViewSample.git

rounding corners of UIbutton disturbing its width

I have three buttons in which I want to round:
Top corners of first button
Bottom corners of second button
All four corners of third button
I achieved this by the following code:
button1.roundedButton1()
button2.roundedButton2()
button3.layer.cornerRadius = 5
extension UIButton {
func roundedButton1(){
let maskPAth1 = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.topLeft , .topRight],
cornerRadii:CGSize(width:5.0, height:5.0))
let maskLayer1 = CAShapeLayer()
// maskLayer1.frame = self.bounds
maskLayer1.path = maskPAth1.cgPath
self.layer.mask = maskLayer1
}
func roundedButton2(){
let maskPAth1 = UIBezierPath(roundedRect: self.bounds,
byRoundingCorners: [.bottomLeft , .bottomRight],
cornerRadii:CGSize(width:5.0, height:5.0))
let maskLayer1 = CAShapeLayer()
maskLayer1.frame = self.bounds
maskLayer1.path = maskPAth1.cgPath
self.layer.mask = maskLayer1
}
}
But the width of my 1st and 2nd button is getting disturbed.
If I use button2.layer.cornerRadius = 5 then the width becomes alright. I have searched which code it altering its width but didn't find anything appropriate. And this is the only working solution i found for UIButton.Can anyone tell me why the width of button is changing and how to fix it?
The constraints of button are as follows:
Instead of using UIButton you can achieve this result by using UIView & UITapGestureRecognizer
add this extension
extension UIView {
func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
then create a custom view class
class CustomView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
self.roundCorners([.topRight, .topLeft], radius: 5) // you can use .topRight , .topLeft , .bottomRight, .bottomLeft
}
}
then use the class on your view
Hope this will help you

Round Corners of resizable view

Ive been using the code shown below to round selected corners of views, however am now having trouble achieving this on a resizable view as the layer? isn't updated each time the view is resized.
extension UIView {
func roundCorners(corners:UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
titleLabelView.roundCorners(corners: [.topLeft, .topRight], radius: 10)
There is a similar question here but its quite old and all done in objC.
Is there a way of rounding selected corners in swift for resizable views?
----- EDIT -----
So essentially what i have is a text table that i have set to resize based on the size of the text.
In most cases i can just use:
myTextLabel.layer.cornerRadius = 10
However this does all 4 corners. So if i want to round just the top 2 then i need to use the extension above. Now because i am using scrollViewDidEndDecelerating to set the content for the label (i need to get the indexPath for the cell at the centre of the collectionView so i can set the text label)
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
GeneralFunctions.getIndexOfCell(sender: self) { (index) in
self.titleLabel.text = self.partArray[index].title
self.titleLabel.roundCorners(corners: [.topLeft, .topRight], radius: 10)
self.descriptionLabel.text = self.partArray[index].description
self.descriptionLabel.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 10)
self.backgroundLabelView.layer.cornerRadius = 16
self.backgroundLabelView.layoutIfNeeded()
self.backgroundLabelView.layoutSubviews()
}
}
Using viewDidLayoutSubViews doesn't work in this case as there is a lag between accelerating ending and the layout. I have tried using the same code(without the check for the centre index) inside viewDidLayoutSubViews but the result is the same.
And The label does resize correctly when i don't use any of the corner rounding.
I had similar problem, I've solved it by using this function like
DispatchQueue.main.async(execute: {
self.roundCorners(.allCorners, radius: 6, borderColor: nil, borderWidth: nil)
})
I am using this function a lot for UITableViewCell, and my whole code looks like
private var didLayoutSubview = false {
didSet {
DispatchQueue.main.async(execute: {
self.roundCorners(.allCorners, radius: 6, borderColor: nil, borderWidth: nil)
})
}
}
override func layoutSubviews() {
if !self.didLayoutSubview {
self.didLayoutSubview = true
}
super.layoutSubviews()
}
So basically, calling this function in main thread helped, and I am calling it inside layoutSubivews because I think it is the place.
My function
func roundCorners(_ corners: UIRectCorner, radius: CGFloat, borderColor: UIColor?, borderWidth: CGFloat?) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.frame = self.bounds
mask.path = path.cgPath
self.layer.mask = mask
if borderWidth != nil {
addBorder(mask, borderWidth: borderWidth!, borderColor: borderColor!)
}
}

Resources