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()
}
Related
I have two sections in a table view that contains data. When clicking on section 2's delete button it removes all content from the table view. I'm using the table view header for section separation.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: DiagnosisTVHeaderCell.self)) as? DiagnosisTVHeaderCell else {return UITableViewCell()}
cell.delegate = self
cell.selectionStyle = .none
return cell
} else if section == 1 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: EMRAttachmentsCell.self)) as? EMRAttachmentsCell else {return UITableViewCell()}
cell.selectionStyle = .none
cell.delegate = self
return cell
}
return UIView()
}
func deleteTableCell(index: Int) {
if attachmentTypeDiagnosis.isEmpty == false {
attachmentTypeDiagnosis.remove(at: index)
attachmattachmentInfoDiagnosis.remove(at: index)
tableviewDiagnosis.deleteRows(at: [IndexPath(row: index, section: 1)], with: .left)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: DiagnosisListingTVCell.self)) as? DiagnosisListingTVCell else {return UITableViewCell()}
cell.selectionStyle = .none
cell.lblTitle.attributedText = "\(self.presenter?.emrRecord?.emrDetails?.emrDiagnosis?[indexPath.row].name ?? "")".style(using: .syne_regular_18_black)
cell.lblDes.attributedText = "\(self.presenter?.emrRecord?.emrDetails?.emrDiagnosis?[indexPath.row].description ?? "")".style(using: .syne_regular_14_grey)
return cell
}
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 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)
}
}
What I want to do:
I have a feed (TableView( and once the user taps on a Post (TableViewCell), he should see a new Page (TableView) with the Post he tapped on first (the same TableViewCell) on top and a couple of comments below.
My Problem:
I dont get how to "clone" that TableViewCell.
Here two pictures for a better understanding:
Some complications:
I have multiple post types in the main feed, so the code would have to differentiate between them to see which cell type to use to display the content.
My code:
Main Feed
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return mixed.count
}
else if section == 1{
return phots.count
}
else{
return texttt.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: self.mixed[indexPath.row])
return cell
}
else if indexPath.section == 1{
let cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: self.phots[indexPath.row])
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: self.texttt[indexPath.row])
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC")
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
My second ViewController
class CommentsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView!
var texty = [TextComment]()
override func viewDidLoad() {
super.viewDidLoad()
table.register(popularTableViewCell.nib(), forCellReuseIdentifier: popularTableViewCell.identifier)
table.register(featuredTableViewCell.nib(), forCellReuseIdentifier: featuredTableViewCell.identifier)
table.register(textTableViewCell.nib(), forCellReuseIdentifier: textTableViewCell.identifier)
table.register(mixedTableViewCell.nib(), forCellReuseIdentifier: mixedTableViewCell.identifier)
table.register(textComTableViewCell.nib(), forCellReuseIdentifier: textComTableViewCell.identifier)
table.delegate = self
table.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}
else{
return 15
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: textComTableViewCell.identifier, for: indexPath) as! textComTableViewCell
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0{
// self.table.estimatedRowHeight = 250
// self.table.rowHeight = UITableView.automaticDimension
// return UITableView.automaticDimension
return 300
}
else{
// self.table.estimatedRowHeight = 150
// self.table.rowHeight = UITableView.automaticDimension
// return UITableView.automaticDimension
return 150
}
}
Note
Right now the it isnt working at all, how I want it. I just have these "mock" posts as space-fillers in there.
Any help or ideas would be greatly appreciated!
My structs
struct PhotoPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let postImageName: String
let postID: String
}
struct TextPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
let postID: String
}
struct MixedPhoto {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
let postImageName: String
let postID: String
}
Here my errors:
Each instance of UITableView has its own pool of cells, for this reason it would not be correct to "steal" an instance of the cell from one UITableView and put it into another. Also, as far as i can see you already have a convenient way to feed your cells with data, and dequeue corresponding types. Thus the only thing left here is to pass the required data from MainFeed under your tableView(_: didSelectRowAt:) function, something like that:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC") as? CommentsViewController else {
return
}
switch indexPath.section {
case 0:
vc.mixedData = mixed[indexPath.row]
case 1:
vc.photoData = photos[indexPath.row]
default:
vc.textData = texttt[indexPath.row]
}
vc.modalPresentationStyle = .fullScreen
navigationController?.pushViewController(vc, animated: true)
}
And then, under the CommentsViewController's tableView(_:, cellForRowAt:) function, implement pretty much the same stuff you did in MainFeed:
var mixedData: MixedPhoto?
var photoData: PhotoPost?
var textData: TextPost?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell: UITableViewCell
switch (mixedData, photoData, textData) {
case (.some(let value), _, _):
cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: value)
case (_, .some(let value), _):
cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: value)
case (_, _, .some(let value)):
cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: value)
default:
fatalError("The data is not set")
}
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: textComTableViewCell.identifier, for: indexPath) as! textComTableViewCell
return cell
}
}
Also I should say that it's a good idea to implement a common protocol for your data types, so you actually can define a single non-optional variable in the CommentsViewController instead of three optionals.
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/