I have a custom UITableViewCell that displays a circular image on the left-hand side. Since the default UIImageView supplied with the UITableViewCell is the same height as the row, the images end up nearly touching. I'd like to shrink the image slightly to create some extra padding.
I was able to get this to work using the following code
override func layoutSubviews() {
super.layoutSubviews()
// Make the image view slightly smaller than the row height
self.imageView!.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
// Round corners
self.imageView!.layer.cornerRadius = self.imageView!.bounds.height / 2.0
self.imageView!.layer.borderWidth = 0.5
self.imageView!.layer.borderColor = UIColor.gray.cgColor
self.imageView!.layer.masksToBounds = true
self.imageView!.contentMode = .scaleAspectFill;
self.updateConstraints()
}
override func prepareForReuse() {
super.prepareForReuse()
self.imageView!.image = nil
self.layoutSubviews()
}
This works only for the cells displayed in the table view when it first appears on the screen. Once I scroll (i.e. dequeue a re-usable cell), the transform is no longer applied. The image below shows the left side of the table view. I've captured the region where the original cells transition to re-used cells.
For completeness, here is my tableView(cellForRowAt:) function
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.itemTableView.dequeueReusableCell(withIdentifier: "ItemCell") as! InventoryItemTableViewCell
if let items = self.displayedItems {
if indexPath.row < items.count {
let item = items[indexPath.row]
cell.item = item
cell.textLabel!.text = items[indexPath.row].partNumber
cell.detailTextLabel!.text = items[indexPath.row].description
if let quantity = items[indexPath.row].quantity {
cell.quantityLabel.text = "Qty: \(Int(quantity))"
}
else {
cell.quantityLabel.text = "Qty: N/A"
}
if let stringImageBase64 = item.imageBase64 {
let dataDecoded: Data = Data(base64Encoded: stringImageBase64, options: .ignoreUnknownCharacters)!
cell.imageView!.image = UIImage(data: dataDecoded)
}
else {
cell.imageView!.image = blankImage
}
}
}
return cell
}
I tried other methods such as playing with the image view's insets but this had no effect.
Question
Why is the transform being applied to the original cells when the table is created but not to any re-used cells? Should I be approaching this differently?
I was able to accomplish resizing the image using the following code. It seems the autolayout is applied after the transform, therefore overriding it.
override func layoutSubviews() {
// Layout all subviews except for the image view
super.layoutSubviews()
// Make the image view slightly smaller than the row height
self.imageView!.frame = CGRect(x: self.imageView!.frame.origin.x + 4,
y: self.imageView!.frame.origin.y + 4,
width: 56,
height: 56)
// Round corners
self.imageView!.layer.cornerRadius = self.imageView!.frame.height / 2.0
self.imageView!.layer.borderWidth = 0.5
self.imageView!.layer.borderColor = UIColor.gray.cgColor
self.imageView!.layer.masksToBounds = false
self.imageView!.clipsToBounds = true
self.imageView!.contentMode = .scaleAspectFit;
}
Related
I'm pretty new so apologies if my title doesn't phrase things correctly. I've been hacking away and haven't been able to find an answer to this problem.
I have a horizontally scrolling collection. I'm trying to visually show poll results programatically adding CGRect to the relevant item in the collection based on voting data held in a Firestore array.
This is working, but the problem is when you scroll away (so the item in the collection is off screen) and then back, the code to draw the CGRects gets triggered again and more graphics get added to the view. Is there a way to delete these CGRects when the user scrolls an item collection off screen so when the user scrolls the item back into view, code is triggered again it doesn't create duplicates?
Here are a couple of screenshots showing first and second load
Here is my code (cell b is where the CGrect gets triggered)
//COLLECTION VIEW CODE
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.sentCollectionView {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "sCell", for: indexPath) as! SentCollectionViewCell
cellA.sentQuestionLabel.text = sentMessages[indexPath.row].shoutText
// Set up cell
return cellA
}
else {
let cellB = receivedCollectionView.dequeueReusableCell(withReuseIdentifier: "pCell", for: indexPath) as! ReceivedCollectionViewCell
receivedMessages[indexPath.row].pollTotal = receivedMessages[indexPath.row].pollResults.reduce(0, +)
print("Sum of Array is : ", receivedMessages[indexPath.row].pollTotal!)
cellB.receivedShoutLabel.text = receivedMessages[indexPath.row].shoutText
print(receivedMessages[indexPath.row].pollResults.count)
if receivedMessages[indexPath.row].pollResults != [] {
for i in 0...receivedMessages[indexPath.row].pollResults.count - 1 {
cellB.resultsView.addSubview(sq(pollSum: receivedMessages[indexPath.row].pollTotal!, pollResult: receivedMessages[indexPath.row].pollResults[i]))
}
}
return cellB
}
}
//THIS DRAWS THE CGRECT
func sq(pollSum: Int, pollResult: Int) -> UIView {
// divide the width by total responses
let screenDivisions = Int(view.frame.size.width) / pollSum
// the rectangle top left point x axis position.
let xPos = 0
// the rectangle width.
let rectWidth = pollResult * screenDivisions
// the rectangle height.
let rectHeight = 10
// Create a CGRect object which is used to render a rectangle.
let rectFrame: CGRect = CGRect(x:CGFloat(xPos), y:CGFloat(yPos), width:CGFloat(rectWidth), height:CGFloat(rectHeight))
// Create a UIView object which use above CGRect object.
let greenView = UIView(frame: rectFrame)
// Set UIView background color.
greenView.backgroundColor = UIColor.green
//increment y position
yPos = yPos + 25
return greenView
}
Cells of collection are dequeued dequeueReusableCell , you need to override prepareForReuse
Or set a tag
greenView.tag = 333
And inside cellForItemAt do this
cellB.resultsView.subviews.forEach {
if $0.tag == 333 {
$0.removeFromSuperview()
}
}
if receivedMessages[indexPath.row].pollResults != [] {
for i in 0...receivedMessages[indexPath.row].pollResults.count - 1 {
cellB.resultsView.addSubview(sq(pollSum: receivedMessages[indexPath.row].pollTotal!, pollResult: receivedMessages[indexPath.row].pollResults[i]))
}
}
In a section of my UITableView, there are 5 cells, three of which have been configured to expand/collapse to provide a more detailed view when selected. One of these cells shows a diagram of a number of small squares, which displays perfectly, until another cell is expanded, like this:
When the cell is collapsed, however, the subviews in the cell display in different cells, in different sections, like this:
and this:
To create the subviews in the cell, this is my code in the cellForRow method, which just uses an array of UIViews:
for vote in vote_array {
cell.contentView.addSubview(vote as? UIView ?? UIView.init(frame: CGRect.init(x: 0, y: 0, width: 0, height: 0)))
}
I tried removing all the subviews before I added them by doing this, but it doesn't change anything:
for subview in cell.contentView.subviews {
subview.removeFromSuperview()
}
Edit: This is inside a switch statement, but here is the relevant cell/case cellForRow:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.contentView.clipsToBounds = true
cell.clipsToBounds = true
let vote_array = getVoteArray()
for subview in cell.contentView.subviews {
subview.removeFromSuperview()
}
for case let vote as UIView in vote_array {
cell.contentView.addSubview(vote)
}
Edit:
The core of getVoteArray:
func getVoteArray() -> NSMutableArray {
var i = 0
var x = 20
var y = 4
let blockViews : NSMutableArray = []
for color in blocks {
let block = UIView.init(frame: CGRect.init(x: x, y: y, width: 20, height: 20))
block.backgroundColor = color as? UIColor
blockViews.add(block)
x = x + 24
i = i + 1
if i == num_blocks_per_row { i = 0; y = y + 24; x = 20 }
}
diagramHeight = y + 24
return blockViews
}
I can't seem to figure out why the subviews are generating randomly all over the tableView.
Ended up adding
for case let cell as UITableViewCell in tableView.subviews {
for subview in cell.contentView.subviews {
if subview.tag == 115 {
subview.removeFromSuperview()
}
}
}
to my didSelectRowAt method, after adding the tag when each view is created. I'm still not sure why the views were being added to different cells, but this got rid of them at least.
Try to implement unique ReuseIdentifiers for collapsed and expanded states.
If the cell is collapsed then don't load all those views in it by dequeuing a collapsedCell where the height of all those UIViews is either 0 or they are not added to subview.
If the cell is expanded than deque a expandedCell where the views are layed out as in the first screenshot.
After expanding and or collapsing call tableview.reloadData()
It used to be a long long time ago that UIViews clipped their children, but that hasn't been true for a very long time. If you want clipping on you need to either change UIView.clipsToBounds to true or use the underlying CALayer property maskToBounds.
cell.contentView.clipsToBounds = true
Or you can check the box in the storyboard/nib.
I am loading a number of remote images with Kingfisher and having significant difficulty getting them to load correctly into a Tableview with cells of dynamic heights. My goal is to have the images always be the full width of the screen and of a dynamic height, how can this be achieved?
I asked a related question previously which led to understanding the basic layout using a stack view: SnapKit: How to set layout constraints for items in a TableViewCell programatically
So I've built something like the following:
With the following code (some parts removed for brevity):
// CREATE VIEWS
let containerStack = UIStackView()
let header = UIView()
let headerStack = UIStackView()
let title = UILabel()
let author = UILabel()
var previewImage = UIImageView()
...
// KINGFISHER
let url = URL(string: article.imageUrl)
previewImage.kf.indicatorType = .activity
previewImage.kf.setImage(
with: url,
options: [
.transition(.fade(0.2)),
.scaleFactor(UIScreen.main.scale),
.cacheOriginalImage
]) { result in
switch result {
case .success(_):
self.setNeedsLayout()
UIView.performWithoutAnimation {
self.tableView()?.beginUpdates()
self.tableView()?.endUpdates()
}
case .failure(let error):
print(error)
}
}
...
// LAYOUT
containerStack.axis = .vertical
headerStack.axis = .vertical
headerStack.spacing = 6
headerStack.addArrangedSubview(title)
headerStack.addArrangedSubview(author)
header.addSubview(headerStack)
containerStack.addArrangedSubview(header)
containerStack.addSubview(previewImage)
addSubview(containerStack)
headerStack.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(20)
}
containerStack.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
Without a constraint for imageView, the image does not appear.
With the following constraint, the image does not appear either:
previewImage.snp.makeConstraints { make in
make.leading.trailing.bottom.equalToSuperview()
make.top.equalTo(headerView.snp.bottom).offset(20)
}
With other attempts, the image is completely skewed or overlaps the labels/other cells and images.
Finally, following this comment: With Auto Layout, how do I make a UIImageView's size dynamic depending on the image? and this gist: https://gist.github.com/marcc-orange/e309d86275e301466d1eecc8e400ad00 and with these constraints make.edges.equalToSuperview() I am able to get the images to display at their correct scales, but they completely cover the labels.
Ideally it would look something like this:
100 % working solution with Sample Code
I just managed to acheive the same layout with dynamic label contents and dynamic image dimensions. I did it through constraints and Autolayout. Take a look at the demo project at this GitHub Repository
As matt pointed out, we have to calculate the height of each cell after image is downloaded (when we know its width and height). Note that the height of each cell is calculated by tableView's delegate method heightForRowAt IndexPath
So after each image is downloaded, save the image in array at this indexPath and reload that indexPath so height is calculated again, based on image dimensions.
Some key points to note are as follows
Use 3 types of cells. One for label, one for subtitle and one for Image. Inside cellForRowAt initialize and return the appropriate
cell. Each cell has a unique cellIdentifier but class is same
number of sections in tableView == count of data source
number of rows in section == 3
First row corresponds to title, second row corresponds to subtitle and the 3rd corresponds to the image.
number of lines for labels should be 0 so that height should be calculated based on content
Inside cellForRowAt download the image asynchrounously, store it in array and reload that row.
By reloading the row, heightForRowAt gets called, calculates the required cell height based on image dimensions and returns the height.
So each cell's height is calculated dynamically based on image dimensions
Take a look at Some code
override func numberOfSections(in tableView: UITableView) -> Int {
return arrayListItems.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//Title, SubTitle, and Image
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
//configure and return Title Cell. See code in Github Repo
case 1:
//configure and return SubTitle Cell. See code in Github Repo
case 2:
let cellImage = tableView.dequeueReusableCell(withIdentifier: cellIdentifierImage) as! TableViewCell
let item = arrayListItems[indexPath.section]
//if we already have the image, just show
if let image = arrayListItems[indexPath.section].image {
cellImage.imageViewPicture.image = image
}else {
if let url = URL.init(string: item.imageUrlStr) {
cellImage.imageViewPicture.kf.setImage(with: url) { [weak self] result in
guard let strongSelf = self else { return } //arc
switch result {
case .success(let value):
print("=====Image Size \(value.image.size)" )
//store image in array so that `heightForRowAt` can use image width and height to calculate cell height
strongSelf.arrayListItems[indexPath.section].image = value.image
DispatchQueue.main.async {
//reload this row so that `heightForRowAt` runs again and calculates height of cell based on image height
self?.tableView.reloadRows(at: [indexPath], with: .automatic)
}
case .failure(let error):
print(error) // The error happens
}
}
}
}
return cellImage
default:
print("this should not be called")
}
//this should not be executed
return .init()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//calculate the height of label cells automatically in each section
if indexPath.row == 0 || indexPath.row == 1 { return UITableView.automaticDimension }
// calculating the height of image for indexPath
else if indexPath.row == 2, let image = arrayListItems[indexPath.section].image {
print("heightForRowAt indexPath : \(indexPath)")
//image
let imageWidth = image.size.width
let imageHeight = image.size.height
guard imageWidth > 0 && imageHeight > 0 else { return UITableView.automaticDimension }
//images always be the full width of the screen
let requiredWidth = tableView.frame.width
let widthRatio = requiredWidth / imageWidth
let requiredHeight = imageHeight * widthRatio
print("returned height \(requiredHeight) at indexPath: \(indexPath)")
return requiredHeight
}
else { return UITableView.automaticDimension }
}
Related.
Another approach that we can follow is return the image dimensions from the API request. If that can be done, it will simplify things a lot. Take a look at this similar question (for collectionView).
Self sizing Collection view cells with async image downloading.
Placholder.com Used for fetching images asynchronously
Self Sizing Cells: (A Good read)
Sample
It’s relatively easy to do what you’re describing: your image view needs a width constraint that is equal to the width of the “screen” (as you put it) and a height constraint that is proportional to the width constraint (multiplier) based on the proportions of the downloaded image (aka “aspect ratio”). This value cannot be set in advance; you need to configure it once you have the downloaded image, as you do not know its proportions until then. So you need an outlet to the height constraint so that you can remove it and replace it with one that has the correct multiplier when you know it. If your other constraints are correct in relation to the top and bottom of the image view, everything else will follow as desired.
These screen shots show that this approach works:
(Scrolling further down the table view:)
It isn’t 100% identical to your desired interface, but the idea is the same. In each cell we have two labels and an image, and the images can have different aspect ratios but those aspect ratios are correctly displayed - and the cells themselves have different heights depending upon that.
This is the key code I used:
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell
// in real life you’d set the labels here too
// in real life you’d be fetching the image from the network...
// ...and probably supplying it asynchronously later
let im = UIImage(named:self.pix[indexPath.row])!
cell.iv.image = im
let con = cell.heightConstraint!
con.isActive = false
let ratio = im.size.width/im.size.height
let newcon = NSLayoutConstraint(item: con.firstItem, attribute: con.firstAttribute, relatedBy: con.relation, toItem: con.secondItem, attribute: con.secondAttribute, multiplier: ratio, constant: 0)
newcon.isActive = true
cell.heightConstraint = newcon
return cell
There's a straight forward solution for your problem if you don't want to change your layout.
1- define your cell
2- put the UIImageView and other UI elements you like inside your cell and add these constraints for the image view:
-top,leading,trailing,bottom to superview
-height constraints and add outlet to your code (for example :heightConstraint)
3-Change the content fill to : aspect fit
4- Load your images via kingfisher or any other way you like, once you pass your image, check the size and calculate the ratio : imageAspectRatio = height/width
5-Set the heightConstraint.constant = screenWidth * imageAspectRatio
6-call layoutIfNeeded() for the cell and you should be ok!
*This solution works with any UI layout composition including stack views, the point is having a constraint on the images and letting the tableview figure it out how to calculate and draw constraints.
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var heightConstraint: NSLayoutConstraint!
#IBOutlet weak var sampleImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func configure(image:UIImage) {
let hRatio = image.size.height / image.size.width
let newImageHeight = hRatio * UIScreen.main.bounds.width
heightConstraint.constant = newImageHeight
sampleImageView.image = image
sampleImageView.layoutIfNeeded()
}
}
Result :
I am working on a popup view for an app I am making. If you take a second to look at the image attached below, you will see that the top edges are rounded, but the bottom edges are not. This is because I only rounded the edges of the view (it is lowest in the hierarchy). I cannot round the edges of the images (the colorful boxes) because they are tables in a scrolling view. The only solution I can think of is a very ugly one where I mask the bottom edges with a UIImageView that appears once the popup has faded in. Does anyone have a better solution? If so, I would greatly appreciate your help. Also, my scrolling view is not yet functional, so that is not referenced here and the solution (if functional) should work regardless.
My code:
allSeenPopover.layer.cornerRadius = 5
userProfile.layer.cornerRadius = 15
colorBackground.layer.cornerRadius = 15
colorBackground.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
#IBAction func loadUserProfile(_ sender: Any) {
if darken.alpha == 0 {
darken.alpha = 1
self.view.addSubview(userProfile)
userProfile.center = self.view.center
userProfile.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
userProfile.alpha = 0
UIView.animate(withDuration: 0.3) {
self.largeDropShadow.alpha = 0.3
self.userProfile.alpha = 1
self.userProfile.transform = CGAffineTransform.identity
}
}
else {
UIView.animate(withDuration: 0.2, animations: {
self.userProfile.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
self.userProfile.alpha = 0
self.darken.alpha = 0
self.largeDropShadow.alpha = 0
}) { (success:Bool) in
self.userProfile.removeFromSuperview()
}
}
}
The image I was referring to:
Since the view you want rounded is inside a table view cell, you must take care that the view is created added only once per reused cell.
Each time a reused cell scrolls into view, check to see if it has had an imageView subview (using a tag that is unique within the cell is a quick way to make that check). If you don't have one, create it and then configure it for the particular row, otherwise just configure it for the particular row...
(warning, I'm not swift fluent, but the idea should be clear)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as UITableViewCell!
let imageView:UIImageView = cell.viewWithTag(99) as? UIImageView
if (!imageView) {
// this code runs just once per reused cell, so setup
// imageView properties here that are row-independent
imageView = UIImageView()
imageView.tag = 99 // so we'll find this when the cell gets reused
imageView.layer.cornerRadius = 15.0
imageView.clipsToBounds = true
// any other props that are the same for all rows
imageView.frame = // your framing code here
cell.addSubview(imageView)
}
// this code runs each time a row scrolls into view
// so setup properties here that are row-dependent
imageView.image = // some function of indexPath.row
return cell
}
Thanks in advance for the help.
I have a UITableView within a main view contoller. Within the prototype cell, I have a UIImageview. In the code below everything works until I add the 5 lines to apply a circular mask and border. Once I do that, the images will not load unless I scroll the cells. The mask and border do get applied perfectly however. Will be great when it works... but until then.
Certainly this has been seen before. I'm a swift/objective-C newbie.
Working in swift for this one.
Code below;
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("mixerCell", forIndexPath: indexPath) as! MixerTableViewCell
// set label background color to clear
cell.textLabel?.backgroundColor = UIColor.clearColor()
// set highlight selection to none
cell.selectionStyle = .None
// set image for cell
let imageView = cell.viewWithTag(1) as! UIImageView
// put circular mask and border. This is the problem code that causes initial load of the tableview images to show up blank.
imageView.layer.cornerRadius = imageView.frame.size.width / 2;
imageView.clipsToBounds = true;
let color1 = UIColor(white: 1.0, alpha: 0.5).CGColor as CGColorRef
imageView.layer.borderWidth = 2;
imageView.layer.borderColor = color1
// assign image
imageView.image = UIImage(named: mixerSounds[indexPath.row])
return cell
}
initial view load
after scroll
your code is perfectly working for me. Here i am using Xcode-7. i think you are using Xcode-6.3 or less version. just upgrade it to Xcode- 7. and if you are using the same then just check your heightforRowAtIndexpath or other delegates there should be some issue.
thanks
Try changing the below lines,
// replace this
let imageView = cell.viewWithTag(1) as! UIImageView
// to
let imageView = cell.yourImageViewName
/* yourImageViewName is the outlet
reference name you have given in the
MixerTableViewCell custom class.
*/
Edit 2: Just for debugging purposes,
hardcode the image name and check if the image appears on the all the cells.
imageView.image = UIImage(named: "first1.png")
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
let cellIdentifier = "cell"
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as UITableViewCell
cell.image_View.image = UIImage(named: mixerSounds[indexPath.row])
println("The loaded image: \(image)")
cell.image_View.layer.masksToBounds = false
cell.image_View.layer.borderColor = UIColor.blackColor().CGColor
cell.image_View.layer.cornerRadius = image.frame.height/2
cell.image_View.clipsToBounds = true
return cell
}
Give imageview outlet to cell and not give imageview name because by default name is imageview so take diffrent name
It looks like the problem is using clipToBounds = true I am facing the same issue while making circular UIImageView inside UITableViewCell
I didn't find the exact solution but for now I found a way to do this
if (indexPath.row == indexPath.length && !isTableReloaded)
{
let dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.000000001 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
self.reloadTableView()
})
}
func reloadTableView()
{
isTableReloaded = true
self.tableViewContacts.reloadData()
}
Here isTableReloaded is a Bool type var which is initialized to false in viewDidLoad()
and the if condition is to be placed at the last of cellForRowAtIndexPath but before return statement
This will resolve our problem but do not rely on this as this is not the best approach.
Please post solution for this if any one found the better approach.
Here is a perfect and state away solution for circular image in UITableview Cell.
Simply modify your UITableviewCell (custom cell) class with below code.
override func awakeFromNib() {
super.awakeFromNib()
imgEvent.layer.frame = (imgEvent.layer.frame).insetBy(dx: 0, dy: 0)
imgEvent.layer.borderColor = UIColor.gray.cgColor
imgEvent.layer.cornerRadius = (imgEvent.frame.height)/2
imgEvent.layer.masksToBounds = false
imgEvent.clipsToBounds = true
imgEvent.layer.borderWidth = 0.5
imgEvent.contentMode = UIViewContentMode.scaleAspectFill
}
It will also helps to solve the problem of image circular only after scrolling table..(if any!)
let width = cell.frame.size.width
cell.img.layer.cornerRadius = width * 0.72 / 2
0.72 is the ratio of the cell width to image width, for eg. cellWidth = 125 and imageWidth = 90, so 125/90 would give 0.72. Do similar calculation for your image.
First: Images doesn't load until you scroll, because when cellForRowAtIndexPath methods called the constraints doesn't set for image until now, so when scrolling the constraints was added and the image appears, so if you set proportional width and height for imageView (width==height) in cell then
do that
let w = tableview.frame.width*(proportional value like 0.2)
imageView.layer.cornerRadius = w / 2
imageView.clipsToBounds = true;