Auto Re-Sizing Tableview cell to the cells content (SWIFT) - ios

I'm trying to get my tableview to work so when a cell is clicked it resizes to fit the content inside the cell automatically. (Different amounts of text will automatically re-size different.
Cell when not clicked (first state and size it should go back to when clicked = 44.0
So with this image, this is the stage each cell will be in only as default and deselected. The white text will be the only thing visible.
Cell clicked state. resizes to my "let selectedCellHeight: CGFloat = 88.0
" constant. Which needs to automatically size to fit the green text no matter how much is in there.
This is my full code for the tableview and viewcontroller.
import UIKit
class TasksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblTasks: UITableView!
//For persisting data
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
self.tblTasks.backgroundColor = UIColor(red: 64/255.0, green: 67/255.0, blue: 68/255.0, alpha: 0)
self.tblTasks.reloadData()
self.tblTasks.register(UINib(nibName: "WhiteTaskTableViewCell", bundle: nil), forCellReuseIdentifier: "nameCell")
tblTasks.tableFooterView = UIView()
let darkModeColor = UIColor(red: 52/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0)
view.backgroundColor = darkModeColor
tblTasks.dataSource = self;
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
self.tblTasks.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return taskMgr.tasks.count
}
//Define how our cells look - 2 lines a heading and a subtitle
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let identifier = "nameCell"
var cell: WhiteTaskTableViewCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? WhiteTaskTableViewCell
if cell == nil {
tableView.register(UINib(nibName: "WhiteTaskTableViewCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? WhiteTaskTableViewCell
}
// Assign the contents of our var "items" to the textLabel of each cell
// cell.textLabel!.text = taskMgr.tasks[indexPath.row].name
// cell.detailTextLabel!.text = taskMgr.tasks[indexPath.row].desc
cell.TaskNameLabel.text = taskMgr.tasks[indexPath.row].name
cell.NotesLabel.text = taskMgr.tasks[indexPath.row].note
cell.selectionStyle = .none
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(_ willDisplayforRowAttableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = UIColor(red: 64/255.0, green: 67/255.0, blue: 68/255.0, alpha: 0)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
// handle delete (by removing the data from your array and updating the tableview)
taskMgr.removeTask(indexPath.row)
tblTasks.reloadData()
}
}
// EXPAND CELL ON CLICK
// Global Variables/Constants
var selectedCellIndexPath: NSIndexPath?
let selectedCellHeight: CGFloat = 88.0
let unselectedCellHeight: CGFloat = 44.0
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
self.tblTasks.rowHeight = UITableViewAutomaticDimension
if selectedCellIndexPath == indexPath as NSIndexPath? {
return selectedCellHeight
}
return unselectedCellHeight
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedCellIndexPath != nil && selectedCellIndexPath == indexPath as NSIndexPath? {
selectedCellIndexPath = nil
} else {
selectedCellIndexPath = indexPath as NSIndexPath?
}
tableView.beginUpdates()
tableView.endUpdates()
if selectedCellIndexPath != nil {
// This ensures, that the cell is fully visible once expanded
tableView.scrollToRow(at: indexPath as IndexPath, at: .none, animated: true)
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
I'm open to any help and insight. Thank you very much.

You need to set an Outlet to your UITableView and set the rowHeight parameter to UITableViewAutomaticDimension. Also you need set the estimatedRowHeight to a value fitting your needs. This way the size of the Cell will fit the size of its content.
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 55
tableView.rowHeight = UITableViewAutomaticDimension
}
For this to work, you need to set the Autolayout Constraints for every element of your Cell.
Source Apple Doc:
Working with Self-Sizing Table View Cells
In iOS, you can use Auto Layout to define the height of a table view
cell; however, the feature is not enabled by default.
Normally, a cell’s height is determined by the table view delegate’s
tableView:heightForRowAtIndexPath: method. To enable self-sizing table
view cells, you must set the table view’s rowHeight property to
UITableViewAutomaticDimension. You must also assign a value to the
estimatedRowHeight property. As soon as both of these properties are
set, the system uses Auto Layout to calculate the row’s actual height.
Additionally, try to make the estimated row height as accurate as
possible. The system calculates items such as the scroll bar heights
based on these estimates. The more accurate the estimates, the more
seamless the user experience becomes.

Related

layoutSubviews() is ran every time the cell is tapped

I'm developing an iOS app in Swift and I have a UITableView with custom UITableViewCells that have spacing at the left and right of the cell by overriding layoutSubviews().
This works by subtracting 40 to self.bounds.size.width.
As I'm not really good at explaining, here you have an image:
But the problem is that when I click on a cell, the overridden layoutSubviews() function is run again, so the cell is shrunken again as it subtracts 40 again to the already original self.bounds.size.width - 40.
How can I avoid layoutSubviews() running every time the cell is clicked and make it run only once when the view is load?
I do not know why the layoutSubviews is run again, as it is loaded in my custom UITableViewCell class.
Here you have my code:
class TBRepoTableViewCell: UITableViewCell {
#IBOutlet weak var repoLabel: UILabel!
#IBOutlet weak var urlLabel: UILabel!
#IBOutlet weak var repoIcon: UIImageView!
override func layoutSubviews() {
// Set the width of the cell
self.bounds = CGRect(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width - 40, self.bounds.size.height)
super.layoutSubviews()
}
}
class SourcesViewController: UITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// note that indexPath.section is used rather than indexPath.row
print("You tapped cell number \(indexPath.row).")
}
override func viewWillAppear(_ animated: Bool) {
setEditing(false, animated: true)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TBRepoTableViewCell
let repoArray = array[indexPath.row]
cell.repoLabel.text = repoArray.repoName
cell.urlLabel.text = repoArray.repoURL
cell.repoIcon.image = repoArray.icon
self.tableView.separatorStyle = .none
// add borders
cell.layer.cornerRadius = 10
cell.clipsToBounds = true
cell.layer.masksToBounds = true
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
array.remove(at: indexPath.row)
tableView.reloadData()
}
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
}
Never modify the view's frame or bounds in layoutSubviews. The only thing you should do there is update the frame or bounds of the view's subviews based on the current size of the view.
What you should do is modify your cell view class such that it has a view that shows the indent and the rounded corners. Let's call this a "background view". Add the other subviews of the cell to this background view. Then add the background view to the cell's contentView.
Your cellForRowAt should not be changing the cell's layer. That logic belongs in the custom cell class.

UITableView not drawing cells properly on initial load - Swift

I have a table view that's in a nib file and it loads the data properly. It loads the required number of cells and fills in the data correctly. The cell is a xib file as well that includes multiple views. Each cell has a custom height. I managed to set the right height per cell using:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return (data[indexPath.row].height + 200)
}
The problem is that on initial load the cells don't get drawn properly like so:
Initial load image
The description area doesn't move where I made it move by changing its X and Y coordinates.
This gets fixed however when I scroll the table view beyond the initially loaded cells and go back to them, like so:
After scrolling
Upon loading the cell I move the description area below the image. This works for cells but not on the initially loaded ones. It only gets fixed once I scroll the broken cells out of view and go back to them. How do I fix this? How can I make it so that the cells get drawn properly on the initial load?
Edit: To clarify: The cells get loaded properly but aren't drawn correctly. I have to scroll out of the first few cells and scroll back to them for the cells to be drawn right.
Any help is appreciated. Thank you!
I can see that the image you'r trying to load is of larger dimension than that of the image container view.
You can try giving clipsToBound = True to the imageView.
This would most probably resolve your issue.
Thanks.
you want to increase UITableViewCell height based on image inside it, right?
Here is tableview datasource and delegate.
extension MyDataSource: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = self.rowHeights[indexPath.row] {
return height
} else {
return 100
}
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = self.rowHeights[indexPath.row] {
return height
} else {
return 100
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mydatas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let mydata = mydatas[indexPath.row]
var cell: UITableViewCell
cell = tableView.dequeueReusableCell(withIdentifier: 'myCell.cellIdentify()')!
cell.contentView.backgroundColor = UIColor.clear
cell.backgroundColor = UIColor.clear
cell.tag = indexPath.row
cell.selectionStyle = .none
let image = UIImage(named: promotion)
(cell as! myCell).configureCell(downloadImage: image!)
let aspectRatio = (image?.size.height)!/(image?.size.width)!
let imageHeight = (cell.contentView.frame.width * aspectRatio) + 16
UIView.performWithoutAnimation {
self.myTableView?.beginUpdates()
self.rowHeights[indexPath.row] = imageHeight
self.myTableView?.endUpdates()
}
return cell
}
}
here is UITableViewCell custom class.
myCell
import UIKit
class myCell: UITableViewCell {
#IBOutlet weak var imageHolder: WMView!
#IBOutlet weak var actionImage: UIImageView!
#IBOutlet weak var loaderIndicator: UIActivityIndicatorView!
override func prepareForReuse() {
super.prepareForReuse()
self.loaderIndicator.isHidden = false
self.loaderIndicator.startAnimating()
self.actionImage.image = nil
}
static func cellHeight() -> CGFloat {
return 73.0
}
static func cellIdentify() ->String {
return "myCell"
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func configureCell(downloadImage: UIImage) {
self.imageHolder.layer.borderWidth = 1
self.imageHolder.layer.cornerRadius = 5
self.imageHolder.layer.borderColor = UIColor.clear.cgColor
self.imageHolder.layer.masksToBounds = true
self.imageHolder.clipsToBounds = true
//ImageHolder
self.actionImage.image = downloadImage
self.loaderIndicator.isHidden = true
}
}

What is the best way to make a reusable tableview for different screens in the same application?

I am working on a social ios application in swift similar to Instagram.
I have 2 screens that contain almost the same display for feeds.
The first one is a simple feeds screen that contains a tableview, the second one is the profile screen that contains a tableview header of profile info, and the tableview should contain same data of the first screen.
I was able to do that but I had to repeat the same code for tableview in both first and second screen:
(cellforRow, Number, data, and calculations...)
what is the best approach to avoid duplicating data in such a case?
You can achieve this by writing an separate tableview delegate and data source handler class which can handle the data displaying on behalf for view controller.
Handler:
import UIKit
class GenericDataSource: NSObject {
let identifier = "CellId"
var array: [Any] = []
func registerCells(forTableView tableView: UITableView) {
tableView.register(UINib(nibName: "", bundle: nil), forCellReuseIdentifier: identifier)
}
func loadCell(atIndexPath indexPath: IndexPath, forTableView tableView: UITableView) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
return cell
}
}
// UITableViewDataSource
extension GenericDataSource: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return self.loadCell(atIndexPath: indexPath, forTableView: tableView)
}
}
// UITableViewDelegate
extension GenericDataSource: UITableViewDelegate {
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
protocol GenericDataSourceDelegate: class {
// Delegate callbacks methods
}
How to use it with view controller!
class MyViewControllerA: UIViewController {
#IBOutlet weak var tableView: UITableView!
var dataSource = GenericDataSource()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self.dataSource
self.tableView.dataSource = self.dataSource
}
}
class MyViewControllerB: UIViewController {
#IBOutlet weak var tableView: UITableView!
var dataSource = GenericDataSource()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self.dataSource
self.tableView.dataSource = self.dataSource
}
}
If two tableview contain the same data, you can extract a DataSource class to manage the data, put every repeat methods in this class, such as cellForRow, numberOfRow, cellForRow.
Then at your viewContoller, just init the DataSource class and set the datasource.
self.tableViewDataSource = DataSource()
tableview.dataSource = self.tableViewDataSource
Same for UITableViewDelegate if two tableView have the same behavior.
I'd recommend implementing a UITableViewCell subclass where you can do the layout programatically or in a .xib. In the screens where you want to use those cells you call either self.tableView.registerClass(MYTableViewCell.self, forCellReuseIdentifier: "cell") if the layout is done programatically or self.tableView.registerNib(MYTableViewCell.self, forCellReuseIdentifier: "cell") if the layout is done in a .xib file.
Your class can have a configureWithData(data: SomeDataClass) function where you do all the calculations and populating the cell with the data you provide with the SomeDataClass instance.
If you need to same tableview in different view controller then Container Views is best option.
This link help for you :
Embedding TableView in TableViewController into another view
Swift table view Embedded in Container
// EventStatus Types
enum EventStatusType: String {
case ALL = "ALL"
case LIVE_NOW = "LIVE_NOW"
case HAPPENING_SOON = "HAPPENING_SOON"
case COMING_UP = "COMING_UP"
case ENDING_NOW = "ENDING_NOW"
}
class FilterTableHandler: NSObject, UITableViewDelegate,UITableViewDataSource {
public typealias FilterTableCallback = ( Int, String ) -> Void
private var callback: FilterTableCallback?
var filterListArray = [FilterCellObject]()
var table : UITableView!
override init() {
super.init()
}
func initializeFilterList() {
filterListArray.append(FilterCellObject.init(title: "Live Now" , imageName: "filterGreen", querystring: EventStatusType.LIVE_NOW.rawValue, selectionColor: UIColor(red: 0.973, green: 0.996, blue: 0.914, alpha: 1.00)))
filterListArray.append(FilterCellObject.init(title: "Happening Soon" , imageName: "filterYellow", querystring: EventStatusType.HAPPENING_SOON.rawValue, selectionColor: UIColor(red: 0.976, green: 0.925, blue: 0.902, alpha: 1.00)))
filterListArray.append(FilterCellObject.init(title: "Coming Up" , imageName: "filterOrange", querystring: EventStatusType.COMING_UP.rawValue, selectionColor: UIColor(red: 1.000, green: 0.945, blue: 0.918, alpha: 1.00)))
filterListArray.append(FilterCellObject.init(title: "All" , imageName: "", querystring: EventStatusType.ALL.rawValue, selectionColor: UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 1.00)))
}
init(tableView: UITableView,callback: #escaping FilterTableCallback) {
super.init()
initializeFilterList()
self.callback = callback
table = tableView
tableView.allowsSelection = true
tableView.separatorStyle = .none
tableView.backgroundColor = UIColor.clear
tableView.bounces = false
tableView.register(UINib(nibName: "FilterTableViewCell", bundle: nil), forCellReuseIdentifier: "FilterTableViewCell")
tableView.delegate = self
tableView.dataSource = self
table.delegate = self
table.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.filterListArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FilterTableViewCell", for: indexPath) as! FilterTableViewCell
cell.lblTitle.text = self.filterListArray[indexPath.row].title
if self.filterListArray[indexPath.row].imageName.isNotEmpty {
cell.colorImgView.image = UIImage(named:self.filterListArray[indexPath.row].imageName)
}
cell.customBackgroundView.backgroundColor = self.filterListArray[indexPath.row].backGroundSelectionColor
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
self.callback?(indexPath.row,self.filterListArray[indexPath.row].querystring)
}
}
This class handles all table view delegate and dataSource.
And returns data.
Just design TableView and create IBOutlet of that table without adding cell in the storyboard. And create your tableview cell using xib to make it reusable.
Then, in your controller use FilterTableHandler like this
var filerHandler = FilterTableHandler.init()
self.filerHandler = FilterTableHandler.init(tableView: self.filterTableView, callback: { (index,queryString) in
//Your actions on cell selection
self.hideFilterView()
self.hideInfoView()
self.getEventList(queryString: queryString)
if index != 3 {
//filter option selected
self.btnFilter?.setImage(UIImage(named:"filterFilled"), for: .normal)
}
else {
//"all" option selected
self.btnFilter?.setImage(UIImage(named:"filter"), for: .normal)
}
})
Initialize FilterTableHandler object as shown, And receive selected data using custom callbacks.
You can customize it as per your requirement.
And tableview becomes reusable for whole app.

Resizing a tableView full screen when clicked

I am working on the following :
Screenshot
Basically it's one UIImageView inside of another UIImageView at the top (60% of the screen) and a UITableView that takes 40% of the screen
and code (see below) :
What I am trying to achieve is to resize the cells of the UITableView full screen when my customCell is clicked on and unsize it to it's original state when unclicked.
Is there any way to make this work?
Thanks in advance.
//Label outlets
#IBOutlet weak var tableView: UITableView!
var selectedIndexPath : IndexPath? = nil
override func viewDidLoad() {
super.viewDidLoad()
//MARK Start of CustomViewCell Code
tableView.register(UINib(nibName: "CustomViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! CustomViewCell
cell.clipsToBounds = true
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let index = indexPath
if selectedIndexPath != nil {
if index == selectedIndexPath {
return 667
} else {
return 62
}
} else {
return 62}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch selectedIndexPath {
case nil:
selectedIndexPath = indexPath
default:
if selectedIndexPath! == indexPath {
selectedIndexPath = nil
} else {
selectedIndexPath = indexPath
}
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
//MARK End of CustomViewCell Code
Besides reloading the cells with the new heights, you also need to change the frame of the table view. If you want to make the table occupy the whole screen, make sure you create an IBOutlet for it, say myTableView, then, after:
tableView.reloadRows(at: [indexPath], with: .automatic)
Add this code:
myTableView.frame = view.bounds
You may also create a Bool variable to keep track of normal and full-screen modes of the table view, and some CGRect variable to keep the initial frame. You may need something like this when you want the table view to go back to its initial frame:
myTableView.frame = initialTableViewFrame
Hope you get the idea.
Here is a pure auto-layout approach:
1.In your interface builder, create a UIImageView with constraints [Trailing, Leading, Top , Bottom, Height], make the height >= and priority is 999. You will use this height later in code for the expand/collapse logic.
2.Create a dummy UIView whose height will be programmatically set later, this UIView will 'push' / 'stretch' your cell height when you create the expand effect to your imageview. Set it's visibility to hidden since you don't need to show this to your user.
3.In your custom cell, create two NSLayoutConstraint instances as #IBoutlets, one for UIImageView height and one for the dummy UIView height then connect them later in your interface file.
let lowPriorityHeight : Float = 250;
let highPriorityHeight : Float = 999;
class CustomCell: UITableViewCell {
#IBOutlet weak var imgVwHeight: NSLayoutConstraint!
#IBOutlet weak var tempHeight : NSLayoutConstraint!
var isExpanded = false{
didSet{
imgVwHeight.priority = (isExpanded) ? lowPriorityHeight : highPriorityHeight;
if isExpanded == true{
tempHeight.constant = ExpandedHeight
}else{
tempHeight.constant = NormalHeight
}
}
}
4.In your main class, set the isExpanded to true or false to create the effect.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! CustomCell
cell.isExpanded = !cell.isExpanded
tableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : CustomCell = tableView.dequeueReusableCell(withIdentifier: "kCustomCell", for: indexPath) as! CustomCell
return cell
}
You may download my sample implementation HERE

how to expand or replace the cell with another cell, when an particular cell select in table view

I have already asked this doubt/problem in SO. but not get get solution. Please help me out....
i have one table view which will show the list of name data till 10 datas. But what i need is , when user press any cell, that cell should be replace with another cell, which have some image, phone number, same data name. How to do that.
I have two xib : 1. normalcell, 2. expandable/replace cell
Here is my viewconrolelr.swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var Resultcount: UILabel!
var tableData = ["thomas", "Alva", "Edition", "sath", "mallko", "techno park",... till 10 data]
let cellSpacingHeight: CGFloat = 5
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var nib = UINib(nibName:"customCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
Resultcount.text = "\(tableData.count) Results"
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.tableData.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return cellSpacingHeight
}
// Make the background color show through
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.clearColor()
return headerView
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:customCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! customCell
cell.vendorName.text = tableData[indexPath.section]
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Starting my cell will look like this :
When i press that cell, i need some thing to do like this with replace ment of like below cell :
But when i press same cell again, again it should go to normal cell.
How to do that ??
First modify your tableView:cellForRowAtIndexPath: implementation as follows. Then you need to implement the click handler. One way would be in the MyCell class. Another would be to override selectRowAtIndexPath. Without knowing more about what you want (e.g. multiple vs single selection), it's hard to give actual code but here's something.
BOOL clickedRows[MAX_ROWS]; // Init this array as all false in your init method. It would be better to use NSMutableArray or something similar...
// selectRowAtIndexPath code
int row = indexPath.row
if(clickedRows[row]) clickedRows[row]=NO; // we reverse the selection for the row
else clickedRows[row]=YES;
[self.tableView reloadData];
// cellForRowAt... code
MyCell *cell = [tableView dequeueResuableCell...
if(cell.clicked) { // Nice Nib
[tableView registerNib:[UINib nibWithNibName... for CellReuse...
} else { // Grey Nib
[tableView registerNib:[UINib nibWithNibName... for CellReuse...
}
You need to create two independent cell on xib. Then you can load using check.You can copy and paste it will work perfectly.
in cellForRowAt like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if selectedIndexPath == indexPath && self.isExpand == true{
let cell = tableView.dequeueReusableCell(withIdentifier: "LeaveBalanceExpandedCell", for: indexPath) as! LeaveBalanceExpandedCell
cell.delegate = self
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "LeaveBalanceNormalCell", for: indexPath) as! LeaveBalanceNormalCell
return cell
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// cell.animateCell(cell)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedIndexPath == indexPath{
if isExpand == true{
self.isExpand = false
}
else{
self.isExpand = true
}
}
else{
selectedIndexPath = indexPath
self.isExpand = true
}
self.tableView.reloadData()
}

Resources