Dropdown table view with multiple and single selection in iOS swift? - ios

I have filter which is done in dropdown table view in an view controller. The dropdown table view contains three section namely section 1, section 2 and section 3. For section 1 and section 3 should single selection and section 2 should be multiple selection. When tapping section 1 it expands table view cell and when tapping on section 2 will expand and section 1 will close the expansion.
When selecting the option from each section should stored even user close and reopens the filter dropdown table view.
I have four questions:
When user tap on different section it should automatically close already open sections?
Table view should adjust height and its position based number cells in each sections?
how to do multiple and single selection for three sections?
selected should be stored even if dropdown table view is close and reopened.
Here is the code which tried so far all question which i have mentioned above:
extension HomeViewController : UITableViewDelegate, UITableViewDataSource, ExpandableHeaderViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
if locationListBool == true {
return 1
} else {
return sectionss.count
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if locationListBool == true {
return autocompleteplaceArray.count
} else {
return sectionss[section].category.count
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if locationListBool == true {
return 0
} else {
return 30
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if locationListBool == true {
return 30
} else {
if (sectionss[indexPath.section].expanded) {
return 30
} else {
return 0
}
}
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
if locationListBool == true {
return 0
} else {
return 2
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if locationListBool == true {
return nil
} else {
let header = ExpandableHeaderView()
header.contentView.backgroundColor = UIColor.white
header.customInit(title: sectionss[section].genre, section: section, delegate: self)
return header
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if locationListBool == true {
let cell = tableView.dequeueReusableCell(withIdentifier: "placecell", for: indexPath) as! locationNameTableViewCell
guard autocompleteplaceArray.count > 0 else {
return cell
}
cell.locationName.text = autocompleteplaceArray[indexPath.row]
return cell
} else {
let cell = dropDownTbl.dequeueReusableCell(withIdentifier: "dropDownCell", for: indexPath) as! dropDownCell
cell.dropDownLbl.text = sectionss[indexPath.section].category[indexPath.row]
cell.selectionStyle = .none
return cell
}
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = UIColor.clear
if locationListBool == true {
let lastRowIndex = tableView.numberOfRows(inSection: 0)
if indexPath.row == lastRowIndex - 1 {
tableView.allowsSelection = true
} else {
tableView.allowsSelection = true
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if locationListBool == true {
if let indexPath = tableView.indexPathForSelectedRow {
let currentCell = tableView.cellForRow(at: indexPath) as! UITableViewCell
searchText.text = (currentCell.textLabel?.text)
searchText.text = autocompleteplaceArray[indexPath.row]
placeIDString = autocompletePlaceIDArray[indexPath.row]
print("placeIDString::::\(String(describing: placeIDString))")
if placeIDString != nil {
getPlaceIDLatLong(placeIDs: placeIDString!)
print("get lat long \(getPlaceIDLatLong(placeIDs: placeIDString!))")
}
// PrefsManager.sharedinstance.lastlocation = searchText.text
locationText = searchText.text
print("locationText::::\(String(describing: locationText))")
}
self.locationTableList.isHidden = true
}
else {
}
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
switch indexPath.section {
case 0:
if let previousIndexPath = indexPathOfSelectedRowPaidBy {
dropDownTbl.deselectRow(at: previousIndexPath as IndexPath, animated: false)
dropDownTbl.cellForRow(at: previousIndexPath as IndexPath)?.accessoryType = UITableViewCellAccessoryType.none
}
indexPathOfSelectedRowPaidBy = indexPath as NSIndexPath?
dropDownTbl.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
case 1:
dropDownTbl.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
default:
break
}
return indexPath
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
{
switch indexPath.section {
case 0:
if let previousIndexPath = indexPathOfSelectedRowPaidBy {
dropDownTbl.deselectRow(at: previousIndexPath as IndexPath, animated: false)
dropDownTbl.cellForRow(at: previousIndexPath as IndexPath)?.accessoryType = UITableViewCellAccessoryType.none
}
indexPathOfSelectedRowPaidBy = nil
case 1:
dropDownTbl.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
default:
break
}
}
func toogleSection(header: ExpandableHeaderView, section: Int) {
sectionss[section].expanded = !sectionss[section].expanded
dropDownTbl.beginUpdates()
if sectionss[0].expanded{
dropDownTbl.layer.frame = CGRect(x: 15, y: 152, width: 345, height: 300)
} else if sectionss[1].expanded {
dropDownTbl.layer.frame = CGRect(x: 15, y: 152, width: 345, height: 230)
} else if sectionss[2].expanded {
dropDownTbl.layer.frame = CGRect(x: 15, y: 152, width: 345, height: 330)
} else {
dropDownTbl.layer.frame = CGRect(x: 15, y: 152, width: 345, height: 90)
}
for i in 0 ..< sectionss[section].category.count {
dropDownTbl.reloadRows(at: [IndexPath(row: i, section: section)], with: .automatic)
}
dropDownTbl.endUpdates()
}
}
Expandable table view header::
import UIKit
protocol ExpandableHeaderViewDelegate {
func toogleSection(header: ExpandableHeaderView, section: Int)
}
class ExpandableHeaderView: UITableViewHeaderFooterView {
var delegate: ExpandableHeaderViewDelegate?
var section: Int!
var collapaseHandlerArray = [String]()
let button = UIButton()
let button2 = UIButton()
override init(reuseIdentifier: String?){
super.init(reuseIdentifier: reuseIdentifier)
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(selectheaderAction)))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc func selectheaderAction(gestureRecognizer: UITapGestureRecognizer) {
let cell = gestureRecognizer.view as! ExpandableHeaderView
}
func customInit(title: String, section: Int, delegate: ExpandableHeaderViewDelegate) {
self.textLabel?.text = title
self.section = section
self.delegate = delegate
}
override func layoutSubviews() {
super.layoutSubviews()
self.textLabel?.font = UIFont(name: "Nunito-Light", size: 12)
self.textLabel?.textColor = UIColor(red: 64.0/255, green: 75.0/255, blue: 105.0/255, alpha: 1.0)
self.contentView.backgroundColor = UIColor.white
}
}
Dropdown table view cell:
class dropDownCell: UITableViewCell {
#IBOutlet weak var dropDownLbl: UILabel!
#IBOutlet weak var dropDwnBtn: UIButton!
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
}
}
Here is the screen shots when selection done in cell and after reopen filter selections are removed or options selected are changed, sections are not closed already expanded sections. Excepted result:

There is no built-in support for allowing differing numbers of cells to be selected in different sections of a table view.
However, the UITableViewDelegate protocol includes the function tableView(_:willSelectRowAt:).
If you read the docs on that function, it says:
Return Value
An index-path object that confirms or alters the selected
row. Return an NSIndexPath object other than indexPath if you want
another cell to be selected. Return nil if you don't want the row
selected.
So you should be able to set your view controller up as the delegate of the table view, set the allowsMultipleSelection flag to true, and implement logic in the tableView(_:willSelectRowAt:) function that provides the selection rules you want.
Take a stab at writing such a function and if you have trouble, post your code, tell us how it fails to meet your needs, and we'll try to help you fix it.

Related

UITableViewRows Not Visible

I have a simple UITableViewController and none of the rows are displaying. The table view header and section headers are all there. I have never encountered this. Thoughts?
import UIKit
class DashboardTableViewController: UITableViewController {
var countyName: String?
var sections = ["Quota Over/Short", "Qualified Renewals", "Membership Dues"]
override func viewDidLoad() {
super.viewDidLoad()
if countyName != nil {
self.title = "\(countyName!) County"
} else {
self.title = "County Info"
}
let headerView = DashboardCollectionView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 200))
tableView.tableHeaderView = headerView
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
} else if section == 1 {
return 2
} else {
return 9
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "UITableViewCell")
}
if #available(iOS 13.0, *) {
cell?.textLabel?.textColor = .label
} else {
cell?.textLabel?.textColor = .black
}
cell?.textLabel?.font = UIFont(name: "HelveticaNeue-Regular", size: 25)
cell?.textLabel?.numberOfLines = 2
if indexPath.section == 0 {
cell?.textLabel?.text = "-500"
} else if indexPath.section == 1 {
if indexPath.row == 0 {
cell?.textLabel?.text = "Previous Year: 1500"
} else {
cell?.textLabel?.text = "Current Year: 1000"
}
} else {
cell?.textLabel?.text = "Test Dues"
}
return cell!
}
}
You didn't answer the question about Prototype or Code-based cell class, and the code you've shown (in cellForRowAt) is not the right way to use table view cells.
Without seeing your custom cell setup, try it like this with a "default" cell:
class DashboardTableViewController: UITableViewController {
var countyName: String?
var sections = ["Quota Over/Short", "Qualified Renewals", "Membership Dues"]
override func viewDidLoad() {
super.viewDidLoad()
if countyName != nil {
self.title = "\(countyName!) County"
} else {
self.title = "County Info"
}
// I don't have your DashboardCollectionView class, so I'm creating
// as plain UIView with a blue background
//let headerView = DashboardCollectionView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 200))
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 200))
headerView.backgroundColor = .blue
tableView.tableHeaderView = headerView
// register a default UITableViewCell
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "defaultCell")
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
} else if section == 1 {
return 2
} else {
return 9
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
//override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return UITableView.automaticDimension
//}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// don't do it like this
//var cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")
//if cell == nil {
// cell = UITableViewCell(style: .default, reuseIdentifier: "UITableViewCell")
//}
// dequeue a registered cell
let cell = tableView.dequeueReusableCell(withIdentifier: "defaultCell", for: indexPath)
if #available(iOS 13.0, *) {
cell.textLabel?.textColor = .label
} else {
cell.textLabel?.textColor = .black
}
cell.textLabel?.font = UIFont(name: "HelveticaNeue-Regular", size: 25)
cell.textLabel?.numberOfLines = 2
if indexPath.section == 0 {
cell.textLabel?.text = "-500"
} else if indexPath.section == 1 {
if indexPath.row == 0 {
cell.textLabel?.text = "Previous Year: 1500"
} else {
cell.textLabel?.text = "Current Year: 1000"
}
} else {
cell.textLabel?.text = "Test Dues"
}
return cell
}
}
Result:
If that works (which it will), then try to use this code to figure out why your custom cell is not working.
From the image it looks like UITableView allocated space for your cells. I would recommend testing the cell by
NOT reuse cell just to see if you can get something to show up
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
Set background color to something
cell.backgroundColor = .red
If you see the cell show up then you know at least the tableview is giving you the correct # of cells

Expandable Tableview work with sectionHeader

I am trying to load my different controller using Expandable Tableview but my headerview is set
as switch condition
For Header XXX1 -> two sub menu a and b ..
For Header XXX2-> sub menu c
but for Header XXX3 no sub menu ,, So i will work on click with XXX3(currently working with check SectionData.count == 0 ) but for multiple how to manage .. check out my code
sectionNames = ["xxxx1","xxxx2","xxx3","xxxx4"] //this is main header
sectionItems = [ ["a","b"],[c],[],[],[],[],[],[]]// This is sub menu items
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.expandedSectionHeaderNumber == section) {
let arrayOfItems = self.sectionItems[section] as! NSArray
return arrayOfItems.count;
} else {
return 0;
}
//return arraylist.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if (self.sectionNames.count != 0) {
return self.sectionNames[section] as? String
}
return ""
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60.0;
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 50))
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifer, for: indexPath)
let section = self.sectionItems[indexPath.section] as! NSArray
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.text = section[indexPath.row] as? String
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
}
let indexPath = tableView.indexPathForSelectedRow
// print(indexPath as Any)
//getting the current cell from the index path
let currentCell = tableView.cellForRow(at: indexPath!)! as UITableViewCell
// print(currentCell as Any)
//getting the text of that cell
let currentItem = currentCell.textLabel!.text
print(currentItem!)
switch currentItem {
case "XXXX1":
//// Here unable to do any work
break
case "a":
APICalla()
case "b":
APICallb ()
default:
break
}
return
}
Using this link
Sorry this tutorial is quite poor.
Swift is an object oriented language so use a custom model, a generic Section object with name, items and the information if the section is collapsed
class Section<T> {
var name : String
var items = [T]()
var isCollapsed = false
init(name : String, items : [T] = []) {
self.name = name
self.items = items
}
}
and a suitable struct for the items with a title and a closure to be called in didSelect
struct Item {
let title : String
let selectorClosure : (() -> Void)?
}
Rather than using multiple arrays populate the data source array consistently
var sections = [Section<Item>(name:"xxxx1", items: [Item(title: "a", selectorClosure: APICalla), Item(title: "b", selectorClosure: APICallb)]),
Section<Item>(name:"xxxx2", items: [Item(title: "c", selectorClosure: APICallc)]),
Section<Item>(name:"xxxx3")]
In numberOfRowsInSection return the proper number of items depending on isCollapsed
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let currentSection = sections[section]
return (currentSection.isCollapsed) ? 0 : currentSection.items.count
}
In cellForRow don't use typeless Foundation collection types
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifer, for: indexPath)
let item = sections[indexPath.section].items[indexPath.row]
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.text = item.title
return cell
}
In the method to collapse/expand the sections just toggle isCollapsed
let currentSection = sections[section]
currentSection.isCollapsed.toggle()
and perform the animation
titleForHeaderInSection is much simpler, too
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].name
}
In didSelectRow never get any data from the view (the cell) get it from the model (the data source array) and call the selector closure. With this logic a switch is not needed.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
let item = sections[indexPath.section].items[indexPath.row]
item.selectorClosure?()
}
Swift4 I think this will helps you
// declare globally
var isExpanded : Bool = true
var indexOfSection = Int()
var yourArray = [ModelName]()
override func viewDidLoad() {
super.viewDidLoad()
indexOfSection = 999
}
extension ViewController: UITableViewDelegate, UITableViewDataSource
{
func numberOfSections(in tableView: UITableView) -> Int {
if yourArray.count > 0{
return yourArray.count
}else{
return 0
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x: view.frame.origin.x,y: 0 , width: view.frame.size.width ,height: 60))
headerView.backgroundColor = .white
let collapseBtn = UIButton(frame: CGRect(x: headerView.frame.origin.x,y: headerView.frame.origin.y , width: view.frame.size.width ,height: 60))
collapseBtn.addTarget(self, action: #selector(expandSection(sender:)), for: .touchUpInside)
collapseBtn.tag = section
collapseBtn.backgroundColor = .clear
headerView.addSubview(collapseBtn)
return headerView
}
#objc func expandSection(sender:UIButton){
print(sender.tag)
if isExpanded == true{
indexOfSection = sender.tag
mIdeaTableView.reloadData()
isExpanded = false
mTableView.reloadSections([indexOfSection], with: UITableView.RowAnimation.bottom)
}else{
indexOfSection = 999
isExpanded = true
self.mTableView.reloadData()
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if yourArray.count > 0{
if yourArray[section].items!.count > 0{
if indexOfSection == section{
return yourArray[section].items!.count
}else{
return 0
}
}else{
return 0
}
}else{
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: “CellID”, for: indexPath) as! Cell
if yourArray[indexPath.section]. items!.count > 0{
if yourArray[indexPath.section]. items!.count > 0{
let ideas = yourArray[indexPath.section].ideaItems
if ideas!.count > 0{
if indexOfSection == indexPath.section{
cell.mLbl.text = ideas![indexPath.row].name ?? ""
if ideas![indexPath.row].isExpanded == true{
cell.mAddImg.image = #imageLiteral(resourceName: "tick")
}else{
cell.mAddImg.image = #imageLiteral(resourceName: "edit213-1")
}
}
}
}
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
//Structure of my response
{
items = (
{
name = “a”;
},
{
name = “b”;
},
);
name = “xxxx1”;
}
items = (
{
name = “c”;
},
);
name = “xxxx2”;
}
}

Make first section rows cell already expanded in Expandable table view cells

In my App I implemented Expandable tableview. It's worked perfectly but now I want to change the first section was already expandable mode but I unable to do that.
Here I have implemented my own native code for creating expandable tableview not using any third party libraries.
Here I post my Full code for Expandable TableView:
#IBOutlet weak var tableViewSecond: UITableView!
var hidden = [true]
override func viewDidLoad() {
super.viewDidLoad()
tableViewSecond.delegate = self
tableViewSecond.dataSource = self
InspectionArray = [["inspection_name":"AVM Inspection"], ["inspection_name":"Simple Inspection"], ["inspection_name":"BVM Inspection"]]
InspectionSectionArray = [["inspection_Session":"Current Inspection"], ["inspection_Session":"Past Inspection"], ["inspection_Session":"Future Inspection"]]
}
func numberOfSections(in tableView: UITableView) -> Int {
for _ in 0..<InspectionSectionArray.count {
hidden.append(true)
}
return InspectionSectionArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if hidden[section] {
return 0
} else {
return InspectionArray.count
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.orange
headerView.tag = section
let label = UILabel()
label.text = (InspectionSectionArray[section] as AnyObject).value(forKey: "inspection_Session") as? String
label.frame = CGRect(x: 45, y: 5, width: 150, height: 35)
label.font = UIFont.boldSystemFont(ofSize: 15)
headerView.addSubview(label)
label.tag = section
let tapForheaderView = UITapGestureRecognizer(target: self, action: #selector(SecondViewController.tapFunction))
headerView.isUserInteractionEnabled = true
headerView.addGestureRecognizer(tapForheaderView)
return headerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 2
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "SecondTableViewCell", for: indexPath) as? SecondTableViewCell
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "SecondTableViewCell") as? SecondTableViewCell;
}
cell!.dataLbl.text = (InspectionArray[indexPath.row] as AnyObject).value(forKey: "inspection_name") as? String
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
print(indexPath.row)
print("\(indexPath.section)","\(indexPath.row)")
}
func tapFunction(sender:UITapGestureRecognizer) {
let section = sender.view!.tag
let indexPaths = (0..<InspectionArray.count).map { i in return IndexPath(item: i, section: section) }
hidden[section] = !hidden[section]
tableViewSecond.beginUpdates()
if hidden[section] {
tableViewSecond.deleteRows(at: indexPaths, with: .fade)
} else {
tableViewSecond.insertRows(at: indexPaths, with: .fade)
}
tableViewSecond.endUpdates()
}
I believe you only need to change this:
// declare hidden as this
var hidden: [Bool] = []
override func viewDidLoad() {
super.viewDidLoad()
InspectionArray = [["inspection_name":"AVM Inspection"], ["inspection_name":"Simple Inspection"], ["inspection_name":"BVM Inspection"]]
InspectionSectionArray = [["inspection_Session":"Current Inspection"], ["inspection_Session":"Past Inspection"], ["inspection_Session":"Future Inspection"]]
// initialize hidden array so that the first is false and the rest true
hidden = Array<Bool>(repeating: true, count: InspectionSectionArray.count)
hidden[0] = false
tableViewSecond.delegate = self
tableViewSecond.dataSource = self
}
// and change numberOfSections to this
func numberOfSections(in tableView: UITableView) -> Int {
return InspectionSectionArray.count
}
Just change this function
func tapFunction(sender: UITapGestureRecognizer?) {
var section = 0
if sender != nil {
section = sender!.view!.tag
}
let indexPaths = (0..<InspectionArray.count).map { i in return IndexPath(item: i, section: section) }
hidden[section] = !hidden[section]
tableViewSecond.beginUpdates()
if hidden[section] {
tableViewSecond.deleteRows(at: indexPaths, with: .fade)
} else {
tableViewSecond.insertRows(at: indexPaths, with: .fade)
}
tableViewSecond.endUpdates()
}
And call self.tapFunction(sender: nil) in viewdidLoad.

how to select Table View row selection with custom checkbox button?

How to select tableview row with custom button . i have another button called select all its outside of the table view my question is while clicking outside of the tableview button how to select and deselect inside tableview rows? At the same time i could able to select single row in the tableview ? how to do it in swift 3? This is my code in cellforrow method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "Custom"
var cell: TStudentAttendanceCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? TStudentAttendanceCell
if cell == nil {
tableView.register(UINib(nibName: "TStudentAttendanceCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? TStudentAttendanceCell
}
print("studentAttendanvceArray--",studentAttendanceArray.object(at: indexPath.row) )
var localDic :NSDictionary!
localDic = studentAttendanceArray.object(at: indexPath.row) as! NSDictionary
Common.sharedInstance.StopActivity()
cell.profile_img.image = self.image
cell.name_lbl.text = localDic["student_name"] as? String
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.contentView.backgroundColor = UIColor.clear
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 10, y: 8, width: self.view.frame.size.width - 20, height: 90))
whiteRoundedView.layer.backgroundColor = CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [1.0, 1.0, 1.0, 0.9])
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 2.0
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.2
cell.contentView.addSubview(whiteRoundedView)
cell.contentView.sendSubview(toBack: whiteRoundedView)
return cell
}
ViewController
class ViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var allStudentsArr:[[String:String]] = []
var selectedRows:[IndexPath] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsSelection = false
allStudentsArr = [["name":"name1"],["name":"name2"],["name":"name3"],["name":"name4"],["name":"name5"],["name":"name6"],["name":"name7"],["name":"name8"]]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allStudentsArr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! CustomTableViewCell
cell.nameLbl.text = allStudentsArr[indexPath.row]["name"]
if selectedRows.contains(indexPath)
{
cell.checkBox.setImage(UIImage(named:"selected"), for: .normal)
}
else
{
cell.checkBox.setImage(UIImage(named:"unselected"), for: .normal)
}
cell.checkBox.tag = indexPath.row
cell.checkBox.addTarget(self, action: #selector(checkBoxSelection(_:)), for: .touchUpInside)
return cell
}
#objc func checkBoxSelection(_ sender:UIButton)
{
let selectedIndexPath = IndexPath(row: sender.tag, section: 0)
if self.selectedRows.contains(selectedIndexPath)
{
self.selectedRows.remove(at: self.selectedRows.index(of: selectedIndexPath)!)
}
else
{
self.selectedRows.append(selectedIndexPath)
}
self.tableView.reloadData()
}
#IBAction func selectAllBtnAction(_ sender: UIBarButtonItem) {
self.selectedRows = getAllIndexPaths()
self.tableView.reloadData()
}
func getAllIndexPaths() -> [IndexPath] {
var indexPaths: [IndexPath] = []
for j in 0..<tableView.numberOfRows(inSection: 0) {
indexPaths.append(IndexPath(row: j, section: 0))
}
return indexPaths
}
}
Custom Cell
class CustomTableViewCell: UITableViewCell {
#IBOutlet var nameLbl: UILabel!
#IBOutlet var checkBox: UIButton!
}
Thats how you can programatically select all rows of a single section
#IBAction func didTapSelectAllButton(sender: UIButton) {
let totalRows = tableView.numberOfRows(inSection: 0)// Make some logic if you have more than 1 section
for row in 0..<totalRows {
let indexPath = IndexPath(row: row, section: 0)
tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
}
}
If you don't want to use default check box of tableView then disable multipleSelection from tableView and implement logic using an extra global array.
var selectedArrayIndex = [Int]()
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedArrayIndex.contains(indexPath.row) {
selectedArrayIndex.remove(at: selectedArrayIndex.index(of: indexPath.row)!)
}else {
selectedArrayIndex.append(indexPath.row)
}
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if selectedArrayIndex.contains(indexPath.row) {
// Enable You Check
cell.checkBoxView.isHidden = false
}else {
cell.checkBoxView.isHidden = true
}
}
#IBAction func didTapSelectAllButton(sender: UIButton) {
let totalRows = tableView.numberOfRows(inSection: 0)// Make some logic if you have more than 1 section
selectedArrayIndex.removeAll()
for row in 0..<totalRows {
selectedArrayIndex.append(row)
}
}

How do select a row from each section of the tableview in swift?

I want to select a row from different sections of the same table-view. I am getting output that many rows are selecting but I want exactly only one selected row from each section.
Here is My Arrays:
var filterFeedUnderAll = ["Complex","NotComplex","Easy"]
var filterFeedUnderAllStocks = ["AllStocks","Portfolio","Watchlist","Sector","Ticker"]
var filterFeedUnderByDate = ["ByDate","ByComments","ByLikes"]
The methods I have used:
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 3
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
var count:Int?
if section == 0
{
count = filterFeedUnderAll.count
}
else if section == 1
{
count = filterFeedUnderAllStocks.count
}
else if section == 2
{
count = filterFeedUnderByDate.count
}
return count!
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = self.m_HomeFeedFilterBaseTableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! HomeFeedFIlterBaseTableViewCell
switch (indexPath.section)
{
case 0:
cell.m_TableItemsLabel.text = filterFeedUnderAll[indexPath.row]
case 1:
cell.m_TableItemsLabel.text = self.filterFeedUnderAllStocks[indexPath.row]
case 2:
cell.m_TableItemsLabel.text = filterFeedUnderByDate[indexPath.row]
default:
cell.m_TableItemsLabel.text = "Other"
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let cell = m_HomeFeedFilterBaseTableView.cellForRowAtIndexPath(indexPath) as! HomeFeedFIlterBaseTableViewCell
for selectedIndexPath: NSIndexPath in tableView.indexPathsForSelectedRows!
{
if selectedIndexPath.section == indexPath.section
{
cell.m_TableItemsLabel.textColor = selectedTextColor
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
}
I want to select one row from each section. Help me to achieve this task.
first of all you need to enable multiple selection in your tableView and then this is the code that I used to do that, note that I use a Dictionary with format [String:NSIndexPath] named selectedRows where I store one indexPath by section I do this in addSelectedCellWithSection
UPDATED for last swift
import UIKit
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,UITextFieldDelegate {
#IBOutlet weak var tableView: UITableView!
var filterFeedUnderAll = ["Complex","NotComplex","Easy"]
var filterFeedUnderAllStocks = ["AllStocks","Portfolio","Watchlist","Sector","Ticker","bla bla bla1","bla bla bla2","bla bla bla3","bla bla bla1","bla bla bla2","bla bla bla3","bla bla bla1","bla bla bla2","bla bla bla3"]
var filterFeedUnderByDate = ["ByDate","ByComments","ByLikes"]
var selectedRows = [String:IndexPath]()
var alert : UIAlertController?
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 3
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50;
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCell(withIdentifier: "headerCell") as! mycustomHeader
let layer = CAShapeLayer()
let corners = UIRectCorner.topLeft.union(UIRectCorner.topRight)
layer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: headerCell.frame.width, height: headerCell.frame.height), byRoundingCorners: corners, cornerRadii:CGSize(width: 20.0, height: 20.0)).cgPath
headerCell.layer.mask = layer
return headerCell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
var count:Int?
if section == 0
{
count = filterFeedUnderAll.count
}
else if section == 1
{
count = filterFeedUnderAllStocks.count
}
else if section == 2
{
count = filterFeedUnderByDate.count
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! testCell
switch (indexPath.section)
{
case 0:
cell.lblName.text = filterFeedUnderAll[indexPath.row]
case 1:
cell.lblName.text = self.filterFeedUnderAllStocks[indexPath.row]
case 2:
cell.lblName.text = filterFeedUnderByDate[indexPath.row]
default:
cell.lblName.text = "Other"
}
cell.lblName.textColor = UIColor.black
if(self.indexPathIsSelected(indexPath)) {
cell.lblName.textColor = UIColor.red
}
return cell
}
func addSelectedCellWithSection(_ indexPath:IndexPath) ->IndexPath?
{
let existingIndexPath = selectedRows["\(indexPath.section)"]
selectedRows["\(indexPath.section)"]=indexPath;
return existingIndexPath
}
func indexPathIsSelected(_ indexPath:IndexPath) ->Bool {
if let selectedIndexPathInSection = selectedRows["\(indexPath.section)"] {
if(selectedIndexPathInSection.row == indexPath.row) { return true }
}
return false
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = self.tableView.cellForRow(at: indexPath) as! testCell
let previusSelectedCellIndexPath = self.addSelectedCellWithSection(indexPath);
if(previusSelectedCellIndexPath != nil)
{
let previusSelectedCell = self.tableView.cellForRow(at: previusSelectedCellIndexPath!) as! testCell
previusSelectedCell.lblName.textColor = UIColor.black
cell.lblName.textColor = UIColor.red
tableView.deselectRow(at: previusSelectedCellIndexPath!, animated: true)
}
else
{
cell.lblName.textColor = UIColor.red
}
for selectedIndexPath: IndexPath in tableView.indexPathsForSelectedRows!
{
if selectedIndexPath.section == indexPath.section
{
cell.lblName.textColor = UIColor.red
tableView.deselectRow(at: indexPath, animated: true)
}
}
}
}
Hope this helps you, for me works perfect

Resources