I'm facing a very strange problem right now where the same code produces different results on a UIView
and a UIImageView
.
I have a custom UITableViewCell
. To add a shadow and also got some separation between the cells. I've used a container view that contains the shadow and the rounded corners. Everything works as expected.
One layer below I use a UIStackView
so I can easily remove the image of the cell if the post has no image at all. This stack view contains one image and another stack view. The corner radius on top of the outer container view doesn't work because the image has no rounded corners. So I've tried to implement this for the image and also for a view above that image that is used as an overlay.
The overlay is outside of the stack view. Now, I've written some code to also add the corner radius to these both views and it works perfectly on the overlay but not on the UIImageView. Even when I pull out the image out of the stack views.
Here is what it looks like:
I've used a slightly bigger corner radius to visualize it and added a border to the image.
What I expect to happen: The image has exactly the same width and corner radius on the correct sides like the overlay (grey).
Here is the code for the custom UIImageView class:
import UIKit
@IBDesignable
class RoundedImageView: UIImageView {
@IBInspectable var cornerRadius: CGFloat = 0.0 { didSet { setUpView() } }
@IBInspectable var isOnlyTop: Bool = false { didSet { setUpView() } }
override func awakeFromNib() {
super.awakeFromNib()
}
override func draw(_ rect: CGRect) {
setUpView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setUpView()
}
func setUpView() {
self.clipsToBounds = true
self.layer.borderColor = UIColor.green.cgColor
self.layer.borderWidth = 2.0
if isOnlyTop {
setTopCornerRadius()
} else {
self.layer.cornerRadius = cornerRadius
}
}
func setTopCornerRadius() {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners:[.topLeft, .topRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
self.layer.masksToBounds = true
}
}
I've copied the code from the rounded view. However, for completion I will add it below:
import UIKit
@IBDesignable
class RoundedView: UIView {
@IBInspectable var cornerRadius: CGFloat = 0.0 { didSet { setUpView() } }
@IBInspectable var isOnlyTop: Bool = false { didSet { setUpView() } }
override func awakeFromNib() {
super.awakeFromNib()
setUpView()
}
override func draw(_ rect: CGRect) {
setUpView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setUpView()
}
func setUpView() {
self.clipsToBounds = true
self.layer.borderColor = UIColor.red.cgColor
//self.layer.borderWidth = 2.0
if isOnlyTop {
setTopCornerRadius()
} else {
self.layer.cornerRadius = cornerRadius
}
}
private func setTopCornerRadius() {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners:[.topLeft, .topRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
}
Here is the whole view tree of the cell:
I know, that I am violating the DRY principle here, but I just have written the same code for UIView and UIImageView so I can verify why it doesn't work.
Hint: Notice that I have two times the same UIImage in this cell (Post Image and Image out of stack view) as I thought it is maybe caused by Constraints or the stack view. So the image outside of the stack view has exactly the same constraints as the Overlay View.
So long story short: Do you know why my UIImageView has the wrong size and also doesn't apply the corner radius that works perfectly on the Overlay View (UIView). Thanks in advance!
EDIT: The expected result should look like this. Unless the top corners of the image should also be rounded (you see that little difference at the top corners of the image? That's caused by the overlay. It has the correct corner radius but the image doesn't).
EDIT 2: I was asked to add the code of the view controller. However, I don't change anything here.
import UIKit
protocol PostListDisplayLogic: class {
}
class PostListViewController: UIViewController, PostListDisplayLogic, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
var interactor: PostListBusinessLogic?
var router: (NSObjectProtocol & PostListRoutingLogic & PostListDataPassing)?
// MARK: Object lifecycle
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
// MARK: Setup
private func setup() {
let viewController = self
let interactor = PostListInteractor()
let presenter = PostListPresenter()
let router = PostListRouter()
viewController.interactor = interactor
viewController.router = router
interactor.presenter = presenter
presenter.viewController = viewController
router.viewController = viewController
router.dataStore = interactor
}
// MARK: Routing
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let scene = segue.identifier {
let selector = NSSelectorFromString("routeTo\(scene)WithSegue:")
if let router = router, router.responds(to: selector) {
router.perform(selector, with: segue)
}
}
}
// MARK: View lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
tableView.register(UINib(nibName: "PostCell", bundle: nil), forCellReuseIdentifier: "PostCell")
}
// MARK: TableView DataSource & Delegate
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell {
return cell
}
return UITableViewCell()
}
}