How to reload selected cell in particular section for expand/collapse in tableview Swift
If you store section and row independently in separate arrays, your algorithm will fail.
The reason is that both are dependent:
Think of three expanded cells (row:1, section:1), (row:2, section:1), (row:3, section:2)
Now what happens for the cell (row:3, section:1)?
The row-array contains the value "3", and the section-array contains value "1", therefore it will be considered as expanded.
Therefore, you need to store the index path as a whole - see the sample code:
var expanded:[IndexPath] = []
expanded.append(IndexPath(row:1, section:1))
expanded.append(IndexPath(row:2, section:1))
expanded.append(IndexPath(row:3, section:2))
let checkPath = IndexPath(row:3, section:1)
if (expanded.contains(checkPath)) {
print ("is expanded")
} else {
print ("collapsed")
}
Update
So in your button handle, you'll do the following:
@IBAction moreButtonTapped(_ sender: Any) {
if(expanded.contains(indexPath)) {
expanded.removeAll { (checkPath) -> Bool in
return checkPath == indexPath
}
} else {
expanded.append(indexPath)
}
entriesTableView.beginUpdates()
entriesTableView.reloadRows(at: [indexPath], with: .none)
entriesTableView.endUpdates()
}
Expandable Sections UITableView IndexPath SWIFT
I don't know why you need sections to do it what you want, you can achieve with normal cells, no need to complicate at all. Just differentiating the parent cells of the child cells is all you need.
I have a repository in Github that achieve what you want, without using sections neither UITapGestureRecognizer
. As soon as possible I'll try to update the project to better performance and more levels of depth in the dropdown.
You can reach it AccordionMenu
, and feel free to post anything you need as issue.
I hope this help you.
Swift 5 UITableViewCell : Expand one section and collapse the expanded section
do this in didselecterow method. This is the else
case of your condition
// You will need to reload multiple sections. So make an array.
var reloadSections = [Int]()
// find already opened array
if let alreadyOpenSection = supportArray.firstIndex(where: { (faq) -> Bool in
return faq.openSection
}) {
// if found, toggle the openSections bit
supportArray[alreadyOpenSection].openSection = false
// add it to reload sections array
reloadSections.append(alreadyOpenSection)
}
supportArray[indexPath.section].openSection = true
reloadSections.append(indexPath.section)
// create index set with reload sections array
let sections = IndexSet.init(reloadSections)
tableView.reloadSections(sections, with: .fade)
// below code is same
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = UIColor(hexString: "#D71B61")
cell.imageButton.tintColor = .white
cell.imageText.textColor = .white
}
}
Swift expandable table view header for sections problem
I am not deep dive in your code but I copy-paste into an Xcode project to look into. So there is basic way to solve your problem, I hope it helps to you.
I assume your class is like that.
class Adres{
var title: String = ""
var isExpanded: Bool = true
init(title: String, isExpanded: Bool){
self.title = title
self.isExpanded = isExpanded
}
}
And in there mainly 2 different variable for adresDict
& adresDictForTeslim
.
So I keep an lock array to doing logic stuff of expandable.
var keys: [Int] = [1,1]
<1> Show
<0> Hide
Now, the arrays elements are showing into UITableView, because its expanded.
There's mock data.
var userAdressDict = [Adres(title: "First Adres", isExpanded: true) ,Adres(title: "Second Adres", isExpanded: true)]
var userAdressDictForTeslim = [Adres(title: "First Teslim", isExpanded: true),Adres(title: "Second Teslim", isExpanded: true)]
viewForHeaderInSection
is same as well.
And for numberOfRowsInSection
check array for key that if its expanded or not.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
if self.keys[0] == 1 {
return userAdressDict.count
}else{
return 0
}
}else{
if self.keys[1] == 1 {
return userAdressDictForTeslim.count
}else{
return 0
}
}
}
Then check these keys in handler functions.
@objc func handleExpandCloseForAlim(sender: UIButton) {
if keys[0] == 0 {
keys[0] = 1
}else{
keys[0] = 0
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
If first array elements in table view is expanded close it, or not expand it.
Then in another function.
@objc func handleExpandCloseForTeslim(sender: UIButton) {
if keys[1] == 0 {
keys[1] = 1
}else{
keys[1] = 0
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
So far so good. It's working on my simulator.
Then there's more efficient way to handle keys of expanded.
Make your UIButton's
of the sectionHeader as public variable in your ViewController
and control it if it's title is "Kapat"
and clicked then it must be "Aç"
or if its "Aç"
and touched it must be "Kapat"
.
Expanding tableview sections on clicking each section
Add an array to keep track of section expend/collapse
let sectionStats = [Bool](repeating: true, count: 2)
Add a, IBAction to track section tap, update value of sectionStats
for the corresponding section and reload section
and update your numberOfRowsInSection
as show below
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard sectionStats[section] else {
return 0
}
if section == 0 {
return 1
} else {
return list.count
}
}
Tappable Header:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return headerView(section: section, title: section == 0 ? "CHAT LIST" : "GROUPS")
}
private func headerView(section: Int, title: String) -> UIView {
let button = UIButton(frame: CGRect.zero)
button.tag = section
button.setTitle(title, for: .normal)
button.setTitleColor(UIColor.red, for: .normal)
button.addTarget(self, action: #selector(sectionHeaderTapped), for: .touchUpInside)
return button
}
@objc private func sectionHeaderTapped(sender: UIButton) {
let section = sender.tag
sectionStats[section] = !sectionStats[section]
tableView.beginUpdates()
tableView.reloadSections([section], with: .automatic)
tableView.endUpdates()
}
Good tutorial on How to build a Table View with Collapsible Sections:
https://medium.com/ios-os-x-development/ios-how-to-build-a-table-view-with-collapsible-sections-96badf3387d0
Expand/collapse section in UITableView in iOS
You have to make your own custom header row and put that as the first row of each section. Subclassing the UITableView
or the headers that are already there will be a pain. Based on the way they work now, I am not sure you can easily get actions out of them. You could set up a cell to LOOK like a header, and setup the tableView:didSelectRowAtIndexPath
to manually expand or collapse the section it is in.
I'd store an array of booleans corresponding the the "expended" value of each of your sections. Then you could 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];
}
}
Then set numberOfRowsInSection
to check the mybooleans
value and return 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;
}
}
Also, you will need to update cellForRowAtIndexPath
to return a custom header cell for the first row in any section.
How to make Expandable with only Cells (NOT SECTION/ HEADER) with UITableView in Swift?
You can add a Bool "expanded" property to your Object.
In numberOfRowsInSection
, if expanded is True, return the count of items in seactionObjection
, else return 1
.
Then, in didSelectRowAt
, if it's the first row in a section, toggle the expanded
property of that section's Object, and reload the section.
Here's a modified version of your controller class:
class HelpViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
struct Object {
var seactionName: String!
var expanded: Bool!
var seactionObjection: [String]!
var footerName: String!
}
var objectArray = [Object]()
var TableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
objectArray = [
Object(seactionName: "Header 1",
expanded: false,
seactionObjection: ["Expandable Cell 1", "One Row 1", "Two Row 1"],
footerName: "Footer 1"),
Object(seactionName: "Header 2",
expanded: false,
seactionObjection: ["Expandable Cell 2", "One Row 2", "Two Row 2"],
footerName: "Footer 2"),
Object(seactionName: "Header 3",
expanded: false,
seactionObjection: ["Expandable Cell 3", "One Row 3", "Two Row 3"],
footerName: "Footer 3"),
// copy and paste new cells
]
title = "Help Center"
view.backgroundColor = UIColor.quaternarySystemFill
TableView.frame = view.bounds
TableView = UITableView(frame: self.view.bounds, style: UITableView.Style.insetGrouped)
TableView.showsVerticalScrollIndicator = true
TableView.indicatorStyle = .default
TableView.register(SliceCell.self, forCellReuseIdentifier: "Slice List")
TableView.delegate = self
TableView.dataSource = self
view.addSubview(TableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// if section is expanded
// return count of seactionObjection
// else
// return 1
return objectArray[section].expanded ? objectArray[section].seactionObjection.count : 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return objectArray.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return objectArray[section].seactionName
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return objectArray[section].footerName
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Slice List") as! SliceCell
cell.backgroundColor = .secondarySystemGroupedBackground
cell.textLabel?.text = objectArray[indexPath.section].seactionObjection[indexPath.row]
cell.textLabel?.numberOfLines = 0
// if it's the first row in a section,
// show accessoryView with
// chevron.up or chevron.down
// based on section Object expanded property
if indexPath.row == 0 {
let chevronName = objectArray[indexPath.section].expanded ? "chevron.up" : "chevron.down"
let img = UIImage(systemName: chevronName)
let disclosureView = UIImageView(image: img)
cell.accessoryView = disclosureView
} else {
// not the first row in a section, so
// clear the accessoryView
cell.accessoryView = nil
}
return cell
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
view.tintColor = .clear
let header = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = UIColor.label
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
objectArray[indexPath.section].expanded.toggle()
tableView.reloadSections([indexPath.section], with: .automatic)
} else {
// do something else on row selection
}
}
}
Related Topics
Implicitly Lazy Static Members in Swift
Set a Default Value for Uipickerview in Swift
Core Data: Failed to Load Model
Swift: How to Call Cckeyderivationpbkdf from Swift
How to Line Break Long Large Title in iOS 11
Can't Understand How Collision Bit Mask Works
How to Convert a String to a Cstring in the Swift Language
How to Create Nsradiobutton Group in Xcode 7 Osx
Swiftui: How to Implement a Custom Init With @Binding Variables
Swift: How to Delete Part of Audio
Today Extension Failed to Inherit Coremedia Permissions From
Prefer Large Titles and Refreshcontrol Not Working Well
Trouble Left-Aligning Uibutton Title (Ios/Swift)
Differencebetween Swift 2.0 Do-Try-Catch and Regular Java/C#/C++ Exceptions
Swift Closures Causing Strong Retain Cycle with Self
How to Execute Code Once and Only Once in Swift
Why How to Use Codable with a Project Language Version of Swift 3.3