i have a cell, that contains containerView with top and bottom cornerRadius = 8. Then i have to put UIImageView with contentMode = .scaleAspectFit and corner radius ONLY on the top (cornerRadius = 8) But the problem that code 'corner radius' is not working with contentMode = .scaleAspectFit
Here is properties
let containerView: UIView = {
let view = UIView()
view.layer.cornerRadius = 8
return view
}()
let imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.layer.cornerRadius = 8
imageView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
imageView.clipsToBounds = true
return imageView
}()
Here is SnapKit method
private func setupViews() {
addSubview(containerView)
containerView.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview()
make.top.bottom.equalToSuperview()
}
containerView.addSubview(imageView)
imageView.snp.makeConstraints { make in
make.top.equalTo(containerView.snp.top)
make.trailing.equalTo(containerView.snp.trailing)
make.leading.equalTo(containerView.snp.leading)
}
}
as a result i got , i need my image.top EqualToContainer.top and with cornerRadius on the top
You haven't given the image view a height constraint, and a UIImageView
has no intrinsic size until its .image
has been set.
So, when you set the image, the image view will use the height of the image to set its own height. Then, because you're telling it to use .scaleAspectFit
, you get the image centered in the new height.
What you need to do is leave the image view at the default of .scaleToFill
and then set its height constraint to use the same proportion as the image.
A quick example, using these two images:
We want it to look like this (I've exaggerated the corner radius to make it obvious):
We'll use a UIView
subclass -- but the same thing will apply when using this in a cell:
class AspectView: UIView {
public var image: UIImage? {
didSet {
// set the image view's image
imageView.image = image
// if height constraint is already set
if let h = hConstraint {
// deactivate it
h.isActive = false
}
// set new height constraint to image aspect ratio
imageView.snp.makeConstraints { make in
self.hConstraint = make.height.equalTo(imageView.snp.width).multipliedBy(image!.size.height / image!.size.width).constraint
}
}
}
private var hConstraint: Constraint!
private let containerView: UIView = {
let view = UIView()
// using corner radius of 32 to make it very obvious
view.layer.cornerRadius = 32
// this will clip the image view subview
view.clipsToBounds = true
return view
}()
private let imageView: UIImageView = {
let imageView = UIImageView()
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupViews()
}
public func addImage(_ img: UIImage) {
imageView.image = img
print(img.size)
if let h = hConstraint {
h.isActive = false
}
imageView.snp.makeConstraints { make in
self.hConstraint = make.height.equalTo(imageView.snp.width).multipliedBy(img.size.height / img.size.width).constraint
}
}
private func setupViews() {
addSubview(containerView)
containerView.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview()
make.top.bottom.equalToSuperview()
}
containerView.addSubview(imageView)
imageView.snp.makeConstraints { make in
make.top.equalTo(containerView.snp.top)
make.trailing.equalTo(containerView.snp.trailing)
make.leading.equalTo(containerView.snp.leading)
}
// so we can see the containerView frame
containerView.backgroundColor = .systemBlue
}
}
and a sample controller class - tapping anywhere will toggle between the two images:
class AspectTestVC: UIViewController {
let testView = AspectView()
let imgNames: [String] = [
"p320x160",
"p320x240",
]
var imgIdx: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// bkg640x360
view.addSubview(testView)
testView.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview().inset(40.0)
make.height.equalTo(400.0)
}
if let img = UIImage(named: imgNames[imgIdx % imgNames.count]) {
testView.image = img
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
imgIdx += 1
if let img = UIImage(named: imgNames[imgIdx % imgNames.count]) {
testView.image = img
}
}
}