I'm trying to build a UIView of Social Media User's Profile and got stuck right in the beginning - when adding a User Image (UIImage) to my UIView. Here's the code I'm trying to use:
import UIKit
class ProfileHeaderView: UIView {
private lazy var profileImage: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "hipsterCat"))
// Making Image Round
imageView.layer.cornerRadius = imageView.frame.size.width / 2
imageView.clipsToBounds = true
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = 3
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
private func setupView() {
backgroundColor = .lightGray
addSubview(profileImage)
}
override func layoutSubviews() {
super.layoutSubviews()
profileImage.frame = CGRect(
x: bounds.midX - 64,
y: bounds.midY - 64,
width: 128,
height: 128
)
}
}
My task is to use CGRect to position UIImage on the superView, yet once I run the project it just doesn't appear on the screen (only light gray background is there).
UIImageView is all right, the image appears when commenting layoutSubviews() override but it's not positioned.
There are multiple things that might have gotten wrong. The strangest result you are seeing is that you don't see the image at all once it is resized.
My best guess is that you are also setting the frame for the ProfileHeaderView
instance. Note that there are 2 APIs for lay outing the views; one is using frame
and the other one is auto layout. From auto layout a method layoutSubviews
will be called. But using frame
then only frame
will be called. So you may be missing another override.
Try to add the following:
override var frame: CGRect {
didSet {
updateImagePosition()
}
}
override func layoutSubviews() {
super.layoutSubviews()
updateImagePosition()
}
private func updateImagePosition() {
profileImage.contentMode = .scaleAspectFit
profileImage.frame = CGRect(
x: bounds.midX - 64,
y: bounds.midY - 64,
width: 128,
height: 128
)
profileImage.layer.cornerRadius = 64
}
Next to adding an override for frame I have also added to option to determine content mode of your view. You might want to move that into your setup method but it is not too bad if it stays here. And the other one is setting corner radius which for sure needs to be set in here. Both mentioned by @HangarRash.
In the end it would be nice to have something like the following to be fair:
@IBDesignable
class ProfileHeaderView: UIView {
@IBInspectable
private var imageName: String = "hipsterCat" {
didSet {
profileImage.image = UIImage(named: imageName)
}
}
@IBInspectable
private var imageRadius: CGFloat = 64 {
didSet {
updateImagePosition()
}
}
private lazy var profileImage: UIImageView = {
let imageView = UIImageView(image: UIImage(named: imageName))
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = 3
return imageView
}()
override var frame: CGRect {
didSet {
updateImagePosition()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
private func setupView() {
backgroundColor = .lightGray
addSubview(profileImage)
}
override func layoutSubviews() {
super.layoutSubviews()
updateImagePosition()
}
private func updateImagePosition() {
profileImage.frame = CGRect(
x: bounds.midX - imageRadius,
y: bounds.midY - imageRadius,
width: imageRadius*2.0,
height: imageRadius*2.0
)
profileImage.layer.cornerRadius = imageRadius
}
}