Two tableviews in one view controller, one table view not showing up - ios

I have two TableViews in one ViewController and only one table is able to populate. I have created outlets for both tables in my view controller. Here is my viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
pickerTableView.delegate = self
pickerTableView.dataSource = self
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView()
pickerTableView.reloadData()
tableView.reloadData()
}
It seems that the only table that is read is self.tableView and the pickerTableView is never read in the protocols for UITableView
extension MealViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if tableView == self.tableView {
let nameHeaderView = NameHeaderView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 40))
nameHeaderView.delegate = self
nameHeaderView.sectionIndex = section
nameHeaderView.nameButton.setTitle(Data.userModels[section].name, for: .normal)
return nameHeaderView
} else {
return nil
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if tableView == self.tableView {
return Data.userModels.count
} else {
return 0
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.tableView {
if Data.userModels[section].isExpandable {
return Data.userModels[section].itemModels.count
} else {
return 0
}
} else if tableView == pickerTableView {
return Data.userModels.count
}
else {
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == self.tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "nameCells", for: indexPath) as! MealTableViewCell
cell.setup(itemModel: Data.userModels[indexPath.section].itemModels[indexPath.row])
return cell
} else if tableView == pickerTableView {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "pickerCells", for: indexPath) as! NamePickerTableViewCell
cell2.setup(userModel: Data.userModels[indexPath.row])
print(Data.userModels)
return cell2
}
else {
return UITableViewCell()
}
}
}
I have also applied constraints on each tableView so they both appear on the screen. When I run the app, the data for self.tableView is shown however the pickerTableView appears empty. self.tableView requires sections and pickerTableView does not require sections, could this be an issue? Also there is data in the Data.userModels array.
And just for reference, here is my UITableViewCell class:
class NamePickerTableViewCell: UITableViewCell {
#IBOutlet weak var namePickerLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setup(userModel: UserModel) {
namePickerLabel.text = userModel.name
}
}
Thanks for the help!

If you do not need any section in pickerTableView, then also it has to have at least one section.
So return 1 in method numberOfSections when tableview == self. pickerTableView.
func numberOfSections(in tableView: UITableView) -> Int {
if tableView == self.tableView {
return Data.userModels.count
} else {
return 1
}
}

Related

Can't find reason for why tableViewCell is not editable and no default text is showing up

Sorry for the ignorant question but I am trying to follow my school's appdev tutorial and I came upon an error where I am trying to create editable table view cells but neither the default text nor the ability to edit is showing up. I checked in the custom TableViewCell class and the TextView Outlet is there. Any help would be much appreciated :3
import UIKit
class AddVerbViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource{
var isPickerViewOpened : Bool = false
#IBOutlet weak var TableView: UITableView!
#IBAction func DoneButtonTapped(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func ClearButtonTapped(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
TableView.delegate = self
TableView.dataSource = self
print("yes")
// Do any additional setup after loading the view.
}
//MARK: - Table View Methods
func numberOfSections(in tableView: UITableView) -> Int {
print("number of sections : 2")
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (section == 0){
return 2
} else {
return 2
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AddVerbCell", for: indexPath)as! AddVerbTableViewCell
cell.TextView.textContainer.maximumNumberOfLines = 1
cell.TextView.textContainer.lineBreakMode = .byTruncatingTail
cell.PickerView.isHidden = true
if (indexPath.section == 0) {
cell.TextView.isEditable = true
cell.TextView.textColor = UIColor.gray
cell.TextView.isScrollEnabled = false
if (indexPath.row == 0){
print("cell Name")
cell.TextView.text = "Name"
} else {
cell.TextView.text = "TeForm"
}
} else {
if (indexPath.row == 0) {
cell.TextView.isEditable = false
cell.TextView.isSelectable = false
cell.TextView.textColor = UIColor.black
cell.TextView.text = "PotentialForm"
} else {
cell.TextView.isHidden = true
cell.PickerView.isHidden = false
}
}
return cell
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 20
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (indexPath.section == 0) {
return 50
} else {
if (indexPath.row == 0){
return 50
} else {
return 100
}
}
}
/*
// 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.destination.
// Pass the selected object to the new view controller.
}
*/
}
I actually figured it out.
So I needed to add cell.TextView.isUserInteractionEnabled = true to the proper areas. Now it works!
Sorry for the trouble everyone

When I go back to the page, changing number and cell datas of the TableView

I am using nested tableview. The main tableview lists the file categories. Child tableview listing the files. I open the files with safari. The child tableview is listed incorrectly when I go back to the page after opening the file. How can i solve this problem? Android sdk have "onActivityResult" method. Does iOS have a similar function? Thanks.
ViewController
import UIKit
class ProductDetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
var bundleProductModel:ProductModel? = ProductModel.init()
var lastFileCatIndex:Int = 0
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If tableview is file category table.
if (tableView.tag == 100){
return bundleProductModel!.fileCategoryModels.count
} else /* Table view is file tableview. */ {
//self.lastFileIndex = self.lastFileIndex + 1
return (bundleProductModel?.fileCategoryModels[self.lastFileCatIndex].files.count)!
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (tableView.tag == 100){
// Define cell for file category.
let cell = tableView.dequeueReusableCell(withIdentifier: "FileCategoryTableViewCell") as! FileCategoryTableViewCell
// Set file category cell height.
cell.frame.size.height = CGFloat(((bundleProductModel?.fileCategoryModels[indexPath.row].files.count)! * 44) + 42)
// cell row height
tableView.rowHeight = CGFloat(((bundleProductModel?.fileCategoryModels[indexPath.row].files.count)! * 44) + 42)
// Control bound
if (self.lastFileCatIndex <= indexPath.row){
// Index.
self.lastFileCatIndex = indexPath.row
// File category name.
cell.lblFileCatNme.text = " \(bundleProductModel?.fileCategoryModels[indexPath.row].file_category_name ?? "Unknow") "
}
return cell
} else {
// Define cell for files.
let cell = tableView.dequeueReusableCell(withIdentifier: "FileTableViewCell") as! FileTableViewCell
if ((bundleProductModel?.fileCategoryModels[self.lastFileCatIndex].files.count)! > indexPath.row){
// Set file model to file cell.
cell.setFile(fileItem: (self.bundleProductModel?.fileCategoryModels[self.lastFileCatIndex].files[indexPath.row])!)
// file cell delegate
cell.delegate = self
} else {
cell.lblFileName.text = "unknow"
}
return cell
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ProductDetailViewController:FileCellDelegate{
func didClickDownload(downloadLink: String, button: UIButton) {
if let url = URL(string: downloadLink) {
UIApplication.shared.open(url)
}
}
}
A very easy workaround on iOS would be to override viewWillAppear and call reloadData() like so:
override func viewWillAppear() {
super.viewWillAppear()
tableView.reloadData()
}
This will update your table everytime your view reappears.
SOLVED
Problem is lastFileCategoryIndex variable. Ex: final value is four. When I come back to the page; listing relative to fourth index. I define child tableview in main tableview cell and solved.
FileCategoryTableViewCell
class FileCategoryTableViewCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
// General Objects
var fileCategoryModel:FileCategoryModel = FileCategoryModel.init()
// Cell Ui Objects
#IBOutlet weak var lblFileCatNme: UILabel!
#IBOutlet weak var fileTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fileCategoryModel.files.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = fileTableView.dequeueReusableCell(withIdentifier: "FileTableViewCell") as! FileTableViewCell
cell.lblFileName.text = "Ex File..."
return cell
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
// Set category model.
func setFileCategory(fileCategoryModel:FileCategoryModel){
self.fileCategoryModel = fileCategoryModel
self.fileTableView.dataSource = self
self.fileTableView.delegate = self
}
}

Swift 3.0 multiple selection with select all cell

I have added data in table view and I have manually added "select all" option to the list at first position, now when the user selects the first option which is 'select all' then the person manually option "Select all" is not selected. Select all, click then work all person or deselect working but signal selection all the person not working "Select all"
I have tried the code below but it's not working so can any one help me to solve this?
var unchecked:Bool = true
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell = ObjTableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SelectUserCell
// set the text from the data model
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.lblStudentName.text = getStudentName[indexPath.row]
if UnAll == "unselect" {
if indexPath.row == 0 {
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
if indexPath.row == Int(selectedNumber) {
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
if indexPath.row == Int(unSelectNumber) {
//var j = "\(i)"
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}
}else
{
if(unchecked){
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
else{
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}
}
return cell
}
var UnAll = ""
var selectedNumber = ""
var unSelectNumber = ""
var checkselect:Bool = true
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UnAll.removeAll()
selectedNumber.removeAll()
unSelectNumber.removeAll()
if(indexPath.row == 0){
btnCheckBoxClick(sender: UIButton())
}else
{
UnAll = "unselect"
btnCheckBoxClick(sender: UIButton())
if checkselect {
selectedNumber = "\(indexPath.row)"
checkselect = false
}else
{
unSelectNumber = "\(indexPath.row)"
checkselect = true
}
print("the selected index is : \(indexPath.row)")
}
}
#IBAction func btnCheckBoxClick(_ sender: Any) {
if(unchecked){
unchecked = false
}
else{
unchecked = true
}
ObjTableview.reloadData()
}
Create a struct for model data with a Bool property. You can modify this property by cell selection.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var allCharacters:[Character] = []
override func viewDidLoad() {
super.viewDidLoad()
allCharacters = [Character(name: "All"),Character(name: "Luke Skywalker"),Character(name: "Leia Organa"),Character(name: "Advik Shah"),Character(name: "Aarav Modi")]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allCharacters.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil{
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
}
cell?.textLabel?.text = allCharacters[indexPath.row].name
if allCharacters[indexPath.row].isSelected
{
cell?.accessoryType = .checkmark
}
else
{
cell?.accessoryType = .none
}
cell?.selectionStyle = .none
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0
{
allCharacters[indexPath.row].isSelected = !allCharacters[indexPath.row].isSelected
for index in allCharacters.indices
{
allCharacters[index].isSelected = allCharacters[indexPath.row].isSelected
}
}
else
{
allCharacters[indexPath.row].isSelected = !allCharacters[indexPath.row].isSelected
if allCharacters.dropFirst().filter({ $0.isSelected }).count == allCharacters.dropFirst().count
{
allCharacters[0].isSelected = true
}
else
{
allCharacters[0].isSelected = false
}
}
tableView.reloadData()
}
}
struct Character
{
var name:String
// var otherDetails
var isSelected:Bool! = false
init(name:String) {
self.name = name
}
}
Creating Array of Struct objects from array of dictionary
let SubjectArray = json["students"] as! [[String:Any]]
allCharacters = SubjectArray.map({ Character(name: $0["studentName"] as! String) })
allCharacters.insert(Character(name:"All"), at: 0)
I like #Pranil's suggestion of using a separate section for the "All" row, so I have stolen that.
You can use an NSMutableIndexSet for tracking the selected rows. This is simpler than having to create a new struct or array of booleans or something. The only thing you do need to be aware of is if your tableview allows row reordering then the index set needs to be adjusted accordingly.
Here is my implementation. The "all" state is determined by the number of selected rows being equal to the number of rows in the data source array.
I have just used simple table view accessories for the checkmarks, but I am sure you can see how to adopt your image based approach in cellForRow(at:)
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableview: UITableView!
let names: [String]? = ["Luke Skywalker","Leia Organa","Advik Shah","Aarav Modi"]
var selectedRows = NSMutableIndexSet()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let names = self.names else {
return 0
}
return 0 == section ? 1 : names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
var text: String
var accessory = UITableViewCellAccessoryType.none
if 0 == indexPath.section {
text = "All"
if self.selectedRows.count == self.names!.count {
accessory = .checkmark
}
} else {
text = names![indexPath.row]
if selectedRows.contains(indexPath.row) {
accessory = .checkmark
}
}
cell.textLabel!.text = text
cell.accessoryType = accessory
return cell
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if indexPath.section == 0 {
if self.selectedRows.count == self.names!.count {
self.selectedRows = NSMutableIndexSet()
} else {
self.selectedRows = NSMutableIndexSet(indexesIn: NSRange(location: 0, length: self.names!.count))
}
tableView.reloadData()
} else {
self.selectedRows.contains(indexPath.row) ? self.selectedRows.remove(indexPath.row) : self.selectedRows.add(indexPath.row)
let rows = [IndexPath(row: 0, section: 0), indexPath]
tableView.reloadRows(at: rows, with: .none)
}
return nil
}
}
I think you are using only one section in the table view. I suggest you use two sections in the table view, so that first section will contain only one row (Select All) and the second section will contain other options. When you click on Select All, that is in the first row of the first section you can make all the rows in the second section as selected while reloading the table view.
// MARK: - struct for cell item
struct CellItem {
var name : String
var isSelected:Bool! = false
init(name: String) {
self.name = name
}
}
class ViewController: UITableViewController {
#IBOutlet var viewTable: UITableView!
// Declare a boolean varaible to toggle the checkbox in the first section of table view
var isSelectAllSelected : Bool = false
var cellData: [CellItem] = []
override func viewDidLoad() {
super.viewDidLoad()
cellData = [CellItem(name: "Luke Skywalker"),CellItem(name: "Leia Organa"),CellItem(name: "Advik Shah"),CellItem(name: "Aarav Modi")]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
}
else
{
return cellData.count
}
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0
}
// MARK: - Table view delegates
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = TableCell()
cell.selectionStyle = .none
if indexPath.section == 0 {
cell.textLabel?.text = "Select All"
if isSelectAllSelected{
cell.accessoryType = .checkmark
}
else{
cell.accessoryType = .none
}
}
else
{
cell.textLabel?.text = cellData[indexPath.row].name
if cellData[indexPath.row].isSelected{
cell.accessoryType = .checkmark
}
else{
cell.accessoryType = .none
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0
{
cellData[indexPath.row].isSelected = !cellData[indexPath.row].isSelected
isSelectAllSelected = cellData[indexPath.row].isSelected
for index in cellData.indices
{
cellData[index].isSelected = cellData[indexPath.row].isSelected
}
}
else
{
cellData[indexPath.row].isSelected = !cellData[indexPath.row].isSelected
if cellData.filter({ $0.isSelected }).count == cellData.count
{
isSelectAllSelected = true
}
else
{
isSelectAllSelected = false
}
}
viewTable.reloadData()
} }
Hello u can take cheboxbutton action method inside view controller with addtarget method and assign tag indexpath.row so u can easily get the indexpath. from below code u can get the idea.
class ViewController:UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var ObjTableview: UITableView!
var arrStudent = ["1","2","3","4","5"]
var arrSelectedStudent :[Int] = []
var selectAll:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrStudent.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell = ObjTableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SelectUserCell
// set the text from the data model
cell.selectionStyle = UITableViewCellSelectionStyle.none
// cell.lblStudentName.text = getStudentName[indexPath.row]
cell.lblStudentName.text = arrStudent[indexPath.row]
cell.btnCheckbox.tag = indexPath.row
cell.btnCheckbox.addTarget(self, action:#selector(btnCheckBoxClick(sender:)), for: .touchUpInside)
if selectAll {
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}else{
if arrSelectedStudent.contains(indexPath.row){
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}else{
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func btnCheckBoxClick(sender: UIButton) {
if sender.tag == 0{
selectAll = true
}else
{
selectAll = false
if let index = arrSelectedStudent.index(of: sender.tag) {
arrSelectedStudent.remove(at: index)
}else{
arrSelectedStudent.append(sender.tag)
}
}
ObjTableview.reloadData()
}}

How to pass data (which am getting from server) into tableView which is in UIView

I have one viewController. In that i have one button, if i click on that button am presenting a UIView on that viewController.
In that UIVew i have one tableView. Now i want to pass data into that tableview, which am getting from server.
I cant display the data in tableView, i kept breakpoint and checked. am not able to enter into cellForRowAt indexPath method also
could any one help me with this
Here is the code which i tried
Here is my UIView class
class ButtonClicked: UIView {
#IBOutlet weak var tableView: UITableView!
override func didMoveToSuperview() {
//super.awakeFromNib()
}
Here is my ViewController class
class ViewController: UIViewController{
var tableviewDisplayArray: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
buttonClicked.tableView.register(UINib(nibName: “TableViewDisplayCell", bundle: nil), forCellReuseIdentifier: “tableViewDispCell")
buttonClicked.tableView.delegate = self
buttonClicked.tableView.dataSource = self
}
#IBAction func addMoneyButtonClicked() {
buttonClickedWebserviceCall()
actionAlertViewController.actionType = ActionAlertType.ADD_MONEY
present(self.view.actionAlertPopup(alertVC: actionAlertViewController), animated: animated, completion: nil)
}
func buttonClickedWebserviceCall(){
let params: NSDictionary = ["langId" : “1”, "countryId" : “1”]
callingWebservice().dataTaskWithPostRequest(urlrequest: URL_BUTTONCLICKED viewcontroller: self, params: params) { (result, status) in
let response : NSDictionary = result as! NSDictionary
let status = response.value(forKey: "httpCode") as! NSNumber
if status == 200{
DispatchQueue.main.async {
self.tableviewDisplayArray= (response.value(forKey: “response”) as? NSArray)!
print(self.tableviewDisplayArray)
self.buttonClicked.tableView.reloadData()
}
}
else{
DispatchQueue.main.async {
}
}
}
}//method close
}//class close
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == buttonClicked.tableView {
return tableviewDisplayArray.count
}
else{
return 5
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if tableView == buttonClicked.tableView {
return 30.0
}
else{
return 75.0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == buttonClicked.tableView {
let cell = buttonClicked.tableView.dequeueReusableCell(withIdentifier: "tableViewDispCell", for: indexPath) as! TableViewDisplayCell
let storedArray = self.tableviewDisplayArray.object(at: indexPath.row) as! NSDictionary
print(storedArray)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: “normalCell”, for: indexPath) as! NormalCell
return cell
}
}
}
You have written the tableView delegate methods in an extension of UIViewController class. Just write that code inside the ViewController class where you have set the delegate and datasource to.Like this
class ViewController: UIViewController,UITableViewDelegate, UITableViewDataSource{
var tableviewDisplayArray: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
buttonClicked.tableView.register(UINib(nibName: “TableViewDisplayCell", bundle: nil), forCellReuseIdentifier: “tableViewDispCell")
buttonClicked.tableView.delegate = self
buttonClicked.tableView.dataSource = self
}
#IBAction func addMoneyButtonClicked() {
buttonClickedWebserviceCall()
actionAlertViewController.actionType = ActionAlertType.ADD_MONEY
present(self.view.actionAlertPopup(alertVC: actionAlertViewController), animated: animated, completion: nil)
}
func buttonClickedWebserviceCall(){
let params: NSDictionary = ["langId" : “1”, "countryId" : “1”]
callingWebservice().dataTaskWithPostRequest(urlrequest: URL_BUTTONCLICKED viewcontroller: self, params: params) { (result, status) in
let response : NSDictionary = result as! NSDictionary
let status = response.value(forKey: "httpCode") as! NSNumber
if status == 200{
DispatchQueue.main.async {
self.tableviewDisplayArray= (response.value(forKey: “response”) as? NSArray)!
print(self.tableviewDisplayArray)
self.buttonClicked.tableView.reloadData()
}
}
else{
DispatchQueue.main.async {
}
}
}
}//method close
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == buttonClicked.tableView {
return tableviewDisplayArray.count
}
else{
return 5
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if tableView == buttonClicked.tableView {
return 30.0
}
else{
return 75.0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == buttonClicked.tableView {
let cell = buttonClicked.tableView.dequeueReusableCell(withIdentifier: "tableViewDispCell", for: indexPath) as! TableViewDisplayCell
let storedArray = self.tableviewDisplayArray.object(at: indexPath.row) as! NSDictionary
print(storedArray)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: “normalCell”, for: indexPath) as! NormalCell
return cell
}
}
//Notice that tableView delegate methods should be in your ViewController class because that is the 'self' here so delegate and datasource is the ViewController class
//buttonClicked.tableView.delegate = self
//buttonClicked.tableView.dataSource = self
//as you write this the tableview looks for data in this ViewController class.
//Extensions are meant for another purpose.
}
//class close

Swift/iOS: Collapsing a section in a UITableView

I have a UITableView with about 5 sections. I am trying to collapse and expand one of those section by the click of a button, but I am seeing an issue where the code I'm using to do so results in the collapsing of other sections as well. Specifically, the first row of all visible sections are collapsed.
Here is what that code looks like:
func didClickSectionCollapseButton() {
shouldCollapseSection = !shouldCollapseSection
tableView.beginUpdates()
tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: .Fade)
tableView.endUpdates()
}
And here is the numberOfRowInSection method:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 1
case 1:
// collapsible section
return shouldCollapse ? 0 : collapsibleSectionCellCount
case 2:
return getCellCount()
case 3:
return 1
case 4:
return 1
default:
return 0
}
}
Is there anything I'm missing here? I've gone through various tutorials and questions, but I haven't been able to find a solution yet.
Hi after a lot of research, i found a solution which worked for me perfectly using storyboard.
View controller code:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblView: UITableView!
var sections = ["section1","section2","section3"]
var cells = ["cell1","cell2","cell3","cell4"]
var selectedIndx = -1
var thereIsCellTapped = false
override func viewDidLoad() {
super.viewDidLoad()
tblView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 2
case 1:
return 3
default:
return 4
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == selectedIndx && thereIsCellTapped{
return 50
}else{
return 0
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCell(withIdentifier: "SectionTableViewCell") as! SectionTableViewCell
headerCell.lblHeader.text = sections[section]
headerCell.btnSelection.tag = section
headerCell.btnSelection.addTarget(self, action: #selector(ViewController.btnSectionClick(sender:)), for: .touchUpInside)
return headerCell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExpandeTableViewCell") as! ExpandeTableViewCell
cell.lblCell.text = cells[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.section)
}
#objc func btnSectionClick(sender:UIButton!){
print("selected index",sender.tag)
if selectedIndx != sender.tag {
self.thereIsCellTapped = true
self.selectedIndx = sender.tag
}
else {
// there is no cell selected anymore
self.thereIsCellTapped = false
self.selectedIndx = -1
}
tblView.reloadData()
}
}
If you don't want to do select and unselect on the same selection then, see code below.
#objc func btnSectionClick(sender:UIButton!){
print("selected index",sender.tag)
selectedIndx = sender.tag
tblView.reloadData()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == selectedIndx{
return 50
}else{
return 0
}
}
It works for me, i referred lot of answers and made it. I hope it will help you.
I've Used this code long time ago it is in Swift 2.3. I don't know if this will help or not but worth to mention it.
class DriversVC : UIViewController , UITableViewDelegate , UITableViewDataSource {
//-----------------------------------------------------------------------
//MARK: - Outlets
#IBOutlet var tvDriverList: UITableView! {
didSet {
tvDriverList.delegate = self
tvDriverList.dataSource = self
}
}
//-----------------------------------------------------------------------
//MARK: - Variables
var arrDriverList : NSArray? //Section data
var arrWorkerList : NSArray? //Section data
var collapseSection0 : Bool = false
var collapseSection1 : Bool = false
var btnSection0Headder : UIButton = UIButton()
var btnSection1Headder : UIButton = UIButton()
//------------------------------------------------------
func btnSection0HeadderTapped () {
if collapseSection0 {
collapseSection0 = false
} else {
collapseSection0 = true
}
tvDriverList.reloadSections(NSIndexSet(index: 0), withRowAnimation: UITableViewRowAnimation.Fade)
}
//------------------------------------------------------
func btnSection1HeadderTapped () {
if collapseSection1 {
collapseSection1 = false
} else {
collapseSection1 = true
}
tvDriverList.reloadSections(NSIndexSet(index: 1), withRowAnimation: UITableViewRowAnimation.Fade)
}
//-----------------------------------------------------------------------------------
//MARK:- Table delegate and data sources
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
//------------------------------------------------------
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 20
}
//------------------------------------------------------
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.mainScreen().bounds.width, height: 50))
view.backgroundColor = OrangeColor //Set your color
let lbl = UILabel(frame: CGRect(x: 10, y: 5, width: UIScreen.mainScreen().bounds.width - 20, height: 40))
lbl.font = UIFont(name: OpenSansRegular, size: 18) //Set your font
lbl.textColor = UIColor.whiteColor()
view.addSubview(lbl)
if section == 0 {
lbl.text = "D R I V E R"
btnSection0Headder.addTarget(self, action: #selector(self.btnSection0HeadderTapped), forControlEvents: .TouchUpInside)
btnSection0Headder.frame = view.frame
view.addSubview(btnSection0Headder) // uncomment to apply collapse effect
} else {
lbl.text = "W O R K E R"
btnSection1Headder.addTarget(self, action: #selector(self.btnSection1HeadderTapped), forControlEvents: .TouchUpInside)
btnSection1Headder.frame = view.frame
view.addSubview(btnSection1Headder) // uncomment to apply collapse effect
}
return view
}
//------------------------------------------------------
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return UIView()
}
//------------------------------------------------------
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if arrWorkerList != nil && arrWorkerList?.count > 0 {
return 2
}
return 1
}
//------------------------------------------------------
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
if !collapseSection0 {
guard arrDriverList != nil else {return 0}
return arrDriverList!.count
} else {
return 0
}
} else {
if !collapseSection1 {
guard arrWorkerList != nil else {return 0}
return arrWorkerList!.count
} else {
return 0
}
}
}
//------------------------------------------------------
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCellWithIdentifier(NSStringFromClass(DriversCVC).componentsSeparatedByString(".").last!) as? DriversCVC else { fatalError("unexpected DriversCVC dequeued from tableView") }
cell.superViewController = self
if indexPath.section == 0 {
guard let dict = arrDriverList![indexPath.row] as? NSDictionary else {return cell}
cell.data = dict
} else {
guard let dict = arrWorkerList![indexPath.row] as? NSDictionary else {return cell}
cell.data = dict
}
cell.setup()
return cell
}
//----------------------------------------------------------------------
//MARK: - Action Method
#IBAction func btnBackTapped(sender: AnyObject) {
guard self.navigationController != nil else {
self.dismissViewControllerAnimated(true, completion: nil)
return
}
guard self.navigationController?.popViewControllerAnimated(true) != nil else {
guard self.navigationController?.dismissViewControllerAnimated(true, completion: nil) != nil else {
AppDelegate.sharedInstance().loginCall()
return
}
return
}
}
//-----------------------------------------------------------------------
//MARK: - View Life Cycle Methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
//----------------------------------------------------------------------
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
setUpVC()
}
//----------------------------------------------------------------------
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
} }
You can use:
func didClickSectionCollapseButton() {
shouldCollapseSection = !shouldCollapseSection
tableView.beginUpdates()
tableView.deleteSections(NSIndexSet(index: 1), withRowAnimation: .Fade)
tableView.endUpdates()
}
beginUpdates() and endUpdates() works in pair if you want subsequent insertions, deletion, and selection operations, but not for the reloadData.
In your code, remove beginUpdates() and endUpdates().
Is there a difference between the shouldCollapseSection variable being set in the button action and the shouldCollapse variable used in the numberOfRowsInSection method ?
It would seem that you are not setting the same variable you are using in the data source delegate.

Resources