uitableview height does not change dynamically in swift ios? - ios

I'm in trouble.I have a city list, I want to display cities in UITableView and I have disabled UITableView's scroll because i don't want to display scroll.
when I changed to UITableView's height dynamically, it doesn't changed and UITableView does not display all cities. Below the code. Please look it.
import UIKit
class FlightDetailsOneWayViewController: UIViewController {
var flightDetailArr:[FlightDetailsOneWay] = [FlightDetailsOneWay]()
#IBOutlet var tableView: UITableView!
#IBOutlet var scrollview: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
flightDetailArr.append(FlightDetailsOneWay(depCity: "London"))
flightDetailArr.append(FlightDetailsOneWay(depCity: "China"))
flightDetailArr.append(FlightDetailsOneWay(depCity: "Singapore"))
flightDetailArr.append(FlightDetailsOneWay(depCity: "Dubai"))
self.tableView.scrollEnabled = false
var cellHeight = CGFloat(self.tableView.rowHeight)
var totalCity = CGFloat(flightDetailArr.count)
var totalHeight = cellHeight * totalCity
self.tableView.frame.size.height = CGFloat(totalHeight)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return flightDetailArr.count
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
let cell:FlightDetailsCell = tableView.dequeueReusableCellWithIdentifier("FlightDetail") as FlightDetailsCell
let flight = flightDetailArr[indexPath.row]
cell.setCell(flight.depCity)
return cell
}
}
class FlightDetailsOneWay
{
var depCity = ""
init(depCity: String)
{
self.depCity = depCity
}
}
class FlightDetailsCell: UITableViewCell {
#IBOutlet var depCity: 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
}
func setCell(depCity: String)
{
self.depCity.text = depCity
}
}
below the preview of above code.

As explanation required to this answer is very detailed.
Follow my other answer "Moving views with constraints" to get idea about how to update layout constraint.
And as per your comment about how to connect NSLayoutConstraint variable with height constraints? as below:
Go to Storyboard.
Select UIView in which you have added constraint. Click on Constraints icon to see all constraints. Right now in below image I have added only one constraint you may find more than that. Check for which constraint you have change it's properties.
Now click on view controller and Click on Show the connection inspector. here you can see all IBOutlets defined in your view controller. As in below image you can see I have created only one IBOutlet for sake of simplicity which is heightConstraint.
And this is how you can add connection to constraint variable.

You can use prototype cell if all your cell will have the same look:
a complete tutorial to make a project using prototype cell
or
a second which it more quick to read
You can can also use
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 42.0
}
This function is perfect if you resize dynamically the height cell.
You just need to use: beginUpdates() and endUpdates() for make it works.

Related

Dynamically resizing an IOS tableview cells which have a textview embedded in swift

I have tried the following code which gives the correct textview frame height
func textViewDidChange(_ textView: UITextView) {
myToDoList[keyArray[sect]]![row] = textView.text
var frame = textView.frame
frame.size.height = textView.contentSize.height
textView.frame = frame
print(frame)
let indexPath = self.tableView.indexPathForView(textView)
print(inputActive,indexPath)
self.tableView.indexPathForView(inputActive)
self.tableView.rowHeight = frame.size.height
}
The answer from "Krunal" is missing a piece or two...
Start with the cell layout / constraints:
And use this code:
import UIKit
class WithTextViewCell: UITableViewCell, UITextViewDelegate {
#IBOutlet var theTextView: UITextView!
var callBack: ((UITextView) -> ())?
override func awakeFromNib() {
super.awakeFromNib()
// in case these were not set in IB
theTextView.delegate = self
theTextView.isScrollEnabled = false
}
func textViewDidChange(_ textView: UITextView) {
// tell controller the text changed
callBack?(textView)
}
}
class TableWithTextViewTableViewController: UITableViewController {
var cellData = [
"UITableViewController implements the following behaviors:",
"If a nib file is specified via the init(nibName:bundle:) method (which is declared by the superclass UIViewController), UITableViewController loads the table view archived in the nib file. Otherwise, it creates an unconfigured UITableView object with the correct dimensions and autoresize mask. You can access this view through the tableView property.",
"If a nib file containing the table view is loaded, the data source and delegate become those objects defined in the nib file (if any). If no nib file is specified or if the nib file defines no data source or delegate, UITableViewController sets the data source and the delegate of the table view to self.",
"When the table view is about to appear the first time it’s loaded, the table-view controller reloads the table view’s data. It also clears its selection (with or without animation, depending on the request) every time the table view is displayed. The UITableViewController class implements this in the superclass method viewWillAppear(_:). You can disable this behavior by changing the value in the clearsSelectionOnViewWillAppear property.",
"When the table view has appeared, the controller flashes the table view’s scroll indicators. The UITableViewController class implements this in the superclass method viewDidAppear(_:).",
"It implements the superclass method setEditing(_:animated:) so that if a user taps an Edit|Done button in the navigation bar, the controller toggles the edit mode of the table.",
"You create a custom subclass of UITableViewController for each table view that you want to manage. When you initialize the controller in init(style:), you must specify the style of the table view (plain or grouped) that the controller is to manage. Because the initially created table view is without table dimensions (that is, number of sections and number of rows per section) or content, the table view’s data source and delegate—that is, the UITableViewController object itself—must provide the table dimensions, the cell content, and any desired configurations (as usual). You may override loadView() or any other superclass method, but if you do be sure to invoke the superclass implementation of the method, usually as the first method call.",
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 100
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "WithTextViewCell", for: indexPath) as! WithTextViewCell
// Configure the cell...
cell.theTextView.text = cellData[indexPath.row]
cell.callBack = {
textView in
// update data source
self.cellData[indexPath.row] = textView.text
// tell table view we're starting layout updates
tableView.beginUpdates()
// get current content offset
var scOffset = tableView.contentOffset
// get current text view height
let tvHeight = textView.frame.size.height
// telll text view to size itself
textView.sizeToFit()
// get the difference between previous height and new height (if word-wrap or newline change)
let yDiff = textView.frame.size.height - tvHeight
// adjust content offset
scOffset.y += yDiff
// update table content offset so edit caret is not covered by keyboard
tableView.contentOffset = scOffset
// tell table view to apply layout updates
tableView.endUpdates()
}
return cell
}
}
The "key" parts:
Add a "call back" closure to your cell, so we can tell the controller when the text has changed.
When the call back occurs, have the table view controller: update the dataSource with the edited text; tell the text view to resize itself; and adjust the content offset to avoid having the caret (the text insertion point) disappear behind the keyboard.
Set UITextview height according to your content (text) size using sizeToFit and enable translatesAutoresizingMaskIntoConstraints in cellForRowAtIndexPath
Try this and see
class TextViewCell: UITableViewCell {
#IBOutlet weak var textview: UITextView!
func adjustTextViewHeight(textview : UITextView) {
textview.translatesAutoresizingMaskIntoConstraints = true
textview.sizeToFit()
textview.isScrollEnabled = false
}
}
class TableController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Don't forget to set dataSource and delegate for table
table.dataSource = self
table.delegate = self
// Set automatic dimensions for row height
table.rowHeight = UITableViewAutomaticDimension
table.estimatedRowHeight = UITableViewAutomaticDimension
}
// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "textview") as! TextViewCell
cell.adjustTextViewHeight(textview: cell.textview)
return cell
}
}
Here is Storyboard Layout:
And here is result:
Its very easy to implement dynamic cell height when you design cell with interfaceBuilder directly as prototype cell or xib, where you just need to set top an bottom constraints properly and rest of the thing is done by tableViewAutoDimension.
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 50
tableView.rowHeight = UITableViewAutomaticDimension
}

Swift TableViewCell empty when cell has values

I have a custom cell with some simple labels and a UIImage. Everything appears to be set correctly, and stepping through the debugger shows that everything is getting a value and even using the print in the debugger shows that the labels have text. However my table view is still empty when executed. I have been looking at this for too long and cannot figure out the problem.
Here is the cell code
class CurrentFileCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var statusImage: UIImageView!
#IBOutlet weak var dateLabel: UILabel!
var currentContent: AircraftContent! {
didSet{
setStyles(Constants.appStyleSetting)
self.nameLabel.text = currentContent.contentName
self.dateLabel.text = currentContent.contentStatus
self.statusImage.image = UIImage(named: "color_label_circle_green")
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
private func setStyles(settings: StyleSettings) {
let tableFont = UIFont(name: settings.bodyFont, size: CGFloat(settings.tableFontSize))
nameLabel.font = tableFont
dateLabel.font = tableFont
// Text color
let tableFontColor = settings.tableFontColor
nameLabel.textColor = tableFontColor
dateLabel.textColor = tableFontColor
}
Here is the ViewController code with a tableview inside.
class CurrentFilesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var content: AircraftContent?
#IBOutlet weak var currentFiles: UILabel!
#IBOutlet weak var downloadingLabel: UILabel!
#IBOutlet weak var readyLabel: UILabel!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
self.content = loadContent()
setStyles(Constants.appStyleSetting)
//self.tableView.reloadData()
// Do any additional setup after loading the view.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CurrentFileCell", forIndexPath: indexPath) as? CurrentFileCell
cell?.currentContent = content
return cell!
}
func loadContent() -> AircraftContent {
return (NSKeyedUnarchiver.unarchiveObjectWithFile(AircraftContent.ArchiveURL.path!) as? AircraftContent)!
}
private func setStyles(settings: StyleSettings) {
let titleFont = UIFont(name: settings.bodyFont, size: CGFloat(settings.titleFontSize))
let key = UIFont(name: settings.bodyFont, size: CGFloat(settings.tableFontSize))
currentFiles.font = titleFont
downloadingLabel.font = key
readyLabel.font = key
// Text color
let titleFontColor = settings.titleFontColor
currentFiles.textColor = titleFontColor
downloadingLabel.textColor = titleFontColor
readyLabel.textColor = titleFontColor
}
Here are some images showing the debug location where the cell is not empty, and also printing out the label which has a value, but isn't being shown during simulation.
http://imgur.com/a/dBkpe
This is an image showing the prototype cell. The cell has the correct class set as well as the identifier.
http://imgur.com/PKtFTeQ
Lastly another image showing that the prototype cell is linked to the labels within the CurrentFileCell.
http://imgur.com/nW0QUjM
Any help at all with this would be appreciated. I have tried recreating everything but continue to be stumped as it seems like everything is how it should be.
You have to implement the 'heightForRowAtIndexPath' method for the table view
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let height:CGFloat = 75
return height
}
You may consider registering the custom class as it does not appear that you did. You can do that by using the following code in the viewDidLoad of your View Controller.
tableView.registerClass(CurrentFileCell.self, forCellReuseIdentifier: "cell")
If you are using an external nib you will want to use registerNib instead like so:
tableView.registerNib(UINib(name:"ReplaceWithYourNibName", bundle: nil), forCellReuseIdentifier: "ReuseIdentifier")
Of course, replace ReplaceWithYourNibName and ReuseIdentifier with the appropriate values. In addition, if your nib is in a different bundle specify that instead of nil (nil defaults to the main bundle).
However, do not use both registerClass and registerNib as whichever one you call last will be used and they were designed to be mutually exclusive. Whenever you make a custom UITableViewCell you must use either of the two for it to work unless you have set it explicitly in the storyboard.
Also, you could instead, use prototype cells to define your custom cell, which would, I believe, automatically register the cell. But only if you did not use prototype cells make sure to use registerClass or registerNib.
Good luck! Hope this helps!
If your cell is a static cell, then you need to comment out these methods in UITableViewDataSource:
/* override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 0
} */
I had the same issue.
Data has values and cell rows are showing empty.
I figured it by adding
contentView.addSubview(titleLabel)
where cell values are being set.

How to create UIImageVIew in custom UITableViewCell? (Swift)

I have a UITableView in a UIViewController, and 1 prototype cell which is defined in my own custom cell class. I have a UIImageView in the top right corner, with top and trailing margin constraints, as well as a fixed width and height:
In Interface Builder
The problem is, when I run the program, the TableView is created but the imageView is oversized:
At runtime
After researching some similar questions on this site, I've come to the conclusion that:
The cell's imageView only appears and is sized when you assign an
image to it.
I've already tried the following code in the custom cell class, and the cellForRowAtIndexPath function:
cell.imageView?.frame = CGRectMake(300, 52, 292, 136)
cell.imageView?.clipsToBounds = true
cell.contentView.addSubview(cell.imageView!)
Am I missing something or what do I do to get the imageView to the size I've made its constraints for?
Thank you in advance!
UIView has the attribute contentMode - try to define it as ScaleToFill:
self.someImage.contentMode = .ScaleToFill
Thanks for the help everyone!
I made a stupid mistake by referencing the custom cell's generic imageView?, rather than the IB Outlet I made under a different name.
Wrong:
cell.imageView?.image = UIImage(named: "whatever name")
Right:
cell.dogImageView.image = UIImage(named: "labrador")
Out of interest, what values are the fixed width and height constraints? It's hard to tell the difference between the interface builder and the device screenshots as the size of the view controller is different.
My suggestion would be doing away with the fixed width and height constraints, and instead:
• Pin the bottom of the image view to the bottom of the cell - this gives the image view it's height.
• Add an aspect ratio constraint to the image view - this gives the image view it's width, based on it's height.
This means that even if you end up changing the height of your cells, your image view will always fit inside of the cell.
Kudos for using prototype cells and a UITableViewCell subclass though - I agree with this method completely!
Your code seems vague although I agree with you using the custom cell class. What this does is to attempt to download all images set and if unable to download, it will replace the image with an image placeholder saved on the assets. All images have the same sizes when loaded.
Here is what you can do to make it work. Here is your custom class.
class SomeCell: UITableViewCell {
#IBOutlet weak var imgMain: UIImageView!
#IBOutlet weak var lblMain: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
imgMain.layer.cornerRadius = 5.0
imgMain.clipsToBounds = true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func configureCell(image: UIImage, text: String){
imgMain.image = image
lblMain.text = text
}
}
Then on your ViewController
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var somePics = ["http://www.something.com/pic1.jpg","http://www.something.net/pic2.jpg","http://www.something.com/pic3.jpg","http://www.something.com/pic4.jpg","http://www.something.net/pic5.jpg"]
var someTitles = ["Picture 1", "Picture 2", "Picture 3", "Picture 4", "Picture 5"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("SomeCell") as? SomeCell {
var img: UIImage!
let url = NSURL(string: somePics[indexPath.row])!
if let data = NSData(contentsOfURL: url) {
img = UIImage(data: data)
}else {
img = UIImage(named: "somePlaceholderpic")
}
cell.configureCell(img, text: someTitles[indexPath.row])
return cell
} else {
return SomeCell()
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return somePics.count
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Hope this helps. :)

Data not showing in custom tableview cell in swift have added the cell class below

I have tried everything possible but I still can't figure out why the data is not shown in a custom cell. It looks fine in a subTitle cell and println confirms the data is there. I have checked the identifier and the IBOutlets a 100 times:
// ActivityDetailsTableViewController.swift
// TestActForm
//
// Created by Jeremy Andrews on 2015/08/08.
// Copyright (c) 2015 Jeremy Andrews. All rights reserved.
//
import UIKit
class ActivityDetailsTableViewController: UITableViewController
{
var activities: [Activity] = activityProfile
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return activities.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("ActivityDetail", forIndexPath: indexPath) as! ActivityDetailCell
let activity = activities[indexPath.row] as Activity
println(activity.question)
cell.questionLabel?.text = activity.question
cell.answerLabel?.text = activity.answer
println(cell.questionLabel.text)
return cell
}
}
import UIKit
class ActivityDetailCell: UITableViewCell
{
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var answerLabel: 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
}
}
Thanks to everyone who gave suggestions - after 2 days struggle I finally found the solution thanks to: creating custom tableview cells in swift.
All you have to do is go to file inspector - uncheck size classes - there will be warnings etc.run and there is the data - strangely - go back to file inspector and check "use size classes" again, run and all data correctly reflected. Seems like in some cases the margin is set to negative.
A thought - if println( cell.nameLabel.text) shows your data is there then it is, check margin or put labels in the centre as a trial.
I noticed before that the story board had a highlighted area that did not match the cell boundaries - this actually showed the boundaries that run would use. A bug I think
Use a breakpoint in cellForRowAtIndexPath and check cell, outlets, model.
Also check if you set the delegate, datasource and outlet for the table.
cell.questionLabel?.text = activity.question
cell.answerLabel?.text = activity.answer
this code would fail silently if these label are not created. I bet you did not hook them up via IBOutlets in your storyboard.

Swift - pop up view, date picker?

I've googled for hours and have tried a handful of tutorials, but haven't been able to get this working:
I have a TableView, and I want to make it so pressing on a cell presents a popup that has a date picker.
I have my custom viewcontroller with the date picker presenting (popping up from the bottom), but it takes up the entire screen. Thoughts? I found one mention of this exact issue while googling but the solution didn't work.
One possibility is to overlay a subview (object of UIView) (with a date picker and a done button) on top of your tableview. Then use .hidden feature of the subview to hide/show the view. The following is an example of the tableviewcontroller. When setting up the storyboard make sure that the subview has the layout constraints so the date picker is positioned properly. I used the "resolve auto layout issues" and it worked good. Unless you do special processing the subview will get positioned at the bottom of the rows. If you have a lot of rows the aubview will get clipped or hidden completely. So it is better to position the subview at the relative to the bottom of the page in your auto layout.
Here is a simple example that worked well for me. In viewDidLoad the subview is hidden. When you click on any row it will show the subview and the date picker. When you press done it will hide the subview again.
import UIKit
class TableViewController: UITableViewController {
#IBAction func doneButton(sender: UIButton) {
// process the date using datePickerOutlet properties
subView.hidden = true // hide the subview and its components
}
#IBOutlet weak var subView: UIView!
#IBOutlet weak var datePickerOutlet: UIDatePicker!
#IBAction func datePicker(sender: UIDatePicker) {
}
override func viewDidLoad() {
super.viewDidLoad()
subView.hidden = true // hide the subview and its components
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("\(indexPath.row)")
subView.hidden = false // show the subview and its components
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = "\(indexPath.row)"
return cell
}
}
Alternatively, put it in a UIAlertView(). At least it will be centered. It's going to be tough to combine a table and a picker on a small screen, like let's say a 4S.
I think this should work:
override var preferredContentSize: CGSize {
get{
// Checks if it is currently presenting
if presentingViewController != nil {
return (datePicker.sizeThatFits(presentingViewController!.view.bounds.size))
}
return super.preferredContentSize
}
set{ super.preferredContentSize = newValue }
}
This code goes under the View controller for the popup.
Basically what it does is to set the width of the popup to the minimum size required for the date picker.
Got it from the iTunes U tutorial by Paul Hegarty

Resources