UITableView only updating on scroll up, not down - ios

I have a UITableView that updates when I scroll up, but it does not update when I scroll down. Furthermore, when it does update it occasionally seems to "skip" a cell and update the next one.
There are 6 total cells that should populate
I've created the UITableView in the storyboard, set my constraints for both the hashLabel and the creditLabel in storyboard
Here is the image of the initial TableView:
And upon scrolling up, when updated properly:
...and when scrolling up "misses" a cell:
and of course, the class:
class HashtagController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var model:ModelData!
var currentCell: UITableViewCell!
#IBOutlet var hashtagTableView: UITableView!
let basicCellIdentifier = "CustomCells"
override func viewDidLoad() {
super.viewDidLoad()
model = (self.tabBarController as CaptionTabBarController).model
hashtagTableView.delegate = self
hashtagTableView.dataSource = self
self.navigationController?.navigationBar.titleTextAttributes = [ NSFontAttributeName: UIFont(name: "CherrySwash-Regular", size: 25)!, NSForegroundColorAttributeName: UIColor(red:27.0/255, green: 145.0/255, blue: 114.0/255, alpha: 1.0)]
configureTableView()
hashtagTableView.reloadData()
}
func configureTableView() {
hashtagTableView.rowHeight = UITableViewAutomaticDimension
hashtagTableView.estimatedRowHeight = 160.0
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//deselectAllRows()
hashtagTableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
hashtagTableView.reloadData()
}
func deselectAllRows() {
if let selectedRows = hashtagTableView.indexPathsForSelectedRows() as? [NSIndexPath] {
for indexPath in selectedRows {
hashtagTableView.deselectRowAtIndexPath(indexPath, animated: false)
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.quoteItems.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return customCellAtIndexPath(indexPath)
}
func customCellAtIndexPath(indexPath:NSIndexPath) -> CustomCells {
var cell = hashtagTableView.dequeueReusableCellWithIdentifier(basicCellIdentifier) as CustomCells
setTitleForCell(cell, indexPath: indexPath)
setSubtitleForCell(cell, indexPath: indexPath)
return cell
}
func setTitleForCell(cell:CustomCells, indexPath:NSIndexPath) {
let item = Array(Array(model.quoteItems.values)[indexPath.row])[0] as? String
cell.hashLabel.text = item
}
func setSubtitleForCell(cell:CustomCells, indexPath:NSIndexPath) {
let item = Array(model.quoteItems.keys)[indexPath.row]
cell.creditLabel.text = item
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
/*currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
var currentLabel = currentCell.textLabel?.text
var currentAuthor = currentCell.detailTextLabel?.text
model.quote = currentLabel!
model.author = currentAuthor!*/
}
}
class CustomCells: UITableViewCell {
#IBOutlet var hashLabel: UILabel!
#IBOutlet var creditLabel: UILabel!
}

As it turns out, the issue had to do with my estimatedRowHeight. In this case the row height was too large and it was effecting the way the table cells were being constructed.
So in the end I changed hashtagTableView.estimatedRowHeight = 160.0 to hashtagTableView.estimatedRowHeight = 80.0 and everything worked just fine.

Related

How to make an expandable and collapsable UITableView (parent and child cells) in swift?

I wanted to have a UITableView which is able to expand and collapse while clicking on cells.
When I load the page, I want the Tableview to be expanded like this and function collapse and expand by clicking on the header(see the date).
Any help is appreciated.
Thanks everyone. I have solved the problem at last.This is the final sample code.
1) //Arrays for header and Child cells.
var topItems = [String]()
var subItems = [String]()
//Section index reference
var selectedIndexPathSection:Int = -1
2) Added Two custom cells. - one as header and other as Cell.
// AgendaListHeaderTableViewCell.swift
import UIKit
class AgendaListHeaderTableViewCell: UITableViewCell {
#IBOutlet weak var agendaDateLabel: UILabel!
#IBOutlet weak var expandCollapseImageView: UIImageView!
#IBOutlet weak var headerCellButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Child cell:
// AgendaListTableViewCell.swift
import UIKit
class AgendaListTableViewCell: UITableViewCell {
#IBOutlet weak var agendaListContainerView: UIView!
#IBOutlet weak var moduleListTitleLabel: UILabel!
#IBOutlet weak var moduleDueOnStatusLabel: UILabel!
#IBOutlet weak var moduleLocationLabel: UILabel!
#IBOutlet weak var moduleStatusLabel: UILabel!
#IBOutlet weak var moduleDownLoadStatusImageView: UIImageView!
#IBOutlet weak var moduleStatusLeftSideLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
agendaListContainerView.layer.cornerRadius = 3.0
moduleStatusLabel.layer.borderWidth = 0.5
moduleStatusLabel.layer.borderColor = UIColor.clearColor().CGColor
moduleStatusLabel.clipsToBounds = true
moduleStatusLabel.layer.cornerRadius = 5.0
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
3) On View Controller:
// AgendaListViewController.swift
import UIKit
class AgendaListViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var agendaListTableView: UITableView!
var appUIColor:UIColor = UIColor.brownColor()
var topItems = [String]()
var subItems = [String]()
var selectedIndexPathSection:Int = -1
override func viewDidLoad() {
super.viewDidLoad()
topItems = ["26th April 2017","27th April 2017","28th April 2017","29th April 2017","30th April 2017"]
subItems = ["Monday","TuesDay","WednessDay"]
}
override func viewWillAppear(animated: Bool) {
self.title = "AGENDA VIEW"
self.automaticallyAdjustsScrollViewInsets = false
agendaListTableView.tableFooterView = UIView(frame: CGRectZero)
}
//tableview delegate methods
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 85;
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return topItems.count
}
func tableView(tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 35
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCellWithIdentifier("agendaTableViewHeaderCellD") as! AgendaListHeaderTableViewCell
headerCell.agendaDateLabel.text = topItems[section]as String
//a buttton is added on the top of all UI elements on the cell and its tag is being set as header's section.
headerCell.headerCellButton.tag = section+100
headerCell.headerCellButton.addTarget(self, action: "headerCellButtonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
//minimize and maximize image with animation.
if(selectedIndexPathSection == (headerCell.headerCellButton.tag-100))
{
UIView.animateWithDuration(0.3, delay: 1.0, usingSpringWithDamping: 5.0, initialSpringVelocity: 5.0, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
headerCell.expandCollapseImageView.image = UIImage(named: "maximize")
}, completion: nil)
}
else{
UIView.animateWithDuration(0.3, delay: 1.0, usingSpringWithDamping: 5.0, initialSpringVelocity: 5.0, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
headerCell.expandCollapseImageView.image = UIImage(named: "minimize")
}, completion: nil)
}
return headerCell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if( selectedIndexPathSection == section){
return 0
}
else {
return self.subItems.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let childCell = tableView.dequeueReusableCellWithIdentifier("agendaTableViewCellID", forIndexPath: indexPath) as! AgendaListTableViewCell
childCell.moduleListTitleLabel.text = subItems[indexPath.row] as? String
childCell.moduleLocationLabel.text = subItems[indexPath.row] as? String
childCell.moduleDueOnStatusLabel.text = subItems[indexPath.row] as? String
return childCell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
//button tapped on header cell
func headerCellButtonTapped(sender:UIButton)
{
if(selectedIndexPathSection == (sender.tag-100))
{
selectedIndexPathSection = -1
}
else {
print("button tag : \(sender.tag)")
selectedIndexPathSection = sender.tag - 100
}
//reload tablview
UIView.animateWithDuration(0.3, delay: 1.0, options: UIViewAnimationOptions.TransitionCrossDissolve , animations: {
self.agendaListTableView.reloadData()
}, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The sample can be downloaded # https://github.com/alvinreuben/Expand-ColllapseTableView
**Try to implement below**
import UIKit
class BankDepositsHistoryVC: UIViewController {
#IBOutlet weak var tableView: UITableView!
let NORMAL_HEIGHT:CGFloat = 90
let EXPANDABLE_HEIGHT:CGFloat = 200
var SECTION_OTHER_CARDS = 0
var expandableRow:Int = Int()
override func viewDidLoad() {
super.viewDidLoad()
self.expandableRow = self.historyData.count + 1 // initially there is no expanded cell
self.tableView.reloadData()
}
// MARK: - TableViewDelegate Setup
extension BankDepositsHistoryVC : UITableViewDelegate,UITableViewDataSource {
func numberOfSectionsInTableView(tableView: UITableView) -> Int{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.historyData.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
let value = indexPath.section
let row = indexPath.row
switch (value){
case SECTION_OTHER_CARDS:
switch (row){
case self.expandableRow:
return EXPANDABLE_HEIGHT
default:
return NORMAL_HEIGHT
}
default:
return 0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DepositsHistoryCell", forIndexPath: indexPath) as! DepositsHistoryCell
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
self.expandableRow = indexPath.row // provide row to be expanded
//self.tableView.reloadSections(NSIndexSet(index: indexPath.row), withRowAnimation: UITableViewRowAnimation.Fade)
self.tableView.reloadData()
}
}
with the help of below method you can do that
for objective-c
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
for swift
func tableView(_ tableView: UITableView,heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
just change the height for a row when its get clicked and reload the section.
when you design any cell in storyboard don't put bottom constraint on the expandable part.just put top and height constraint.Hope this help :)

No call to my didSelectRowAtIndexPath function

I'm trying to create an app that displays some data on labels on the top of a screen, and then the lower half or so is a table which will allow selection of an item in the table to pop up another segue for editing a value. I'm struggling though to get the didSelectRowAtIndexPath to be called when an item on the list is selected by the user. I've put the code for the View controller below.
I've searched quite a bit and haven't found anything so far that explains the issue I'm seeing.
I think I've connected everything up correctly as far as delegates and datasource, and I'm not using any gesture captures so it's not those. Does anyone have any ideas?
I've attached screen grabs of the view controller connections and attributes inspector settings as well.
Connections screengrab
Attributes screengrab
import UIKit
class TemperatureViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var CurrentTemp: UILabel!
#IBOutlet weak var HeaterStatus: UILabel!
#IBOutlet weak var ChillerStatus: UILabel!
#IBOutlet weak var TempTableView: UITableView!
var settings = [TemperatureSettings] ()
var HeaterTemp:Float = 0.0
var ChillerTemp:Float = 0.0
var ThresholdTemp:Float = 0.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.loadTempSettings()
TempTableView.delegate = self
TempTableView.dataSource = self
TempTableView.allowsSelection = true
TempTableView.editing = false
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.loadTempSettings()
}
func loadTempSettings() {
let TempSetting1 = TemperatureSettings(name: "Heater On at", CurrentSetting: HeaterTemp)!
let TempSetting2 = TemperatureSettings(name: "Chiller On at", CurrentSetting: ChillerTemp)!
let TempSetting3 = TemperatureSettings(name: "Threshold", CurrentSetting: ThresholdTemp)!
settings = [TempSetting1, TempSetting2, TempSetting3]
TempTableView.reloadData()
//refreshControl?.endRefreshing()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return settings.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Stop spoof separators after the table entries for blank entries
tableView.tableFooterView = UIView(frame: CGRect.zeroRect)
// Turn off the separator for each cell.
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
let cellIdentifier = "TemperatureSettingsTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TemperatureSettingsTableViewCell
let setting = settings[indexPath.row]
cell.SettingNameLabel.text = setting.name
cell.SettingCurrentLabel.text = String(format: "%.1f C", setting.CurrentSetting)
cell.SettingCurrentLabel.textAlignment = .Left
// Configure the cell...
//useTimer = true
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Setting Row \(indexPath.row) clicked")
performSegueWithIdentifier("Settings", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This works for me:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("works");
}
Add override before func maybe?

How to add a cell to my Table View dynamically using a button

I am trying to add a cell to my table view with a button. Everything I have read and watched suggests that what I have written should work, but it doesn't. Any suggestions?
import UIKit
class RootViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
private var cellPointSize: CGFloat!
private var albumsList: AlbumList!
private var albums:[Album]!
private let albumCell = "Album"
#IBOutlet var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let preferredTableViewFont = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
cellPointSize = preferredTableViewFont.pointSize
albumsList = AlbumList.sharedAlbumList
albums = albumsList.albums
self.myTableView.dataSource = self
self.myTableView.delegate = self
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return albums.count
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Albums"
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCellWithIdentifier(albumCell, forIndexPath: indexPath) as! UITableViewCell
//cell.textLabel?.font = fontForDisplay(atIndexPath: indexPath)
cell.textLabel?.text = albums[indexPath.row].name
cell.detailTextLabel?.text = albums[indexPath.row].artist
return cell
}
#IBAction func addNewAlbumAction(sender: UIBarButtonItem) {
var newAlbum = Album(nameIn: "New Title", yearIn: "New Year", artistIn: "New Artist", labelIn: "New Label")
albumsList.addAlbum(newAlbum)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.myTableView.reloadData()
})
}
func saveData(albumObject: Album) {
var archiveArray = NSMutableArray(capacity: albums.count)
for a in albums {
var albumEncodedObject = NSKeyedArchiver.archivedDataWithRootObject(a)
archiveArray.addObject(albumEncodedObject)
}
var userData = NSUserDefaults()
userData.setObject(archiveArray, forKey: "albums")
userData.synchronize()
}
My albums array is adding the data correctly. I can see the albums in the debugger. The delegate methods are never being called after the first time when the app loads. Any ideas?
in tableView:numberOfRowsInSection:, it returns albums.count
but when the button is pressed, you add the new album to albumsList
The problem is, albums will not get update.
So I think you should return albumsList.albums.count instead.
and in tableView:cellForRowAtIndexPath:, you modify the cell correspond to albumsList.albums[indexPath.row]

UICollectionView cells with Images inside UITableView prototype

UPDATE: I solved my primary issue of correct images not loading until scrolling on the collectionView. I added a collectionView.reloadData() to the tableView:cellForRowAtIndexPath. I also made some changes to pre-load the sequence array, instead of building it while scrolling through the table (tableView:cellForRowAtIndexPath).
Added the updates to GitHub if you are interested.
https://github.com/Druiced/OpenDeck
I will follow-up once I figure out how to prevent the App from crashing when a dynamic value is placed in the return (if i set this to 15, the app will not crash):
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return count(Array(sequenceArray[collectionView.tag])) / 2
}
ORIGINAL POST:
request for some guidance.
This tutorial helped me realize this must have to do with my DataSource/Delegate. The author builds the cell with addSubview instead of taking advantage of the Xcode prototype cell, which seems like a cool thing, so I'm trying to do it.
http://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell
Any criticism about my approach or failure to follow best practices is welcome.
Each cell in the table has a UICollectionView. Each cell in the Collection View displays an image in order of the saved "Sequence" string. example: "ADKDQDJDTD" link up to AD.png KD.png QD.png JD.png TD.png
I have two issues I can't seem to get past.
numberOfItemsInSection gets whacky when the number of cards is driven by the array length (return handArray.count / 2). If I place a fixed number the app will work, but not very slick.
When the table first comes up, the correct cards do not display until I scroll up and down the table. It also appears the data for each CollectionView is crossing paths as the wrong cards show up when scrolling up and down rapidly.
I'm almost positive this has to do with how my datasource is setup.
DeckTableViewController.swift
import UIKit
import Parse
var deviceID: String?
var noRefresh: Bool?
var sequenceArray: Array<Character>?
class DeckTableViewController: UITableViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var handArray: Array<Character>!
var timeLineData:NSMutableArray = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
noRefresh = false
deviceId = UIDevice.currentDevice().identifierForVendor.UUIDString
}
override func viewDidAppear(animated: Bool) {
if noRefresh == false {
loadData()
noRefresh = true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return timeLineData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:DeckTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DeckTableViewCell
let deck:PFObject = timeLineData.objectAtIndex(indexPath.row) as! PFObject
cell.collectionView.dataSource = self
cell.collectionView.delegate = self
let sequenceTemp = deck.objectForKey("Sequence") as! String
handArray = Array(sequenceTemp)
cell.sequenceId.setTitle(deck.objectId, forState: UIControlState.Normal)
cell.cardCountLabel.text = "\((count(sequenceTemp)/2))"
// Date to String Stuff
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "(MM-dd) hh:mm:ss"
cell.timeLabel.text = dateFormatter.stringFromDate(deck.updatedAt!)
let layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSizeMake(99, 140)
layout.scrollDirection = UICollectionViewScrollDirection.Horizontal
cell.collectionView.collectionViewLayout = layout
return cell
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return handArray.count / 2
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:TableCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! TableCollectionViewCell
var bcolor : UIColor = UIColor.orangeColor()
cell.layer.borderColor = bcolor.CGColor
cell.layer.borderWidth = 2
cell.layer.cornerRadius = 3
var firstLetter: Character!
var secondLetter: Character!
//Building card file names from Sequence data
if (indexPath.row * 2) + 1 <= handArray.count {
firstLetter = handArray[indexPath.row * 2]
secondLetter = handArray[indexPath.row * 2 + 1]
let imageNameString = "\(firstLetter)\(secondLetter).png"
let front = UIImage(named: imageNameString)
cell.ImageView.backgroundColor = UIColor.orangeColor()
cell.ImageView.image = front
}
return cell
}
DeckTableViewCell.swift
import UIKit
class DeckTableViewCell: UITableViewCell, UITextViewDelegate {
#IBOutlet var collectionView: UICollectionView!
#IBOutlet var sequenceId: UIButton!
#IBOutlet var timeLabel: UILabel!
#IBOutlet var cardCountLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
TableCollectionViewCell.swift
import UIKit
class TableCollectionViewCell: UICollectionViewCell {
#IBOutlet var ImageView: UIImageView!
}
For this example I set (return handArray.count / 2) to a 10 and loaded 3 sequences.
The number in the top center represents the number of cards for each row.
Notice the CollectionView does not update with the right cards, it's picking up data from the other CollectionViews. IF I add bunch more sequences to this mix, when scrolling up and down, the correct cards WILL populate SOMETIMES, but unpredictable.
Thanks for any suggestions, I'm happy to go back to the drawing board. Cheers
Ok lets think this way, your DeckTableViewController acts as datasource for tableview, and DeckTableViewCell acts as datasource for collection view.
with the above thing in mind we create a sample project
i am not going in depth, i am giving example like the tutorial as u go through
lets create a sample project with single view app and in ViewController
past the below code, i took one array of integers which contains some values as how many cells to be appears in collection view. don't forget add tableview and set its datasource and deleagte.
before we are coding to controller class we need some classes like custom tableview cell and custom collection view cell we create them first
create a new file which is the subclass of UICollectionViewCell and name it as CustomCollectionViewCell and with xib file.
class CustomCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var aLabel: UILabel! //to show the card number
#IBOutlet weak var imageView: UIImageView! //imageview i am setting it's background color
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
and create a outlets for label and image view as in the above code.
Next, create new file subclass of UITableViewCell and name it as CustomTableViewCell with xib file. open up CustomTableViewCell.xib file and drag and drop the collection view and set it's datasource and delegate to cell not the controller.
and create a outlet for the collection view and name it as foldersCollectionView.
pass the below code
import UIKit
class CustomTableViewCell: UITableViewCell,UICollectionViewDataSource,UICollectionViewDelegate {
#IBOutlet weak var foldersCollectionView: UICollectionView!
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
// fatalError("init(coder:) has not been implemented")
super.init(coder: aDecoder)
}
var folderCount:Int?
{
didSet(value)
{
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
//configure our collectionview
var aFlowLayout : UICollectionViewFlowLayout = UICollectionViewFlowLayout()
aFlowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal
aFlowLayout.itemSize = CGSizeMake(60.0, 90.0)
aFlowLayout.minimumLineSpacing = 10.0
aFlowLayout.minimumInteritemSpacing = 0.0
aFlowLayout.sectionInset = UIEdgeInsetsMake(2, 9, 0, 10)
foldersCollectionView.collectionViewLayout = aFlowLayout
foldersCollectionView.registerClass(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "FOLDER_CELL")
var cNib:UINib? = UINib(nibName: "CustomCollectionViewCell", bundle: nil)
foldersCollectionView.registerNib(cNib, forCellWithReuseIdentifier: "FOLDER_CELL")
foldersCollectionView.frame = self.bounds
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
class func CreateCustomCell() -> CustomTableViewCell
{
var nibElements: Array = NSBundle.mainBundle().loadNibNamed("CustomTableViewCell", owner: self, options: nil)
var item: AnyObject?
for item in nibElements
{
if item is UITableViewCell
{
return item as CustomTableViewCell
}
}
return item as CustomTableViewCell
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell :CustomCollectionViewCell? = collectionView.dequeueReusableCellWithReuseIdentifier("FOLDER_CELL", forIndexPath: indexPath) as? CustomCollectionViewCell
//hear u can modify which image to be displayed in the collection view cell
cell?.aLabel.text = "Card:\(indexPath.row)"
return cell!
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return folderCount!
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
}
now we are going the code the ViewController class
now just past the below code
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
var cardCountArray:[Int] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
cardCountArray = [5,15,6,12,7,10]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return cardCountArray.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell:CustomTableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? CustomTableViewCell;
if(cell == nil)
{
cell = CustomTableViewCell.CreateCustomCell()
}
cell?.folderCount = cardCountArray[indexPath.section]
cell?.foldersCollectionView.reloadData()
cell?.clipsToBounds = true
return cell!;
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return 100.0
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var headerView:UIView = UIView(frame: CGRectMake(0, 0, tableView.bounds.size.width, 70.0))
var labelTitle:UILabel = UILabel(frame: CGRectMake(0, 0, tableView.bounds.size.width, 35))
var descriptionTitle:UILabel = UILabel(frame: CGRectMake(0, 20,tableView.bounds.size.width , 30))
headerView.addSubview(labelTitle)
headerView.addSubview(descriptionTitle)
labelTitle.text = "TOTAL_CARDS in section:\(section)"
descriptionTitle.text = "This CARD_SECTION contains \(cardCountArray[section]) CARDS"
return headerView
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50.0
}
}
result will be like below
if any thing missing please let me know
For your comment I have an array, for example, ["2C3C4C5C6C7C", "AD2D3D4D5D", "9H8H7H"]
for this u need to make below modification
//for first row u get like this
//the string for the row is 2C3C4C5C6C7C
//stringForCell = "2C3C4C5C6C7C"
//2C
//3C
//4C
//5C
//6C
//7C
//for other cells u can get like below
//the string for the row is AD2D3D4D5D
//stringForCell = "AD2D3D4D5D"
//AD
//2D
//3D
//4D
//5D
//the string for the row is 9H8H7H
//stringForCell = "9H8H7H"
//9H
//8H
//7H
//in controller controller class define array of string
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
var cardCountArray:[Int] = []
var stringArray : [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
stringArray = ["2C3C4C5C6C7C", "AD2D3D4D5D", "9H8H7H"]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
// return cardCountArray.count
return stringArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell:CustomTableViewCell? = tableView.dequeueReusableCellWithIdentifier("CELL") as? CustomTableViewCell;
if(cell == nil)
{
cell = CustomTableViewCell.CreateCustomCell()
}
//cell?.folderCount = cardCountArray[indexPath.section]
cell?.stringForCell = stringArray[indexPath.section];
cell?.foldersCollectionView.reloadData()
cell?.clipsToBounds = true
return cell!;
}
//in custom tableview cell add a string variable
class CustomTableViewCell: UITableViewCell,UICollectionViewDataSource,UICollectionViewDelegate {
#IBOutlet weak var foldersCollectionView: UICollectionView!
var stringForCell:String = "" //add the string to hold the string
//rest of the code
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell :CustomCollectionViewCell? = collectionView.dequeueReusableCellWithReuseIdentifier("FOLDER_CELL", forIndexPath: indexPath) as? CustomCollectionViewCell
var str:NSString = stringForCell
var length = str.length
var totalLlength:Int = length/2
var indexStart = indexPath.row * (2);
var aRange = NSMakeRange(indexStart, 2)
var cardString:NSString = str.substringWithRange(aRange)
println(cardString)
cell?.aLabel.text = "Card: \(cardString)"
return cell!
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
println("the string for the row is \(stringForCell)")
var str:NSString = stringForCell
var length:Int = str.length
return length / 2
//return folderCount!
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
i written a detailed post about how to add collection view inside custom table view cell hear hope this gives more detailed explanation than this post.

dynamic tableview inside custom tableviewcell

I'm trying to create a tableview with custom cells that each one holds a tableview.
I want to show the inner tableview just when it have some data (most of the time it's empty). I've managed to display the cells but can't display their tableview if it's populated with data.
The problem also is that the cell height needs to be dynamic according to the amount of data to display.
The cell code:
class feedViewCell: UITableViewCell , UITableViewDataSource , UITableViewDelegate {
#IBOutlet var feedCellImage: UIImageView!
#IBOutlet var feedCellUserName: UILabel!
#IBOutlet var feedCellDate: UILabel!
#IBOutlet var feedCellComments: UILabel!
#IBOutlet var cardView: UIView!
#IBOutlet var repliesTableView: UITableView!
var repliesArray:[Reply] = []
#IBAction func addComment(sender: AnyObject) {
}
override func awakeFromNib() {
super.awakeFromNib()
var nib = UINib(nibName: "feedComment", bundle: nil)
repliesTableView.registerNib(nib, forCellReuseIdentifier: "commentCell")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func layoutSubviews() {
cardSetup()
}
func cardSetup() {
cardView.layer.masksToBounds = false
cardView.layer.cornerRadius = 5
cardView.layer.shadowOffset = CGSizeMake(-0.2, 0.2)
cardView.layer.shadowRadius = 1
cardView.layer.shadowOpacity = 0.2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return repliesArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = repliesTableView.dequeueReusableCellWithIdentifier("commentCell", forIndexPath: indexPath) as CommentFeedCell
cell.commentCellUserName.text = repliesArray[indexPath.row].userName
return cell
}
}
And the Main controller code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var comment = comments[indexPath.row]
let cell: feedViewCell = tableView.dequeueReusableCellWithIdentifier("feedCell", forIndexPath: indexPath) as feedViewCell
cell.feedCellUserName.text = comment.userName
cell.feedCellImage.backgroundColor = UIColor.redColor()
cell.feedCellComments.text = "\(comment.replies.count) COMMENTS"
cell.repliesArray = comment.replies
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yyy"
cell.feedCellDate.text = dateFormatter.stringFromDate(NSDate())
if cell.repliesArray.count > 0 {
cell.repliesTableView.rowHeight = UITableViewAutomaticDimension
}
cell.repliesTableView.reloadData()
return cell
}
How to show the inner tableview only in cells which have comments (and hiding the tableview in cells with 0 comments)?
Call super in layoutSubviews and let us know what happens.
override func layoutSubviews() {
super.layoutSubviews()
cardSetup()
}

Resources