Set UIView width based off of image in UIImageView in UITableViewCell - swift

I have a subclass of a UITableViewCell, in the cell I have a UIImageView with a content mode set to ScaleAspectFit. The UIImageView has a static height and uses equal leading & trailing constraints, it also has a top constraint.
Directly below the UIImageView, I have a UIView that I'd like the width to be equal to the width of the scaled image. Ideally I'd like to set a minimum width as well.
I seem to be having trouble getting the size of the image in the image view.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCellWithIdentifier("sampleCell") as? SampleCellTableViewCell else {
return UITableViewCell()
}
return cell
}
}
// the cell
class SampleCellTableViewCell: UITableViewCell {
#IBOutlet weak var theImage: UIImageView!
#IBOutlet weak var theView: UIView!
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 tried many things to this point so would like a fresh idea if you have one, thank you.

The solution ended up being to add a width constraint to the view then creating an outlet for it and changing it's constant value to the width of the scaled image within the image view.
// cell
class SampleCellTableViewCell: UITableViewCell {
#IBOutlet weak var theImage: UIImageView!
#IBOutlet weak var theView: UIView!
#IBOutlet weak var theViewWidthConstraint: NSLayoutConstraint!
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
}
}
// cellForRowAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCellWithIdentifier("sampleCell") as? SampleCellTableViewCell else {
return UITableViewCell()
}
cell.theViewWidthConstraint.constant = cell.theImage.frameForImageInImageViewAspectFit().width
return cell
}
You can find the frameForImageInImageViewAspectFit() method definition here: https://stackoverflow.com/a/36428745/4096655

Related

How to UITableView Click image and title

I've created a tableView, but when I click it, I don't get any results. I wanted to add a new feature to improve my project, but I couldn't add the videos I watched and the things I researched.
Table View
import UIKit
class ViewController1: UIViewController {
#IBOutlet weak var FoodView: UITableView!
let dogfoods = ["pork", "banana", "chicken-leg"]
override func viewDidLoad() {
super.viewDidLoad()
FoodView.delegate = self
FoodView.dataSource = self
// not tapped no see
FoodView.allowsSelection = false
}
}
extension ViewController1: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dogfoods.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = FoodView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
let dogfood = dogfoods[indexPath.row]
cell.foodImageView.image = UIImage(named: dogfood)
cell.nameLabel.text = dogfood
return cell
}
}
CustomCell
class CustomCell: UITableViewCell {
#IBOutlet weak var dogView: UIView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var foodImageView: UIImageView!
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
}
}
When I click on one of the cells in the picture, I want to write a larger version of the picture and a description, how can I do this? When I searched on the internet, I applied similar ones, but I couldn't get any results.
You have a few choices. You can add one or more buttons to your custom cell. You can attach a tap gesture recognizer to your cell's content view.
Probably the easiest way to respond to a tap on the whole cell is to have view controller conform to the UITableViewDelegate protocol and implement the tableView(_:didSelectRowAt:) method.
That method will be called when the user selects a cell, and you would use the indexPath of the tapped cell to figure out which one was tapped and do whatever is appropriate.
You can do that with easy and efficient way using Delegate in Swift
//create protocol as we used interface in Java
#objc protocol TableViewCellDelegate {
#objc func click(indexPath: IndexPath?)
}
// Modify your class CustomCell as:
#IBOutlet weak var dogView: UIView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var foodImageView: UIImageView!
var delegate: TableViewCellDelegate?
var indexPath: IndexPath?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
foodImageView.isUserInteractionEnabled = true
foodImageView.addGestureRecognizer(tapGestureRecognizer)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer) {
let tappedImage = tapGestureRecognizer.view as! UIImageView
self.delegate.click?(indexPath: self.indexPath)
}
// Modify your tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) in ViewController1 as
let cell = FoodView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
cell.delegate = self
cell.indexPath = indexPath
let dogfood = dogfoods[indexPath.row]
cell.foodImageView.image = UIImage(named: dogfood)
cell.nameLabel.text = dogfood
return cell
// And now add extension add the end of ViewController1
extension ViewController1: TableViewCellDelegate {
func click(indexPath: IndexPath?) {
// open image for preview here
}
}
You can do it in many ways
use a add a UITableViewDelegate method which is
override func tableView(_ tableView: UITableView, didSelectRowAt
indexPath: IndexPath){
//your code...
}
it will called every time when cell clicked.
if you prefer to trigger any button click rather then cell click then go for delegate (Izaan Saleem already explained), or you can use NotificationCenter, but for this task I prefer didSelect or delegate solution.

Dynamcially fit height of tableview according to its cells content into the scrollview

I want to Fit A UIVIew and a Tableview in a ScrollView But The table view Height is not Dynamically increasing according to the avaualable cells.
What I have done is.
Gave TableView Height constant and priority to 999
Made an outlet of the table view height content and added this code
self.tableViewHeightConstraint.constant = self.myNewTableView.contentSize.height
self.view.layoutIfNeeded()
Made tablview scrollable to false
But the TableView Height is not increasing according to cells
Here is the Example code of My Code.
TableviewCell:-
import UIKit
class NewTableViewCell: UITableViewCell {
#IBOutlet weak var testLabel: UILabel!
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
}
}
ViewController:-
import UIKit
class NewViewViewController: UIViewController {
#IBOutlet weak var myNewTableView: UITableView!
#IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
myNewTableView.rowHeight = 60
myNewTableView.estimatedRowHeight = UITableView.automaticDimension
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
}
extension NewViewViewController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NewTableViewCell", for: indexPath) as! NewTableViewCell
cell.testLabel.text = "Testing the height of tableview"
self.tableViewHeightConstraint.constant = self.myNewTableView.contentSize.height
self.view.layoutIfNeeded()
return cell
}
}
Your self.tableViewHeightConstraint is not connected to the storyboard tableView. I think you mistakenly deleted it in storyBoard. After connecting this constraint, it's working fine. Please check the following attachments.
After this change Output:-
You need to add it here
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.tableViewHeightConstraint.constant = self.myNewTableView.contentSize.height
self.view.layoutIfNeeded()
}
I think the below code will help you.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
self.YOUR_TABLEVIEW.layoutIfNeeded()
self.YOUR_TABLEVIEW_HEIGHTCONSTRAINT.constant = self.YOUR_TABLEVIEW.contentSize.height
}

uitableview scroll event stepper exchange

I have a tableview and stepper.
stepper is touched, random stepper values is changing when tableview is moved.how do i prevent it. Thanks
Code
UIViewController
import UIKit
class ViewController:UIViewController,UITableViewDelegate,UITableViewDataSource{
#IBOutlet weak var tablee: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "test", for: indexPath) as! TesttViewCell
return cell
}
}
TesttViewCell
import UIKit
class TesttViewCell: UITableViewCell {
#IBOutlet weak var adet: UIStepper!
#IBOutlet weak var lblTest: UILabel!
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
}
#IBAction func changee(_ sender: UIStepper) {
lblTest.text = String(sender.value)
}
}

Putting Tableview inside UITableViewCell Swift

I'm having trouble with putting a tableview inside a uitableview cell. Right now, it doesn't even display the nested tableview. I set the tableview's delegates and datasource to the custom cell, and have all the required methods. I am also using a storyboard for my tableviews, and have connected all outlets properly.
The problem is that it does not go into the cellForRow function. It does, however, go into the numberOfRowsInSection function, and also the heightForRow function. Below is the code for the custom cell that holds the nested UITableviewcell.
import UIKit
class EventSurveyCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var cellBox: UIView!
#IBOutlet weak var announcementLabel: UILabel!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var authorLabel: UILabel!
#IBOutlet weak var numVotesLabel: UILabel!
#IBOutlet weak var tableView: UITableView!
var surveyArray: [SurveyClass] = []
override func awakeFromNib() {
super.awakeFromNib()
tableView.delegate = self
tableView.dataSource = self
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
tableView.delegate = self
tableView.dataSource = self
// Configure the view for the selected state
}
func do_table_refresh()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("cellforrow")
let cell: SurveyItemCell = self.tableView.dequeueReusableCellWithIdentifier("surveyItemCell") as! SurveyItemCell!
cell.itemLabel.text = surveyArray[indexPath.row].itemName
//go through firebase to check which one user voted on
cell.voteButton.imageView!.image = UIImage(named: "circle")
let percent = surveyArray[indexPath.row].numOfVotes/surveyArray[indexPath.row].totalNumOfVotes
cell.precentLabel.text = String(percent)
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
print("heightforrow")
return 44
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("numrowsinsection")
return 3
//should be return self.surveyArray.count.
}
}
Below is a snippet of code for in the the viewcontroller that is holding the custom cells (containing nested tableviews). This code is part of the cellforrowatindexpath
case PostType.survey:
let cell: EventSurveyCell = self.tableView.dequeueReusableCellWithIdentifier("EventSurveyCell") as! EventSurveyCell!
//cut out other code as it is irrelevant
cell.surveyArray = eventPost.surveyClassArray
cell.do_table_refresh()
print(cell.tableView.rowHeight)
return cell
Another problem I have noticed is that when printing cell.tableview.rowheight, it prints -1. This could be the reason why it does not enter cellforrowatindexpath, but I clearly return 44 in the heightforrow function. Right now, it doesnt even display the nested tableview.
1) Don't need do_table_refresh, you can call cell.tableView.reloadData() directly.
2) Override the systemLayoutSizeFitting:withHorizontalFittingPriority:verticalFittingPriority function:
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
tableView.reloadData()
// if the table view is the last UI element, you might need to adjust the height
let size = CGSize(width: targetSize.width,
height: tableView.frame.origin.y + tableView.contentSize.height)
return size
}
3) In your view controller, after you set the surveyArray, remove this line cell.do_table_refresh(), replace with cell.setNeedsLayout() to auto adjust the layout (you might also need to call a method to update the other UIs such as announcementLabel etc. call it before setNeedsLayout too.)
I had the same issue, cellForRow was not being called for the TableView Inside Custom Cell. And the reason was that the tableview had no height set for it to show the content inside it. After I set some height for the child TableView, cellForRow started to begin calling.

UITableView Prototype cell not found

every one.
After lots of search and different test my code doesn't work yet...
I try to do a simple UITableView with a simple Prototype cell whit using "dequeueReusableCellWithIdentifier" but this function doesn't found my Prototype Cell.
My code :
import Foundation
import UIKit
class DanceClubViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableViewSound: UITableView!
override func viewDidLoad()
{
super.viewDidLoad()
self.tableViewSound.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cellVote")
self.tableViewSound.dataSource = self
self.tableViewSound.delegate = self
self.tableViewSound.reloadData()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
}
#IBAction func backToViewPlay(sender: AnyObject) {
self.navigationController?.popToRootViewControllerAnimated(true)
}
func tableView(tableView:UITableView, numberOfRowsInSection section:Int)->Int
{
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell : UITableViewCell = self.tableViewSound.dequeueReusableCellWithIdentifier("cellVote") as UITableViewCell
return cell
}
If anyone had already had this problem?
The identifier for my Prototype Cell is : cellVote
The key to address your label is to create a custom TableViewCell class in another file:
import UIKit
class DanceCell: UITableViewCell {
#IBOutlet weak var num: UILabel! //connect the label
}
Then for your ViewController:
import Foundation
import UIKit
class DanceClubViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableViewSound: UITableView!
override func viewDidLoad()
{
super.viewDidLoad()
self.tableViewSound.dataSource = self
self.tableViewSound.delegate = self
self.tableViewSound.reloadData()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
}
#IBAction func backToViewPlay(sender: AnyObject) {
self.navigationController?.popToRootViewControllerAnimated(true)
}
func tableView(tableViewSound:UITableView, numberOfRowsInSection section:Int)->Int
{
return 10
}
func tableView(tableViewSound: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableViewSound.dequeueReusableCellWithIdentifier("cellVote", forIndexPath: indexPath) as DanceCell
cell.num.text = "Hello"
return cell
}
}
I removed some stuff, and added he key line in the 'cellForRowAtIndexPath' function to register the cell. I then was able to communicate with the label. Make sure the prototype cell has set 'cellVote' as the identifier in at attributes inspector.