I'm trying to change the height of a single cell, which normally would be a piece of cake, but i seem to have a strange behavior. When i change the first cells height, it changes the second cells height. What could be the reason for this?
func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.categroyArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("FilterCell") as? FilterCell
var bottomLine:UIView = UIView(frame: CGRectMake(0, cell!.bounds.height, self.view.frame.width, 1))
bottomLine.backgroundColor = UIColor(rgba: "#cecece")
cell?.addSubview(bottomLine)
if indexPath.row == 0 {
var categoryScroll:HMSegmentedControl = HMSegmentedControl(frame: CGRectMake(0, 0, cell!.bounds.width, cell!.bounds.height))
categoryScroll.sectionTitles = self.categroyArray
categoryScroll.autoresizingMask = UIViewAutoresizing.FlexibleRightMargin | UIViewAutoresizing.FlexibleWidth
categoryScroll.font = UIFont(name: "HelveticaNeue", size: 12)
categoryScroll.selectionStyle = HMSegmentedControlSelectionStyleFullWidthStripe
categoryScroll.selectionIndicatorColor = UIColor(rgba: "#b44a44")
categoryScroll.selectedTextColor = UIColor(rgba: "#b44a44")
categoryScroll.textColor = UIColor(rgba: "#666666")
categoryScroll.selectionIndicatorLocation = HMSegmentedControlSelectionIndicatorLocationDown
categoryScroll.segmentEdgeInset = UIEdgeInsetsMake(0, 10, 0, 10)
categoryScroll.selectionIndicatorHeight = 4
cell?.addSubview(categoryScroll)
}
return cell!
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 0 {
return 100
} else {
return 44
}
}
Illustration:
You have a few problems:
You're adding subviews to the cell every time cellForRowAtIndexPath: is called. This is incorrect if you dequeue a cell which already has these subviews.
You're relying on the cell's frame/bounds within the same method. However, the table view hasn't set the cell's frame at this point.
You can resolve both of these problems by moving this code out of this method and into the appropriate methods in your cell subclass.
Related
I have my tableview hooked up property to my viewcontroller class however I am unable to get all of my cells to return within the sections. I want 10pix margins between each cell and was able to do this successfully in another VC, however now the method that I am using is only returning one cell (there are only 2 cells total) so I would like help in figuring out a way to display all cells within the section, code is included below:
//UITableViewDataSource
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.layer.cornerRadius = 8.0
headerView.layer.masksToBounds = true
headerView.backgroundColor = UIColor.colorWithHex("A171FF")
let headerLabel = UILabel(frame: CGRect(x: 30, y: 0, width:
tableView.bounds.size.width, height: tableView.bounds.size.height))
headerLabel.font = UIFont(name: "Gill Sans", size: 15)
headerLabel.textColor = UIColor.white
headerLabel.text = self.tableView(self.myWldTbl, titleForHeaderInSection: section)
headerLabel.sizeToFit()
headerView.addSubview(headerLabel)
return headerView
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch (section) {
case 0 :
return userMoves.count
case 1:
return rsvps.count
default :
print("unable to set up sections")
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row % 2 != 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MyWorldTableViewCell.self)) as! MyWorldTableViewCell
//cell appearance
cell.layer.cornerRadius = 8.0
cell.clipsToBounds = true
//cell data
let evt = userMoves[indexPath.row]
cell.rsvpCount.text = "\(rsvps.count)"
//evt img
if let evtImg = evt.event_photo_url {
cell.img.kf.setImage(with: URL(string: Constants.Server.PHOTO_URL + evtImg))
} else {
cell.img.image = UIImage(named: "user_icon")
}
cell.ttl.text = evt.event_name!
return cell } else {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: InvisibleCell.self)) as! InvisibleCell
cell.backgroundColor = UIColor.clear
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row % 2 == 0 {
return 10.0
}
return 102.0
}
//UITableViewDelegate
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30
}
EDITED:
The first thing that is confusing about your code is that you appear to have 2 sections showing the contents of 2 different arrays (per the logic in numberOfRowsInSection), but you don't check the section number in cellForRowAt.
Before anything else, you should be checking indexPath.section in cellForRowAt to make sure you are using the correct array. As written, your code is using the userMoves array to populate both sections.
The cause of your missing cells is that you must account for the invisible separator cells in your numberOfRowsInSection method. You had the right idea to multiply by 2:
switch (section) {
case 0 :
return userMoves.count * 2
//etc
}
When accessing the array, in cellForRowAt, you need to divide by 2 to avoid the index out of bounds exception:
if indexPath.row % 2 != 0 {
//dequeue, etc.
let evt = userMoves[indexPath.row / 2]
//etc.
}
I'm using code below to get rid of last static cell bottom separator line and it works perfectly for cases when I don't need to reload tableView. Once I reload my tableView separator line appears.
Only code in super VC:
override func viewDidLoad() {
super.viewDidLoad()
let footerFrame = CGRect(x: 0.0, y: 0.0, width:
tableView.frame.size.width, height: 1.0)
tableView.tableFooterView = UIView(frame: footerFrame)
}
And after calling:
fileprivate func showDatePicker()
{
datePicker.setValue(UIColor.white, forKey: "textColor")
showsDatePicker = true
tableView.beginUpdates()
tableView.endUpdates()
tableView.contentInset = UIEdgeInsets(top: -20.0, left: 0.0,
bottom: 0.0, right: 0.0)
}
in my child's tableView(didSelectRowAt indexPath:_) I'm just changing the cell's height with date picker in:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard showsDatePicker else {
switch indexPath.row {
case CellIndex.withDatePicker:
return 0.0
default:
return 44.0
}
}
switch indexPath.row {
case CellIndex.withDatePicker:
return 217.0
default:
return 44.0
}
}
and after that I have separator line drawn! Maybe it's because of STATIC cells usage and the only way is to add blank views to each viewController in storyboard? Replacing tableView.tableFooterView = UIView() to viewDid/WillLayoutSubviews causes empty screen effect. I don't want to add a blank view to all my controllers in the storyboards, maybe there is a way to do it programmatically?
Before displaying your last cell.
if indexPath.row == Your_last_Cell {
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0);
}
create footer with minimum height:
func tableView(_ tableView: UITableView,
heightForFooterInSection section: Int) -> CGFloat{
// This will create a "invisible" footer
return 0.01f; //CGFLOAT_MIN
}
OR
func tableView(_ tableView: UITableView,
viewForFooterInSection section: Int) -> UIView?{
UIView(frame: CGRectZero)
}
My approach to attain this result is as follows,
In your viewDidLoad function,
override func viewDidLoad() {
super.viewDidLoad()
// Add this line
yourTableView.tableFooterView = UIView()
}
Define the number of sections for the table view
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
And in your cellForRowAtIndexPath Function,
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell?
switch indexPath.section {
case 0:
cell = tableView.dequeueReusableCellWithIdentifier("yourfirstcell")
if indexPath.row == yourLastRowIndex {
self.separatorInset = UIEdgeInsetsMake(0, self.bounds.size.width, 0, 0)
}
case 1:
cell = tableView.dequeueReusableCellWithIdentifier("yoursecondcell")
default:
break
}
return cell!
}
This approach will help you.
i am trying to resize row height programmatically in table in UITableViewController. i tried this
class MyProfile: UITableViewController {
var details:[String] = ["collection","of","titles","are","written","here"]
var subdetails:[String] = ["it", "is","a" ,"big", "string", "list"]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0
tableView.tableFooterView = UIView()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return details.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let reuseIdentifier = "eachCellProfile"
var cell:UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) as UITableViewCell?
if (cell != nil) {
cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: reuseIdentifier)
}
cell!.detailTextLabel?.font = UIFont.boldSystemFontOfSize(16.0)
cell?.detailTextLabel?.numberOfLines = 10
cell!.textLabel?.text = self.details[indexPath.row]
cell!.detailTextLabel?.text = self.subdetails[indexPath.row]
return cell!
}
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
}
i didn't add any restriction in table cell. i want to set row height according to title and title details string's length and font size. how can i do it?
Use the heightForRowAtIndexPath to calculate height of each cell before it is created. Use the title detail string that you will use to find the height of and add it to a default height. In my case my default height of cell is 85 and font size is 15.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
var returnValue = CGFloat()
if (dataArray.count > 0) {
let stringData = dataArray[indexPath.row] as NSString
let constraintRect = CGSize(width: 280.0, height: CGFloat.max)
//get height of the string used
let boundingBox = stringData.boundingRectWithSize(constraintRect, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: UIFont.systemFontOfSize(15.0)], context: nil)
return boundingBox.height + CGFloat(85.0)
}
else{
returnValue = CGFloat(85.0);
}
return returnValue;
}
This gave me dynamic cell height according to its content. Hope this helps
I set up my tableView and has two springVar as shown in the image below. I want my tableview to show empty cells after the two springVar so that my solve bar is at the bottom of the screen. Any advices on how to go about it? My code is below.
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return springVar.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Value2, reuseIdentifier: cellIdentifier)
}
cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "cell")
var data : NSManagedObject = springVar[indexPath.row] as! NSManagedObject
cell!.textLabel!.text = "Spring \(indexPath.row + 1)"
var force : Float = data.valueForKey("force") as! Float
var stiffness : Float = data.valueForKey("stiffness") as! Float
cell!.detailTextLabel!.text = "Force =\(force) \t Stiffness =\(stiffness)"
cell!.detailTextLabel!.textColor = UIColor .darkGrayColor()
return cell!
}
i think this maybe helpfull
if indexPAth.row / 2 == 0
{
return UITableViewCell()
// u can customize ur cell to show a button or anything else
}
this show a custom/blank cell after each 2 cell,(odd)
You can add Footer view in your tableView this way:
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 40))
footerView.backgroundColor = UIColor.whiteColor()
//add button in your footer view
var button = UIButton(frame: CGRectMake(0, 0, 75, 30))
button.setTitle("Solve", forState: UIControlState.Normal)
button.setTitleColor(UIColor.brownColor(), forState: UIControlState.Normal)
button.addTarget(self, action: "buttonTapAction:", forControlEvents: UIControlEvents.TouchUpInside)
footerView.addSubview(button)
return footerView
}
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 40.0
}
And your result will be:
You can adjust the footerHeight according to your own needs.
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerHeight : CGFloat = (tableView.frame.size.height - (CGFloat(springVar.count) * 45.0) - 45.0 - 64.0)
let oneCell = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: footerHeight))
return oneCell
}
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
let footerHeight : CGFloat = (tableView.frame.size.height - (CGFloat(springVar.count) * 45.0) - 45.0 - 64.0)
return footerHeight
}
I have 4 sections in my tableView, each section has single cell. When user selects the fourth section's cell, I want them to type on it. So I just added textfield as a accessoryView for that cell in didSelectRow function as shown below.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 3 {
//adding textField
theTextField = UITextField(frame: CGRectMake(10, 480, 300, 40))
theTextField.backgroundColor = UIColor.brownColor()
theTextField.placeholder = "Please type here...."
theTextField.textColor = UIColor.yellowColor()
theTextField.layer.cornerRadius = 10.0
selectedCell?.accessoryView = theTextField
}
But when I click on it, the keyboard is hiding that cell. I want the table view to scroll up. Please help me to resolve this or please please let me know if there is any other way to achieve this!
Not clear why you are implementing the cell specifications in "didSelectRowAtIndexPath" when a more logical place is in "cellForRowAtIndexPath". I implemented your code except putting the cell spec for section 3 in cellForRowAtIndexPath and the table cells are scrolled up as expected. See code below. To take advantage of the tableview scrolling the cell needs to be defined in cellRowForIndex. To meet your objective stated in the comment you can use the .hidden feature and insert the code as shown.
import UIKit
class: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 3 {
selectedCell.accessoryView?.backgroundColor = UIColor.brownColor()
selectedCell.accessoryView?.hidden = false
} else {
selectedCell.accessoryView?.hidden = true
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 4
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
if indexPath.section == 3 {
//adding textField
var theTextField = UITextField(frame: CGRectMake(10, 480, 300, 40))
theTextField.backgroundColor = UIColor.brownColor()
theTextField.placeholder = "Please type here...."
theTextField.textColor = UIColor.yellowColor()
theTextField.layer.cornerRadius = 10.0
cell.accessoryView = theTextField
cell.accessoryView?.hidden = true
}
else {
cell.textLabel!.text = "\(indexPath.section)"
}
return cell
}
}