I have 3 sections and their corresponding cells how to make it expand/collapse? I have created an struct having expanded:Bool value
below are my code.
*THIS IS MY cellForRowAt *
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch (indexPath.section) {
case 0:
if let cell1 = tableview.dequeueReusableCell(withIdentifier: "TimeCardDetailedTableViewCell", for: indexPath) as? TimeCardDetailedTableViewCell{
return cell1
}
case 1:
if let cell2 = tableview.dequeueReusableCell(withIdentifier: "MessageDetailedTableViewCell", for: indexPath) as? MessageDetailedTableViewCell{
return cell2
}
case 2:
if let cell3 = tableview.dequeueReusableCell(withIdentifier: "CrewDetailedTableViewCell", for: indexPath) as? CrewDetailedTableViewCell{
return cell3
}
default:
return UITableViewCell()
}
return UITableViewCell()
}
--->>this is numberOfRowsInSection
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch (section) {
case 0:
return self.timecards.count
case 1:
return self.msglog.count
default:
return self.profile.count
}
}
--->>> viewForHeaderInSection
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0{
let header1 = Bundle.main.loadNibNamed("TimeCardHeaderTableViewCell", owner: self, options: nil)?.last as! TimeCardHeaderTableViewCell
header1.backgroundColor = .red
return header1
} else if section == 1 {
let header2 = Bundle.main.loadNibNamed("MessageTableViewCell", owner: self, options: nil)?.last as! MessageTableViewCell
return header2
} else if section == 2 {
let header3 = Bundle.main.loadNibNamed("CrewTableViewCell", owner: self, options: nil)?.last as! CrewTableViewCell
return header3
}
return UITableViewCell()
}
How to implement expansion on section.im new to iOS
One approach is to update your numberOfRowsInSection like this
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch (section) {
case 0: return self.hiddenSections.contains(0) ? 0 : self.timecards.count
case 1: return self.hiddenSections.contains(1) ? 0 : return self.msglog.count
case 2: return self.hiddenSections.contains(2) ? 0 : return self.profile.count
}
}
viewForHeaderInSection will be like this, where you will set tag and selector.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionButton = UIButton()
sectionButton.setTitle(String(section),
for: .normal)
sectionButton.backgroundColor = .systemBlue
sectionButton.tag = section
sectionButton.addTarget(self,
action: #selector(self.hideSection(sender:)),
for: .touchUpInside)
return sectionButton
}
hideSection method will have logic to hide/show your section
#objc
private func hideSection(sender: UIButton) {
let section = sender.tag
func indexPathsForSection() -> [IndexPath] {
var indexPaths = [IndexPath]()
for row in 0..<self.tableViewData[section].count {
indexPaths.append(IndexPath(row: row,
section: section))
}
return indexPaths
}
if self.hiddenSections.contains(section) {
self.hiddenSections.remove(section)
self.tableView.insertRows(at: indexPathsForSection(),
with: .fade)
} else {
self.hiddenSections.insert(section)
self.tableView.deleteRows(at: indexPathsForSection(),
with: .fade)
}
}
Related
I have to show tableview with two sections based on flag value. Based on flag value I have to show/hide first section.
First section has only one row and static customised cell which will show always same data.
And second section is another customised cell, Which is dynamic rows shows from server data.
I need to show Second section is always. First section based on flag I have to show or hide.
How to handle this?
Here is my code
override func viewDidLoad() {
super.viewDidLoad()
self.registerCells()
}
func registerCells(){
self.DetailsTableview.register(RadioButtonTableViewCell.nib, forCellReuseIdentifier: RadioButtonTableViewCell.identifier)
if flagValue == true {
self.DetailsTableview.register(UPPercentageCell.nib, forCellReuseIdentifier: PercentageCell.identifier)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if flagValue == true {
return 2
}
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if flagValue == true {
return 20
}
return 40
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if flagValue == true {
if section == 0 {
return 1
} else {
return self.response?.data?.count ?? 0
}
}
return self.response?.data?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if flagValue == true {
if indexPath.section == 0 {
let percentagecell: PercentageCell = tableView.dequeueReusableCell(withIdentifier: "PercentageCell", for: indexPath) as! UPPercentageCell
percentagecell.percentage = "20" //some dynamic value
percentagecell.isUserInteractionEnabled = false
return percentagecell
} else {
let cell: RadioButtonTableViewCell = tableView.dequeueReusableCell(withIdentifier: "RadioButtonTableViewCell", for: indexPath) as! RadioButtonTableViewCell
cell.displayDataToUI(title: response?.data?[indexPath.row] ?? "", currentIndexpath: indexPath, selectedIndexpath: selectedIndexpath ?? IndexPath())
cell.radioButtonClicked = {
[weak self] (indexpath) in
self?.saveButton.isUserInteractionEnabled = true
self?.reloadTableviewFromSelectedIndexpath(indexpath: indexpath)
}
return cell
}
} else {
let cell: RadioButtonTableViewCell = tableView.dequeueReusableCell(withIdentifier: "RadioButtonTableViewCell", for: indexPath) as! RadioButtonTableViewCell
cell.displayDataToUI(title: response?.data?[indexPath.row] ?? "", currentIndexpath: indexPath, selectedIndexpath: selectedIndexpath ?? IndexPath())
cell.radioButtonClicked = {
[weak self] (indexpath) in
self?.saveButton.isUserInteractionEnabled = true
self?.reloadTableviewFromSelectedIndexpath(indexpath: indexpath)
}
return cell
}
return UITableViewCell()
}
Is there any better approach to achieve this?
Highly appreciate your valuable suggestions.
Your approach is fine, but you can simplify things a bit with fewer if/else blocks...
First:
func registerCells(){
self.DetailsTableview.register(RadioButtonTableViewCell.nib, forCellReuseIdentifier: RadioButtonTableViewCell.identifier)
// doesn't hurt to go ahead and register both cell classes for reuse
self.DetailsTableview.register(UPPercentageCell.nib, forCellReuseIdentifier: PercentageCell.identifier)
}
next, just a more compact way of writing it:
override func numberOfSections(in tableView: UITableView) -> Int {
return flagValue ? 2 : 1
}
and:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// this will only be true if
// section is 0
// AND
// flagValue is true
if section == 0 && flagValue {
return 1
}
// whether we're in section 0 WITHOUT the "top" section, or
// we're in section 1 WITH the "top" section
return self.response?.data?.count ?? 0
}
and:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// this will only be true if
// section is 0
// AND
// flagValue is true
if indexPath.section == 0 && flagValue {
let cell = tableView.dequeueReusableCell(withIdentifier: UPPercentageCell.identifier, for: indexPath) as! UPPercentageCell
cell.percentage = "20" //some dynamic value
cell.isUserInteractionEnabled = false
return cell
}
// we want to display the same cells from the same data array
// whether we're in section 0 WITHOUT the "top" section, or
// we're in section 1 WITH the "top" section
let cell = tableView.dequeueReusableCell(withIdentifier: RadioButtonTableViewCell.identifier, for: indexPath) as! RadioButtonTableViewCell
cell.displayDataToUI(title: response?.data?[indexPath.row] ?? "", currentIndexpath: indexPath, selectedIndexpath: selectedIndexpath ?? IndexPath())
cell.radioButtonClicked = {
[weak self] (indexpath) in
self?.saveButton.isUserInteractionEnabled = true
self?.reloadTableviewFromSelectedIndexpath(indexpath: indexpath)
}
return cell
}
I have three sections, the first one stores the user's information , the second one contains the field for adding posts, and the third one is posts.
And when scrolling, I start to load the section with the addition of posts and the user information section in the posts section
This is my code
UIViewController extension UITableViewDataSource :
func numberOfSections(in tableView: UITableView) -> Int {
presenter?.numberOfSections() ?? 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let section = UserPageTypeSection(rawValue: section) else { return 0 }
return presenter?.numberOfRowsInSection(section: section) ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let section = UserPageTypeSection(rawValue: indexPath.section),
let userInfo = presenter?.cellForRowAt(section: section, indexRow: indexPath.row)
else { return UITableViewCell() }
switch userInfo.type {
case .userInfo:
guard let cell = tableView.dequeueReusableCell(withIdentifier: ProfileInfoTableViewCell.reuseIdentifier, for: indexPath) as? ProfileInfoTableViewCell else { return UITableViewCell() }
cell.userInformation(userData: userInfo.data?[indexPath.row] as? UserProfile)
return cell
case .userAddPost:
guard let cell = tableView.dequeueReusableCell(withIdentifier: ProfileInfoTableViewCell.reuseIdentifier, for: indexPath) as? ProfileInfoTableViewCell else { return UITableViewCell() }
cell.addPostUser()
return cell
case .userPost:
guard let cell = tableView.dequeueReusableCell(withIdentifier: ProfileInfoTableViewCell.reuseIdentifier, for: indexPath) as? ProfileInfoTableViewCell else { return UITableViewCell() }
cell.post(text: "POST")
return cell
default:
return UITableViewCell()
}
I have one UITableView and it has also header section. Based on header section they have correspondent data.
Each header section have one button which is clickable as user will
click on it it will expend the UITableView
I am using below code for it
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = Bundle.main.loadNibNamed("DashTableViewCell", owner: self, options: nil)?.first as! DashTableViewCell
headerCell.lblQueryType.text = queriesArray[section]
headerCell.btnExpendable.addTarget(self, action: #selector(expendSection), for: .touchUpInside)
headerCell.btnExpendable.tag = section
return headerCell
}
#objc func expendSection(button: UIButton) {
var indexPaths = [IndexPath]()
let section = button.tag
if button.tag == 0 {
QueriesStructArray[section].isExpended = !QueriesStructArray[section].isExpended
for row in QueriesStructArray.indices {
let indexPath = IndexPath(row: row, section: section)
indexPaths.append(indexPath)
}
} else if button.tag == 1 {
MyQueriesStructArray[section].isExpended = !MyQueriesStructArray[section].isExpended
for row in MyQueriesStructArray.indices {
let indexPath = IndexPath(row: row, section: section)
indexPaths.append(indexPath)
}
}
if button.tag == 1 {
if MyQueriesStructArray[section].isExpended == true {
tblProjectDashBoard.deleteRows(at: indexPaths, with: .fade)
} else {
tblProjectDashBoard.insertRows(at: indexPaths, with: .fade)
}
}
else if button.tag == 0 {
if QueriesStructArray[section].isExpended == true {
tblProjectDashBoard.deleteRows(at: indexPaths, with: .fade)
} else {
tblProjectDashBoard.insertRows(at: indexPaths, with: .fade)
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return queriesArray.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
if QueriesStructArray[section].isExpended == true {
return 0
}
return QueriesStructArray.count
} else if section == 1 {
if MyQueriesStructArray[section].isExpended == true {
return 0
} else {
return MyQueriesStructArray.count
}
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "ProjectDashTableViewCell", for: indexPath) as? ProjectDashTableViewCell {
if indexPath.section == 0 {
cell.lblTitle.text = QueriesStructArray[indexPath.row].queries
return cell
} else if indexPath.section == 1 {
cell.lblTitle.text = MyQueriesStructArray[indexPath.row].myQueries
return cell
}
}
return UITableViewCell()
}
every thing is working fine but as I clicked on "Shared Queries"
button then "My Queries" section got hide which is wrong I am unable
to find the issue in code
This is the screen shot. According to this how to list the data in the tableview:
Already I have code as below.
func numberOfSections(in tableView: UITableView) -> Int {
return questionViewModel.numberOfSections()
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100
} func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let identifier = "HeaderCell"
var headercell: questionheader! = tableView.dequeueReusableCell(withIdentifier: identifier) as? questionheader
if headercell == nil {
tableView.register(UINib(nibName: "questionheader", bundle: nil), forCellReuseIdentifier: identifier)
headercell = tableView.dequeueReusableCell(withIdentifier: identifier) as? NH_questionheader
} headercell.setReviewData(reviews:questionViewModel.titleForHeaderInSection(atsection:section))
headercell.isUserInteractionEnabled = false
return headercell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questionViewModel.numberOfRowsIn(section: section)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let model = questionViewModel.titleForHeaderInSection(atsection: indexPath.section)
print(model.answerType)
print(model.answerType?.rawValue)
let c = model.answerType
return c!.cellType().getHeight()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let model = questionViewModel.titleForHeaderInSection(atsection: indexPath.section)
print(model.answerType)
print(model.answerType?.rawValue)
let c = model.answerType
let cellClass = c?.cellType().getClass()
print(cellClass)
let cell = tableView.dequeueReusableCell(withIdentifier: (cellClass?.cellReuseIdentifier())!, for: indexPath) as! BaseCell
print(cell)
cell.selectionStyle = .none
let optionModel = questionViewModel.datafordisplay(atindex: indexPath)
cell.setOptions(Options1: optionModel)
cell.delegate = self
if optionModel.isSelected!
{
print(optionModel.isSelected)
cell.setOptions1(OptionsSelected:optionModel)
}
else {
print(optionModel.isSelected)
cell.setOptions1(OptionsisSelected:optionModel)
}
cell.type = c?.cellType()
print(cell.type)
else if cell.type == .radiotype{
cell.selectionStyle = .none
}
return cell
}
This is my code. But according to this I will get the output as below screen shot.
Actually initially I need to display the section header as: - Please tell about us
After that there is subsection. The subsection questions header are as below: -1. knowledge 2. friendly or not
Then in the subsections display the options. How to do implement?
You can just display "Please tell us about" as UILabel above the table.
Below example may help you out.
let sections = [ // All sections
[ // Sports section
["Baseball", "Softball", "Cricket"], // Bat-and-Ball sub-section
["Field Hockey", "Ice Hockey", "Roller Hockey"] // Hockey subsection
], [ // Engineering section
["Software Engineer", "Electrical Engineer"] // Computer Science subsection
]
]
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionItems = sections[section]
var numberOfRows: Int = sectionItems.count // For second level section headers
for rowItems: [Any] in sectionItems as? [[Any]] ?? [] {
numberOfRows += rowItems.count // For actual table rows
}
return numberOfRows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var sectionItems = sections[indexPath.section]
var sectionHeaders = self.sectionHeaders[indexPath.section]
let itemAndSubsectionIndex: IndexPath? = computeItemAndSubsectionIndex(for: indexPath)
let subsectionIndex = Int(itemAndSubsectionIndex?.section ?? 0)
let itemIndex: Int? = itemAndSubsectionIndex?.row
if (itemIndex ?? 0) < 0 {
// Section header
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "SECTION_HEADER_CELL", for: indexPath)
cell.textLabel?.text = sectionHeaders[subsectionIndex] as? String
return cell
}
else{
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "ROW_CONTENT_CELL", for: indexPath)
cell.textLabel?.text = sectionItems[subsectionIndex][itemIndex ?? 0] as? String
return cell
}
}
func computeItemAndSubsectionIndex(for indexPath: IndexPath?) -> IndexPath? {
var sectionItems = sections[Int(indexPath?.section ?? 0)]
var itemIndex: Int? = indexPath?.row
var subsectionIndex: Int = 0
for i in 0..<sectionItems.count {
// First row for each section item is header
itemIndex = (itemIndex ?? 0) - 1
// Check if the item index is within this subsection's items
let subsectionItems = sectionItems[i] as? [Any]
if (itemIndex ?? 0) < Int(subsectionItems?.count ?? 0) {
subsectionIndex = i
break
} else {
itemIndex = itemIndex! - (subsectionItems?.count)!
}
}
return IndexPath(row: itemIndex ?? 0, section: subsectionIndex)
}
And for objective-C Help you may following URL
http://sapandiwakar.in/nested-sections-in-uitableview/
I have a tableview with custom headers. and the uitableview row cells have refresh button that will call an API and reload the sender cell. However, whenever a refresh is done, the section headers disappear.
extension AccountViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
} else {
return platforms.count - 1
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "BalanceHeaderCell") as? BalanceHeaderCell
if self.currentUser != nil {
self.saveUserDefault(item: currentUser?.balance ?? "", key: Account.accountBalanceRecord)
cell?.headerRefreshButton.tag = section
cell?.headerRefreshButton.addTarget(self, action: #selector(refreshAccountBalanceInfo), for: UIControlEvents.touchUpInside)
cell?.set(user: self.currentUser!)
}
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PlatformHeaderCell") as? PlatformHeaderCell
return cell
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "BankCardsCell", for: indexPath) as? BankCardsCell
cell?.setCell(bankCount: self.bankCount)
return cell!
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PlatformListCell", for: indexPath) as? PlatformListCell
cell?.set(platforms: platforms[indexPath.row])
cell?.platformRefreshButton.tag = indexPath.row
cell?.platformRefreshButton.addTarget(self, action: #selector(refreshPlatformBalanceInfo), for: UIControlEvents.touchUpInside)
return cell!
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return 73
} else {
return 40
}
}
What are your suggestions?