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)
}
Related
I need to change custom UITableview section header corner radius dynamically. Initially section header corner radius is 5 for all corners. After adding cell to section, bottom left and bottom right corners should remove. I changed that in layout subview method of custom UITableViewHeaderFooter class. But its not reflecting, corner radius added for all corners, not changing when adding cell. My code is:
override func layoutSubviews() {
super.layoutSubviews()
textLabel?.textColor = UIColor.black
contentView.backgroundColor = UIColor.clear
backgroundView?.backgroundColor = UIColor.white
if let sections = self.sections, let sectionIndex = self.sectionIndex, let values = sections[sectionIndex].values, values.count > 0, sections[sectionIndex].expanded {
layer.cornerRadius = 5
self.setRoundCorners(cornerRadius: 5, corners: [.topLeft, .topRight])
} else {
layer.cornerRadius = 5
layer.mask = nil
}
}
UIView extension
func setRoundCorners(cornerRadius: CGFloat, corners: UIRectCorner) {
let path = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
layer.mask = maskLayer
}
I have a UIImageView inside of a UICollectionView Cell and I wanna make it' s top corners rounded. I couldn' t solve on my on, any help is appreciated.
You can see cell has 10px corner radius and I want same effect to be applied on image too.
You can try UIRectCorner Document here
here my custom class AGRoundCornersView
extension UIImageView {
public func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let maskPath = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
layer.mask = shape
}
}
code :
1. Call When View is resized.
uiimage.roundCorners([.topLeft, .topRight], radius: 10)
2. Create custom class
class CustomImageView: UIImageView {
override func layoutSubviews() {
super.layoutSubviews()
self.roundCorners([.topLeft, .topRight], radius: 10)
}
}
Swift 5
In your collectionview cell, put the below two lines of code & you are good to go. No need to write any extension:
cell._imageView.layer.cornerRadius = 10
cell._imageView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
Here corner radius will apply TopLeft & TopRight corners & rest of corners will remain same.
If you want to apply the corner radius in BottomLeft & BottomRight corners, then maskedCorners should look like the below:
cell._imageView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
Hope it helps.
Try this in your UICollectionViewCell
override func awakeFromNib() {
super.awakeFromNib()
DispatchQueue.main.async {
self.image.roundCorners([.topRight,.topLeft], radius: 8)
self.image.layer.masksToBounds = true
}
}
Thanks to AshvinGudaliya and Sujewan
Following code worked for my collection cell's ImageView Top Left-Right corners
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:TUGBucketCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! TUGBucketCell
//Rounded corner ImageView
DispatchQueue.main.async {
cell.imgVw.roundCorners([.topLeft, .topRight], radius: 10)
cell.imgVw.layer.masksToBounds = true
}
return cell
}
and the extension is
extension UIImageView {
public func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
let maskPath = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
layer.mask = shape
}
}
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.
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
I'm new to iOS development and trying to create a custom UITableViewCell that has a background which top-left and bottom-left corners I want to round, but it only works for the top-left corner.
Here is my code (Swift 3):
override func awakeFromNib() {
super.awakeFromNib()
let bgViewMask = CAShapeLayer()
let bgViewPath = UIBezierPath(
roundedRect: bgView.bounds,
byRoundingCorners: [.topLeft, .bottomLeft],
cornerRadii: CGSize(width: 8, height: 8)
)
bgViewMask.frame = bgView.bounds
bgViewMask.path = bgViewPath.cgPath
bgView.layer.mask = bgViewMask
}
I also tried this in layoutSubviews()
override func layoutSubviews() {
super.layoutSubviews()
//code here
}
but it didn't work as well.
If I use bgView.layer.cornerRadius = 8 it works for all corners.
Am I doing anything wrong?
You can try this:
import UIKit
class CustomImageView: UIImageView {
override public func layoutSubviews() {
super.layoutSubviews()
self.roundUpCorners([.topLeft, .bottomLeft], radius: 8)
}
}
extension UIView {
func roundUpCorners(_ 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
}
}