I have this issue wherein I need to fix the size on an image inside a tableviewcell. The image below shows that the image size in not uniform.
Here are the codes I used.
if noteImageIsAvailable == true {
if let imageData = assignedNotePhoto?.photoData {
if let image = Utilities.resizePictureImage(UIImage(data: imageData as Data)) {
//added fix
cell.imageView?.frame.size = CGSize(width: 36, height: 24)
cell.imageView?.clipsToBounds = true
//-----
cell.imageView?.contentMode = .scaleAspectFill
cell.imageView?.image = image
}
}
}
I read an answer here in stackoverflow. It says I need to add clipToBounds but unfortunately it doesn't work. Please help me solve this issue. Thank you
TableView Code
extension SettingNoteViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Menu.SettingNote.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "reuseIdentifier")
let keyPass = KeyHelper.NoteSetting.info[indexPath.row]
let assignedNotePhoto = self.getNotePhoto(key: keyPass.key)
let assignedNoteTextData = self.getNoteTextData(key: keyPass.key)?.value
cell.contentView.backgroundColor = .black
cell.textLabel?.textColor = .white
cell.detailTextLabel?.textColor = .white
cell.detailTextLabel?.numberOfLines = 0
let noteImageIsAvailable = assignedNotePhoto?.photoData != nil
if noteImageIsAvailable == true {
if let imageData = assignedNotePhoto?.photoData {
if let image = Utilities.resizePictureImage(UIImage(data: imageData as Data)) {
//added fix
cell.imageView?.translatesAutoresizingMaskIntoConstraints = false
cell.imageView?.frame.size = CGSize(width: 36, height: 24)
cell.imageView?.clipsToBounds = true
//-----
cell.imageView?.contentMode = UIView.ContentMode.scaleAspectFit
cell.imageView?.image = image
}
}
}
cell.textLabel?.text = Menu.SettingNote.items[indexPath.row].value
cell.detailTextLabel?.text = assignedNoteTextData ?? "noteSettingSubTitle".localized
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is InputMemoViewController {
let vc = segue.destination as! InputMemoViewController
vc.infoNoteKey = self.infoNoteKeyToPass
vc.infoLabelText = self.infoLabelToPass
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.infoNoteKeyToPass = KeyHelper.NoteSetting.info[indexPath.row].key
self.infoLabelToPass = KeyHelper.NoteSetting.info[indexPath.row].label
self.performSegue(withIdentifier: "showInputMemo", sender: self)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
The image below was the output when I applied #Kishan Bhatiya solution.
The first and second image is a landscape photo and the third image is in portrait
When you add cell.imageView?.translatesAutoresizingMaskIntoConstraints = false then frame has no effect, so try to use any one
let marginguide = contentView.layoutMarginsGuide
//imageView auto layout constraints
cell.imageView?.translatesAutoresizingMaskIntoConstraints = false
let marginguide = cell.contentView.layoutMarginsGuide
cell.imageView?.topAnchor.constraint(equalTo: marginguide.topAnchor).isActive = true
cell.imageView?.leadingAnchor.constraint(equalTo: marginguide.leadingAnchor).isActive = true
cell.imageView?.heightAnchor.constraint(equalToConstant: 40).isActive = true
cell.imageView?.widthAnchor.constraint(equalToConstant: 40).isActive = true
cell.imageView?.contentMode = .scaleAspectFill
cell.imageView?.layer.cornerRadius = 20 //half of your width or height
And it's better to set constraints in UITableViewCell
you know your imageview size. So you can resize your UIImage to imageView size.
extension UIImage{
func resizeImageWithHeight(newW: CGFloat, newH: CGFloat) -> UIImage? {
UIGraphicsBeginImageContext(CGSize(width: newW, height: newH))
self.draw(in: CGRect(x: 0, y: 0, width: newW, height: newH))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
use like that
let img = originalImage.resizeImageWithHeight(newW: 40, newH: 40)
cell.imageView?.image = img
Here, 40 40 is my imageview size
I have the same problem, scaleAspectFit is solved for me. you can try it
cell.imageView.contentMode = UIViewContentMode.scaleAspectFit
Related
I first programmatically created a tableview :
private func setupTableView() {
tableView = UITableView(frame: CGRect(x: 0, y: 180, width: view.frame.width, height: view.frame.height), style: UITableView.Style.plain)
tableView.dataSource = self
tableView.delegate = self
tableView.register(ItemTableViewCell.self, forCellReuseIdentifier: "Cell")
view.addSubview(tableView)
}
and set the cellForRow method as below :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ItemTableViewCell
guard let finalItems = presenter.finalItems?[indexPath.row] else { return cell }
presenter.configure(cell: cell, FinalItem: finalItems)
return cell
}
Then I configure the ItemTableViewCell as below :
class ItemTableViewCell: UITableViewCell {
private var iconImageView : UIImageView = {
let imgView = UIImageView(image: #imageLiteral(resourceName: "Image"))
imgView.contentMode = .scaleAspectFit
imgView.clipsToBounds = true
return imgView
}()
private var titleLabel : UILabel = {
let lbl = UILabel()
lbl.textColor = .black
lbl.font = UIFont.boldSystemFont(ofSize: 12)
lbl.textAlignment = .left
return lbl
}()
func configure(finalItem: FinalItem) {
titleLabel.text = finalItem.title
iconImageView.downloaded(from: finalItem.images_url.small)
}
}
When I push to the DetailViewController with the uinavigationbar, the elements contained in the rows (titles, labels...) are still visible a few milli seconds:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let finalItem = finalItems[indexPath.row]
let detailViewController = ModuleBuilder.createDetailModuleWith(finalItem)
detailViewController.finalItem = finalItem
navigationController?.pushViewController(detailViewController, animated: true)
}
This is not what I am expecting. I never figure this problem out before.
I am creating a wall page like twitter or Facebook in which user can post on the wall it can include image and just text. So based on the content the cell's heights must change, if the post is of one line the row height must be appropriate.
I tried using UITableViewAutomaticDimensions, but its not working with my code please do help me.
import UIKit
class wallPageViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var tableOfApps : UITableView?
var appNames: [String]? = []
var apps: [wallPageModel]?
var dynamic_height : CGFloat = 150.0
var addPost : UITextField?
var readMore : UITextView?
func loadTableOfApps(){
//appNames = ["jkbajdba", "abfajfb", "akjbfkjag", "ahbfkajf" ]
let provider = wallPageProvider()
apps = provider.getApps()
let tableHeight = view.frame.size.height
tableOfApps = UITableView(frame: CGRect(x: 10, y: 60, width: 300, height: tableHeight))
tableOfApps!.delegate = self
tableOfApps!.dataSource = self
tableOfApps?.separatorStyle = UITableViewCellSeparatorStyle.none
//self.tableOfApps?.rowHeight = UITableViewAutomaticDimension
//self.tableOfApps?.estimatedRowHeight = UITableViewAutomaticDimension
print("load table of apps")
view.addSubview(tableOfApps!)
}
override func viewDidLoad() {
super.viewDidLoad()
loadTableOfApps()
loadAddPost()
tableOfApps?.estimatedRowHeight = 150.0
tableOfApps?.rowHeight = UITableViewAutomaticDimension
view.backgroundColor = UIColor(red: 232/255, green: 234/255, blue: 246/255, alpha: 1.0)
// Do any additional setup after loading the view.
}
func loadAddPost(){
addPost = UITextField(frame: CGRect(x: 10, y: 20, width: 300, height: 30))
addPost?.placeholder = "Stay safe, post a tip!"
addPost?.isUserInteractionEnabled = true
addPost?.borderStyle = UITextBorderStyle.roundedRect
addPost?.autocapitalizationType = .none
view.addSubview(addPost!)
addPost?.addTarget(self, action: #selector(writeComment), for: UIControlEvents.touchDown)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("app coun\(apps!.count)")
return apps!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell : wallModelTableViewCell?
cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? wallModelTableViewCell
if cell == nil {
cell = wallModelTableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
}
let app = apps![indexPath.row]//reading the array of data hence provider
//association of provider and view
//this is the processs from where view can read the data from provide
cell!.iconImageLabel!.image = app.icon
cell!.titleLabel!.text = app.title
cell?.backgroundColor = UIColor.white
cell!.commentsLabel?.image = app.comments_Label
cell?.commentsLabel?.center = CGPoint(x: tableView.frame.size.width/2, y: dynamic_height-20)
cell?.likeButtonLabel?.image = app.likeButton
cell?.likeButtonLabel?.center = CGPoint(x: (tableView.frame.size.width/2)-130, y: dynamic_height-20)
/*cell?.likeButtonLabel?.leftAnchor.constraint(equalTo: tableView.leftAnchor, constant: 50)*/
cell!.feedTextLabel!.text = app.feedText
cell?.feedTextLabel?.sizeToFit()//so that it can expand the data more than two lines
cell?.feedTextLabel?.backgroundColor = UIColor.clear
//Limiting UIlabel to 125 characters
if (cell?.feedTextLabel?.text.count)! > 125{
/*
let index = cell?.feedTextLabel?.text.index((cell?.feedTextLabel?.text.startIndex)!, offsetBy: 125)
cell?.feedTextLabel?.text = cell?.feedTextLabel?.text.substring(to: index!)
cell?.feedTextLabel?.text = cell?.feedTextLabel?.text.appending("...")*/
//cell?.feedTextLabel?.attributedText = NSAttributedString(string: "...readmore")
}
cell?.layer.cornerRadius = 6.0
cell?.isUserInteractionEnabled = false
cell?.titleLabel?.isUserInteractionEnabled = true
tableOfApps?.backgroundColor = UIColor.clear
tableOfApps?.backgroundView?.isOpaque = false
tableOfApps!.estimatedRowHeight = 150.0
tableOfApps!.rowHeight = UITableViewAutomaticDimension
print("table view cell for row")
/*let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector( self.labelAction(gesture:)))
cell?.feedTextLabel?.addGestureRecognizer(tap)
cell?.feedTextLabel?.isUserInteractionEnabled = true
tap.delegate = self as! UIGestureRecognizerDelegate*/
return cell!
}
/*#objc func labelAction(gesture: UITapGestureRecognizer){
}*/
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
print("height for row")
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 150.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
#objc func writeComment(){
let addComment = addCommentViewController()
navigationController?.pushViewController(addComment, animated: true)
}
/*
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
I want each row must have dynamic height as the content is provided by the user if the content contains 150 characters the height of the cell must be 200+ if content contains less than 125 characters the height must be as adequate to read.
booktable.frame = CGRect(x: 0, y: booktopview.bounds.height, width: screenWidth, height: screenHeight-booktopview.bounds.height-tabbarView.bounds.height)
booktable.register(UITableViewCell.self, forCellReuseIdentifier: "mycell")
booktable.dataSource = self
booktable.delegate = self
booktable.separatorColor = UIColor.lightGray
booktable.backgroundColor = UIColor.clear
booktable.separatorStyle = .singleLine
bookview.addSubview(booktable)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(tableView == booktable)
{
let cell1 = booktable.dequeueReusableCell(withIdentifier: "mycell")
for object in (cell1?.contentView.subviews)!
{
object.removeFromSuperview();
}
let img :UIImageView = UIImageView()
let lbl : UILabel = UILabel()
img.frame = CGRect(x: 15, y: 15, width: 80, height: 130)
img.image = imgarray[indexPath.row]
img.layer.borderWidth = 1.0
img.layer.borderColor = UIColor.lightGray.cgColor
cell1?.contentView.addSubview(img)
imgheight = img.bounds.height
lbl.frame = CGRect(x: img.bounds.width + 40, y: (imgheight+40-80)/2, width: booktable.bounds.width-img.bounds.width + 40 - 100, height: 80)
lbl.text = imgname[indexPath.row]
lbl.numberOfLines = 0
lbl.textAlignment = .left
lbl.font = UIFont(name: "Arial", size: 23)
lbl.textColor = UIColor.black
cell1?.selectionStyle = .none
cell1?.contentView.addSubview(lbl)
return cell1!
}
The code shown above is for book table, which sometimes scrolls like normal and sometimes not scrolling at all. I am doing all the code programatically. I have tested this on both simulators and devices but still the problem exists. Any help is appreciated...
Create Custom UITableViewCell, let's say it is ListTableCell
class ListTableCell: UITableViewCell {
#IBOutlet weak var lblTemp: UILabel!
#IBOutlet weak var imgTemp: UIImage!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
I've created UITableViewCell with xib like this and bind IBOutlets
Let's say we have struct Model and array like this
struct Model {
let image : UIImage
let name: String
}
for i in 0...10 {
let model = Model(image: #imageLiteral(resourceName: "Cat03"), name: "Temp \(i)")
array.append(model)
}
Now on ViewController viewDidLoad() method,
tableView.register(UINib(nibName: "ListTableCell", bundle: nil), forCellReuseIdentifier: "ListTableCell")
Implement UITableViewDataSource methods like this,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ListTableCell") as! ListTableCell
let model = array[indexPath.row]
cell.lblTemp.text = model.name
cell.imgTemp.image = model.image
return cell
}
FYI
For different tableviews, you can create different custom cell the same way and cellForRowAt indexPath and numberOfRowsInSection method will change appropriately.
Let me know in case of any queries.
UPDATE
Follow this and this to create CustomTableCell programmatically
I'm trying to create circular Images inside of my TableViewCell but something is going wrong. I guess that the cornerRadius is to big because there is not any Image displayed with this Code. If I set the cornerRadius on 30 for example, I can see the Images rounded but not in a clear circle .Why is this not working ?
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "QuestionLine")
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "QuestionLine")
let user = users[indexPath.row]
cell?.textLabel?.text = user.question
cell?.detailTextLabel?.text = user.name
let image = UIImage(named: user.profilePicture)
cell?.imageView?.image = image
cell?.imageView?.layer.cornerRadius = (image?.size.width)! / 2
cell?.imageView?.clipsToBounds = true
return cell!
}
The UITableViewCell's imageView will be sized to the height of the cell, If you want to customize the size of imageView try the below code.
let image = UIImage(named: user.profilePicture)
cell?.imageView?.image = image
let itemSize = CGSize.init(width: 40, height: 40) // your custom size
UIGraphicsBeginImageContextWithOptions(itemSize, false, UIScreen.main.scale);
let imageRect = CGRect.init(origin: CGPoint.zero, size: itemSize)
cell?.imageView?.image!.draw(in: imageRect)
cell?.imageView?.image! = UIGraphicsGetImageFromCurrentImageContext()!;
UIGraphicsEndImageContext()
cell?.imageView?.layer.cornerRadius = (itemSize.width) / 2
cell?.imageView?.clipsToBounds = true
Try this code
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "QuestionLine")
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "QuestionLine")
let user = users[indexPath.row]
cell?.textLabel?.text = user.question
cell?.detailTextLabel?.text = user.name
let image = UIImage(named: user.profilePicture)
cell?.imageView?.image = image
cell?.imageView?.layer.cornerRadius = (cell?.imageView?.frame.size.width)! / 2
cell?.imageView?.layer.masksToBounds = true
cell?.imageView?.layer.borderColor = colour.cgColor
cell?.imageView?.layer.borderWidth = 1
return cell!
}
First make sure your image height and width is equal, then replace last 3 lines of code with these lines-
cell?.imageView?.layer.cornerRadius = (image?.frame.size.width)! / 2
cell?.imageView?.masksToBounds = true
return cell!
I would like to display multiple images on scrollview when user selected images with DKImagePickerController github.
Here is my code but images don't appear. Anyone can tell what's wrong?
Thank you in advance!
var picker = DKImagePickerController()
var imagesArray = [Any]()
#IBAction func pickPhoto(_ sender: Any) {
picker.maxSelectableCount = 10
picker.showsCancelButton = true
picker.allowsLandscape = false
picker.assetType = .allPhotos
self.present(picker, animated: true)
picker.didSelectAssets = { (assets: [DKAsset]) in
self.imagesArray.append(assets)
for i in 0..<self.imagesArray.count {
let imageView = UIImageView()
imageView.image = self.imagesArray[i] as? UIImage
imageView.contentMode = .scaleAspectFit
let xposition = self.view.frame.width * CGFloat(i)
imageView.frame = CGRect(x: xposition, y: 330, width: self.scrollView.frame.width, height: 170)
self.scrollView.contentSize.width = self.scrollView.frame.width * CGFloat(i * 1)
self.scrollView.addSubview(imageView)
}
}
}
Instead of displaying images to scrollView, you can add that images in array and reload the collectionView/TableView..
as I did it here in collectionView
func showImagePicker() {
let pickerController = DKImagePickerController()
self.previewView?.isHidden = false
pickerController.assetType = .allPhotos
pickerController.defaultAssetGroup = .smartAlbumUserLibrary
pickerController.didSelectAssets = { (assets: [DKAsset]) in
if assets.count>0
{
for var i in 0 ... assets.count-1 {
assets[i].fetchOriginalImage(true, completeBlock: { (image, info) in
self.abc.append(image)
})
}
}
self.previewView?.reloadData()
}
self.present(pickerController, animated: true) {}
}
Here abc :[UIImage] and previewView? : UICollectionView
and in collection delegate methods:
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return self.abc.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell: UICollectionViewCell?
var imageView: UIImageView?
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellImage", for: indexPath)
imageView = cell?.contentView.viewWithTag(1) as? UIImageView
if let cell = cell, let imageView = imageView
{
let tag = indexPath.row + 1
cell.tag = tag
imageView.image = self.abc[indexPath.row]
}
return cell!
}