How to Create this type of tableview in iOS??
Here, If we tap on 1st row 'Account', then automatically it scrolled with some more rows which is showing in Image. And if again we tap on Account, then that view will be hidden.
There are two main base ways to populate a tableview. The more popular is through Interface Building, using a prototype cell UI object. The other is strictly through code when you don't need a prototype cell from Interface Builder.
Swift version: 5.6. Index paths describe an item's position inside a table view or collection view, storing both its section and its position inside that section.
You could easily set up a cell to LOOK like a header, and setup the tableView: didSelectRowAtIndexPath
to expand or collapse the section it is within manually. If I'd store an array of booleans corresponding the the "expended" value of each of your sections. You could then have the tableView:didSelectRowAtIndexPath
on each of your custom header rows toggle this value and then reload that specific section.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { ///it's the first row of any section so it would be your custom section header ///put in your code to toggle your boolean value here mybooleans[indexPath.section] = !mybooleans[indexPath.section]; ///reload this section [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade]; } }
You'd then setup your number numberOfRowsInSection
to check the mybooleans
value and return either 1 if the section isn't expanded, or 1+ the number of items in the section, if it is expanded.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (mybooleans[section]) { ///we want the number of people plus the header cell return [self numberOfPeopleInGroup:section] + 1; } else { ///we just want the header cell return 1; } }
You would also have to update your cellForRowAtIndexPath
to return a custom header cell for the first row in any section
.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
is the better way to provide your "own custom header", as that's exactly what it's designed to do.
For more details, Refer this Answer or this PKCollapsingTableViewSections.
Also, You can get this type of tableviews using setIndentationLevel
. Please refer this DemoCode for this example. I think this the best solution for Drop-Down tableviews.
If you want to make a simple header and cell drop down, then please refer STCollapseTableView.
Hope, this is what you're looking for. Any concern get back to me. :)
The easier and most natural way to implement this if via table view cells. No expanding cell views, no section headers, plain and simply cells (we're in a table view after all).
The design is as following:
CollapsableViewModel
class that holds the information needed to configure the cell: label, imagechildren
, which is an array of CollapsableViewModel
objects, and isCollapsed
, which holds the state of the drop downCollapsableViewModel
, as well as a flat list containing the view models that will be rendered on the screen (the displayedRows
property)displayedRows
and in the table view, via the insertRowsAtIndexPaths()
and deleteRowsAtIndexPaths()
functions.The Swift code is as following (note that the code makes use only of the label
property of the view model, to keep it clean):
import UIKit class CollapsableViewModel { let label: String let image: UIImage? let children: [CollapsableViewModel] var isCollapsed: Bool init(label: String, image: UIImage? = nil, children: [CollapsableViewModel] = [], isCollapsed: Bool = true) { self.label = label self.image = image self.children = children self.isCollapsed = isCollapsed } } class CollapsableTableViewController: UITableViewController { let data = [ CollapsableViewModel(label: "Account", image: nil, children: [ CollapsableViewModel(label: "Profile"), CollapsableViewModel(label: "Activate account"), CollapsableViewModel(label: "Change password")]), CollapsableViewModel(label: "Group"), CollapsableViewModel(label: "Events", image: nil, children: [ CollapsableViewModel(label: "Nearby"), CollapsableViewModel(label: "Global"), ]), CollapsableViewModel(label: "Deals"), ] var displayedRows: [CollapsableViewModel] = [] override func viewDidLoad() { super.viewDidLoad() displayedRows = data } override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return displayedRows.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier") ?? UITableViewCell() let viewModel = displayedRows[indexPath.row] cell.textLabel!.text = viewModel.label return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: false) let viewModel = displayedRows[indexPath.row] if viewModel.children.count > 0 { let range = indexPath.row+1...indexPath.row+viewModel.children.count let indexPaths = range.map { IndexPath(row: $0, section: indexPath.section) } tableView.beginUpdates() if viewModel.isCollapsed { displayedRows.insert(contentsOf: viewModel.children, at: indexPath.row + 1) tableView.insertRows(at: indexPaths, with: .automatic) } else { displayedRows.removeSubrange(range) tableView.deleteRows(at: indexPaths, with: .automatic) } tableView.endUpdates() } viewModel.isCollapsed = !viewModel.isCollapsed } }
The Objective-C counterpart is easy to translate, I added the Swift version only as it's shorter and more readable.
With a couple of small changes, the code can be used to generate drop down lists of multiple levels.
People asked me about the separators, this can be achieved by adding a custom class CollapsibleTableViewCell
which get's configured with a view model (finally, move the cell configuration logic from the controller to where it belongs - the cell). Credits for the separator logic only for some of the cells go to people answering this SO question.
Firstly, update the model, add a needsSeparator
property that tells the table view cell to render or not the separator:
class CollapsableViewModel { let label: String let image: UIImage? let children: [CollapsableViewModel] var isCollapsed: Bool var needsSeparator: Bool = true init(label: String, image: UIImage? = nil, children: [CollapsableViewModel] = [], isCollapsed: Bool = true) { self.label = label self.image = image self.children = children self.isCollapsed = isCollapsed for child in self.children { child.needsSeparator = false } self.children.last?.needsSeparator = true } }
Then, add the cell class:
class CollapsibleTableViewCell: UITableViewCell { let separator = UIView(frame: .zero) func configure(withViewModel viewModel: CollapsableViewModel) { self.textLabel?.text = viewModel.label if(viewModel.needsSeparator) { separator.backgroundColor = .gray contentView.addSubview(separator) } else { separator.removeFromSuperview() } } override func layoutSubviews() { super.layoutSubviews() let separatorHeight = 1 / UIScreen.main.scale separator.frame = CGRect(x: separatorInset.left, y: contentView.bounds.height - separatorHeight, width: contentView.bounds.width-separatorInset.left-separatorInset.right, height: separatorHeight) } }
cellForRowAtIndexPath
would then need to be modified to return this kind of cells:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = (tableView.dequeueReusableCell(withIdentifier: "CollapsibleTableViewCell") as? CollapsibleTableViewCell) ?? CollapsibleTableViewCell(style: .default, reuseIdentifier: "CollapsibleTableViewCell") cell.configure(withViewModel: displayedRows[indexPath.row]) return cell }
One last step, remove the default table view cell separators - either from xib or from code (tableView.separatorStyle = .none
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With