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.
Related
I've implemented tableView section index in my app.
TableView Section Index shows when data of tableView is local, When i get data from api call at that time tableview section index hides.
I don't understand why this happening
Here is my tableview section index code:
var sectionArray = UILocalizedIndexedCollation.current().sectionIndexTitles // section Array
func numberOfSections(in tableView: UITableView) -> Int
{
return memberStructList.count // this is structList
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return memberStructList[section].memberArray.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let cell = tableView.dequeueReusableCell(withIdentifier: "MembersHeaderTVCell") as! MembersTVCell
cell.lblSectionHeader.text = memberStructList[section].sectionName
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "MembersTVCell") as! MembersTVCell
let sectionRows = memberStructList[indexPath.section]
let row = sectionRows.memberArray[indexPath.row]
cell.lblMemberName.text = row.first_name
return cell
}
func sectionIndexTitles(for tableView: UITableView) -> [String]?
{
return sectionArray
}
func tableView(_ tableView: UITableView,
sectionForSectionIndexTitle title: String,
at index: Int) -> Int
{
if memberStructList.contains(where: {$0.sectionName == title}),
let sectionIndex = memberStructList.firstIndex(where: {$0.sectionName == title})
{
return sectionIndex
}
else
{
return NSNotFound
}
}
And Here is Structure Code:
struct MemberStruct
{
var sectionName : String
var memberArray : [MemberModel] = []
}
Here is My Webservice Code and MVCServer is My Webservice Function
MVCServer().serviceRequestWithURL(reqMethod: .get, withUrl: strUrl, withParam: [:], diplayHud: true, includeToken: true) { (ResponseCode, Response) in
if ResponseCode == 1
{
if let array = Response.value(forKeyPath: "payload.data") as? NSArray
{
var memberArray = MemberModel.modelsFromDictionaryArray(array: array)
memberArray.forEach({$0.first_name = $0.first_name.capitalized + " " + $0.last_name.capitalized})
memberArray.sort(){$0.first_name < $1.first_name}
let groupedDictionary = Dictionary(grouping: memberArray, by: {String($0.first_name.capitalized.prefix(1))})
let keys = groupedDictionary.keys.sorted()
self.memberStructList = keys.map({ MemberStruct(sectionName: $0, memberArray: groupedDictionary[$0]!)})
self.tblMembers.reloadData()
}
}
else
{
Utility.showToast(messageData: Response)
}
}
If everything is ok with your local data so, I guess You did not follow the priority.
You must set your tableview Delegate and Datasource after receiving the response from webservice.
self.tableview.dataSource = self
self.tableview.delegate = self
or you should reload your tableview again:
self.tableview.reloadData()
Have you tried this instead of using TableViewCell on the section header?
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 18))
let label = UILabel(frame: CGRectMake(10, 5, tableView.frame.size.width, 18))
label.font = UIFont.systemFontOfSize(14)
label.text = memberStructList[section].sectionName
view.addSubview(label)
view.backgroundColor = UIColor.grayColor() // Set your background color
return view
}
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”;
}
}
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.
I am new to Swift and I am trying to create Tableview in which I have only 3 Rows (Morning, Afternoon, and Night). If I click on the Morning row my cell must expand. It must display keynumber number of user whose time 8 - 12. Same for Afternoon and Night.
I have specified array data of User[] in which keynumber, time and other data are there.
I tried to do with if condition in cellForRowAtIndexPath but it displays only one user key for the Morning row. It doesn't display another users key in that particular time limit.
Try This
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
var items: [String] = ["We", "Heart", "Swift"]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = self.items[indexPath.row]
return cell
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
print("You selected cell #\(indexPath.row)!")
}
}
Hope this helps.
Have a try, works like a charm here
struct User {
var keynumber: Int
var time: NSData
}
class TableViewController: UITableViewController {
var userArr : Array<User> = [] //raw user data
var sortedUser : [String : Array<User>] = ["Morning": [], "Afternoon": [], "Night": []]
var sectionStatusArr : [String: Bool] = ["Morning": false, "Afternoon": false, "Night": false] // section status array used to control expanding
override func viewDidLoad() {
super.viewDidLoad()
//classify user into corresponding group(time zone)
for _ in 0...19 {
let randomKey = Int( arc4random()%23)
let user = User(keynumber: randomKey, time: NSData())
userArr.append(user)
}
//sort user: 8-12 -> morning, 13-18 -> afternoon, 19-8 -> night
for user in userArr{
switch user.keynumber {
case 8,9,10,11,12:
sortedUser["Morning"]?.append(user)
case 13,14,15,16,17,18:
sortedUser["Afternoon"]?.append(user)
default:
sortedUser["Night"]?.append(user)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return sortedUser.keys.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
var rowcount = 0
var shouldExpandSection = false
switch section {
case 0:
rowcount = (sortedUser["Morning"]?.count)!
shouldExpandSection = sectionStatusArr["Morning"]!
case 1:
rowcount = (sortedUser["Afternoon"]?.count)!
shouldExpandSection = sectionStatusArr["Afternoon"]!
default:
rowcount = (sortedUser["Night"]?.count)!
shouldExpandSection = sectionStatusArr["Night"]!
}
return shouldExpandSection ? rowcount : 0
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = UIView(frame: CGRect(x: 0, y: 0, width: 375, height: 60))
let nameBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 375, height: 60))
nameBtn.backgroundColor = UIColor.cyan
nameBtn.tag = section
nameBtn.addTarget(self, action: #selector(self.headerTouched(sender:)), for: .touchUpInside)
switch section {
case 0:
nameBtn.setTitle("Morning", for: .normal)
case 1:
nameBtn.setTitle("Afternoon", for: .normal)
default:
nameBtn.setTitle("Night", for: .normal)
}
header.addSubview(nameBtn)
return header
}
func headerTouched(sender:UIButton){
switch sender.tag {
case 0:
sectionStatusArr["Morning"] = !sectionStatusArr["Morning"]!
case 1:
sectionStatusArr["Afternoon"] = !sectionStatusArr["Afternoon"]!
default:
sectionStatusArr["Night"] = !sectionStatusArr["Night"]!
}
self.tableView.reloadData()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var sectionArr : Array<User>= []
switch indexPath.section {
case 0:
sectionArr = sortedUser["Morning"]!
case 1:
sectionArr = sortedUser["Afternoon"]!
default:
sectionArr = sortedUser["Night"]!
}
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
for subview in cell.subviews{
subview.removeFromSuperview()
}
let lab = UILabel(frame: CGRect(x: 0, y: 0, width: 375, height: 40))
lab.text = "Un:" + String(sectionArr[indexPath.row].keynumber)
lab.textAlignment = .center
cell.addSubview(lab)
return cell
}
}
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