Load more options with UITableView - ios

Trying to load my data in page using pagination, I've already seen many examples but all are in Objective-C and some questions are unanswered.
My code:
class testTableViewController: UITableViewController {
//MARK: - Properties -
var allObjectArray: NSMutableArray = []
var elements: NSMutableArray = []
var currentPage = 0 //number of current page
var nextpage = 0
var selectedRow = Int()
//MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
for var i = 1; i < 500; i++ {
allObjectArray.addObject(i)
}
elements.addObjectsFromArray(allObjectArray.subarrayWithRange(NSMakeRange(0, 30)))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source -
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count + 1
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedRow = (tableView.indexPathForSelectedRow?.row)!
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var customCell = tableView.dequeueReusableCellWithIdentifier("cell")
customCell = UITableViewCell(style: .Default, reuseIdentifier: "cell")
customCell!.textLabel!.text = "cell - \(allObjectArray[indexPath.row])"
if indexPath.row == elements.count {
customCell?.textLabel?.textColor = UIColor.blueColor()
customCell?.textLabel?.text = "Load more..."
}
return customCell!
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
nextpage = elements.count
if indexPath.row == nextpage {
if indexPath.row == selectedRow {
currentPage++
nextpage = elements.count - 5
elements.addObjectsFromArray(allObjectArray.subarrayWithRange(NSMakeRange(currentPage, 30)))
tableView.reloadData()
}
}
}
}
I want this kind of output:
Tried to fetch selected index but it will return nil.

Create Outlets in Interface Builder for tableview and make two dynamic prototype cells give them identifiers make one cell with a button(your load more cell button)
Then create action with that button that will contain the logic to load more cells!!!
now see the snipet below for reference...
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tblDemo: UITableView!
var arForCells:NSMutableArray = NSMutableArray()
let simpleCellID = "SimpleCell"
let loadMoreCell = "LoadMoreCell"
override func viewDidLoad() {
super.viewDidLoad()
tblDemo.delegate = self
tblDemo.dataSource = self
arForCells = NSMutableArray(objects: "1", "2", "3", "4", "5", "6", "7", "8", "9", "10")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arForCells.count + 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if (indexPath.row == arForCells.count){
let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier(loadMoreCell, forIndexPath: indexPath)
return cell
}else {
let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier(simpleCellID, forIndexPath: indexPath)
let lblCounter = cell.viewWithTag(111) as! UILabel
lblCounter.text = arForCells.objectAtIndex(indexPath.row) as! String
return cell
}
}
#IBAction func loadMoreCells(sender: AnyObject) {
let newAr:NSArray = NSArray(objects: "1", "2", "3", "4", "5", "6", "7", "8", "9", "10")
arForCells.addObjectsFromArray(newAr as [AnyObject])
tblDemo.reloadData()
}}
as I have checked, It should give you the desired results.
You could also do the same in TableViewFooter.

To set "Load More.." text add a label with this text in a view having the same size of your tableViewCell. Then add this in your tableView footer. Add a (custom/transparent)button in footer view so when that touched it will load your main array with more data and then reload your tableView.
Hope this helps!

First of all, You don't have to use this:
selectedRow = (tableView.indexPathForSelectedRow?.row)!
in the didSelectRowAtIndexPath. You can use simply
selectedRow = indexPath.row
next, your logic for willDisplayCellAtIndexPath seems redundant if you want to have cell to tap on it. You can simply put the following in enter code here:
nextpage = elements.count
if indexPath.row == nextpage {
currentPage++
nextpage = elements.count - 5
elements.addObjectsFromArray(allObjectArray.subarrayWithRange(NSMakeRange(currentPage, 30)))
tableView.reloadData()
}
also, I am not sure why do you need nextpage = elements.count - 5 but I assume that you have reason behind this.

done it my self
import UIKit
class LoadMoreTableVC: UITableViewController {
//MARK: - Properties -
var allObjectArray: NSMutableArray = []
var elements: NSMutableArray = []
var currentPage = 0 //number of current page
var nextpage = 0
var totalElements = 500 //total elements
var elementAtOnePage = 30 //at one page
//MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
for i in 0 ..< totalElements {
allObjectArray.addObject(i+1)
}
elements.addObjectsFromArray(allObjectArray.subarrayWithRange(NSMakeRange(0, elementAtOnePage)))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source -
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = elements.count + 1
if count < allObjectArray.count
{
return count
}
else
{
return allObjectArray.count
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == elements.count {
loadDataDelayed()
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel!.text = "\(allObjectArray[indexPath.row])"
if indexPath.row == elements.count {
cell.textLabel?.text = "Load more..."
}
return cell
}
func loadDataDelayed(){
currentPage += 1
elements.addObjectsFromArray(allObjectArray.subarrayWithRange(NSMakeRange(currentPage, elementAtOnePage)))
tableView.reloadData()
}
}

I have already done this is in swift.
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if loading == true {
var endScrolling:CGFloat = scrollView.contentOffset.y + scrollView.frame.size.height
if(endScrolling >= scrollView.contentSize.height){
NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "loadDataDelayed", userInfo: nil, repeats: false)
}
}
}
Please try this code.
And share your response.
Happy coding :)

Related

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()
}}

Infinite scroll with UITableView and an Array

I'm new in Swift and I want to make an infinite scroll with an Array. Here it's my class TableViewController
class TableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var legumes: [String] = ["Eggs", "Milk", "Chocolat", "Web", "Miel", "Pop", "Eco", "Moutarde", "Mayo", "Thea", "Pomelade", "Gear", "Etc" , "Nop", "Dews", "Tout", "Fun", "Xen" , "Yoga" ]
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.legumes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ImageTableViewCell
return cell
}
}
I want to show the first ten items of my array and when I am on the bottom of the TableViewController, it will load the next ten items, etc. I don't know how to do, I see a lot of code on GitHub but I don't know how to implement them.
Thank you so much.
Consider using PagingTableView
class MainViewController: UIViewController {
#IBOutlet weak var contentTable: PagingTableView!
var legumes: [String] = ["Eggs", "Milk", "Chocolat", "Web", "Miel", "Pop", "Eco", "Moutarde", "Mayo", "Thea", "Pomelade", "Gear", "Etc" , "Nop", "Dews", "Tout", "Fun", "Xen" , "Yoga" ]
override func viewDidLoad() {
super.viewDidLoad()
contentTable.dataSource = self
contentTable.pagingDelegate = self
}
}
extension MainViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return legumes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ImageTableViewCell
guard legumes.indices.contains(indexPath.row) else { return cell }
cell.content = legumes[indexPath.row]
return cell
}
}
extension MainViewController: PagingTableViewDelegate {
func paginate(_ tableView: PagingTableView, to page: Int) {
contentTable.isLoading = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.legumes.append(contentsOf: legumes)
self.contentTable.isLoading = false
}
}
}
Modify the paginate function to work as you wish
What you're describing is called pagination. You should do something like this:
/* Number of page you're loading contents from */
var pageIndex: Int = 1
override func scrollViewDidScroll(scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
let contentHeight = scrollView.contentSize.height
if offsetY > contentHeight - scrollView.frame.size.height {
/* increment page index to load new data set from */
pageIndex += 1
/* call API to load data from next page or just add dummy data to your datasource */
/* Needs to be implemented */
loadNewItemsFrom(pageIndex)
/* reload tableview with new data */
tableView.reloadData()
}
}

Trigger segue from a "collapsed" cell

I made a table view with collapsing cells I followed this tutorial; everything works great, except for the segue method. I simply tried to add performsegueWithIdentifier method (adding the segue in the storyboard by the cell)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
performSegueWithIdentifier("toChantController", sender: self)
}
and prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "toChantController"
{
let indexPath = tableView.indexPathForCell(sender as! UITableViewCell)
let controller = segue.destinationViewController as! ChantViewController
controller.chant = "\(sections[indexPath!.row])"
}
}
but Xcode sends me this error
"Could not cast value of type 'iSupporters.TeamChantViewController' (0x104562730) to 'UITableViewCell' (0x106600540)."
Here my whole class:
import UIKit
class TeamChantViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
{
// MARK: properties
var teamChants: TeamModel!
#IBOutlet weak var tableView: UITableView!
struct Section {
var name: String!
var items: [String]!
var collapsed: Bool!
init(name: String, items: [String], collapsed: Bool = true) {
self.name = name
self.items = items
self.collapsed = collapsed
}
}
var sections = [Section]()
override func viewDidLoad()
{
super.viewDidLoad()
tableView.backgroundColor = UIColor.clearColor()
tableView.separatorColor = UIColor.clearColor()
sections = [
Section(name: "Juventus", items: ["Olè", "fino alla fine", "ovunque voi giocate", "juve olè"]),
Section(name: "Derby", items: ["toro merda", "odio i granata", "il viola è il colore che odio"]),
Section(name: "Giocatori", items: ["Vidal", "Pogba", "Del Piero"])
]
}
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
self.tabBarController?.tabBar.hidden = true
}
// MARK: collection view data source and delegate
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
var count = sections.count
for section in sections
{
count += section.items.count
}
return count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
let section = getSectionIndex(indexPath.row)
let row = getRowIndex(indexPath.row)
if row == 0 {
return 50.0
}
return sections[section].collapsed! ? 0 : 44.0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let section = getSectionIndex(indexPath.row)
let row = getRowIndex(indexPath.row)
if row == 0
{
let cell = tableView.dequeueReusableCellWithIdentifier("teamChantsHeader") as! TeamChantsHeader
cell.teamChantSectionTitle.text = sections[section].name
cell.toggleButton.tag = section
cell.toggleButton.setTitle(sections[section].collapsed! ? "+" : "-", forState: .Normal)
cell.toggleButton.addTarget(self, action: #selector(TeamChantViewController.toggleCollapse), forControlEvents: .TouchUpInside)
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("teamChantsCell") as UITableViewCell!
cell.textLabel?.text = sections[section].items[row - 1]
return cell
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
performSegueWithIdentifier("toChantController", sender: self)
print(self)
}
// MARK: navigation (segue)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "toChantController"
{
let indexPath = tableView.indexPathForCell(sender as! UITableViewCell)
let controller = segue.destinationViewController as! ChantViewController
controller.chant = "\(sections[indexPath!.row])"
}
}
// MARK: - other methods
func toggleCollapse(sender: UIButton)
{
let section = sender.tag
let collapsed = sections[section].collapsed
// Toggle collapse
sections[section].collapsed = !collapsed
let indices = getHeaderIndices()
let start = indices[section]
let end = start + sections[section].items.count
tableView.beginUpdates()
for i in start ..< end + 1
{
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: i, inSection: 0)], withRowAnimation: .Automatic)
}
tableView.endUpdates()
}
func getSectionIndex(row: NSInteger) -> Int
{
let indices = getHeaderIndices()
for i in 0..<indices.count
{
if i == indices.count - 1 || row < indices[i + 1]
{
return i
}
}
return -1
}
func getRowIndex(row: NSInteger) -> Int
{
var index = row
let indices = getHeaderIndices()
for i in 0..<indices.count
{
if i == indices.count - 1 || row < indices[i + 1]
{
index -= indices[i]
break
}
}
return index
}
func getHeaderIndices() -> [Int]
{
var index = 0
var indices: [Int] = []
for section in sections
{
indices.append(index)
index += section.items.count + 1
}
return indices
}
}
Could anyone help me to perform this segue?
Edit: my segue in the storyboard
You are doing here two things,
First you have created segue in stroyboard from the UITableViewCell to ChantViewController.
Now in didSelectRowAtIndexPath you are performing segue again with passing self as reference of TeamChantViewController.
You need to change any one thing to solved your problem.
Edit: From your comment you need to pass indexPath object with sender parameter in performSegue method like this and get that indexPath in prePareForSegue method.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("toChantController", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toChantController"
{
let indexPath = sender as! NSIndexPath
let controller = segue.destinationViewController as! ChantViewController
controller.chant = "\(sections[indexPath!.row])"
}
}

Loading an Array to TableView based on Segment-Control

I am relatively new to Swift. I tried to search and google the problem but i can't find any answers. It shouldn't be that hard. Hope you guys can help me out. I‘ve been struggling with this Issue over days now:
I created a Tableview which loads an array of tuples from another .swift file. That is working fine! Now I want the tableview to choose the .swift based on a "segment control". So if the Segment-Control is switched to "A" I want it to show the Array of "PSSCBOOKMac.Swift", for B it would be the Array of "PSSCBOOKWin.swift".
The Action ist written properly, I guess (print-statements are working). But the change of the segment-control doesn't effect the Tableview. My guess: The segment-control doesn't effect the Tableview because it has been loaded before and I can't change the value. How can I achieve that?
Cheers for any answers!
Here is the Code:
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
#IBOutlet weak var PSSCSegmentControl: UISegmentedControl!
//LOAD ARRAY FROM PSSCBOOK.SWIFT
var PSSCBook = PSSCBOOKMac()
#IBAction func PSSCSegmentControlChoose(sender: AnyObject) {
if PSSCSegmentControl.selectedSegmentIndex == 0 {
var PSSCBook = PSSCBOOKMac()
println("im mac")
} else {
var PSSCBook = PSSCBOOKWin()
println("im win")
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return PSSCBook.PSSCTools.count
} else {
return PSSCBook.PSSCFile.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("PSCell", forIndexPath: indexPath) as! UITableViewCell
if indexPath.section == 0 {
let (shortCutTitle,shortCutKey) = PSSCBook.PSSCTools[indexPath.row]
cell.textLabel?.text = shortCutTitle
cell.detailTextLabel?.text = shortCutKey
} else {
let (shortCutTitle,shortCutKey) = PSSCBook.PSSCFile[indexPath.row]
cell.textLabel?.text = shortCutTitle
cell.detailTextLabel?.text = shortCutKey
}
/* var PSIcon = UIImage(named: "PSIcon")
cell.imageView?.image = PSIcon */
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Tools"
} else {
return "File"
}
}
}
When you update the datasource of your table view, it won't magically update itself.
You have to reload the table view for the changes to take place:
#IBAction func PSSCSegmentControlChoose(sender: AnyObject) {
if PSSCSegmentControl.selectedSegmentIndex == 0 {
var PSSCBook = PSSCBOOKMac()
println("im mac")
} else {
var PSSCBook = PSSCBOOKWin()
println("im win")
}
self.tableView.reloadData();
}
I spend the last two days trying to figure out what was wrong with my code. I implemented the suggested reloadData() without having errors. The println Values in the console change.. But the tableview just won't refresh. I really don’t know where else to look, is searched for hours. Could somebody please tell me what type of silly mistake I am doing? Thanks guys!
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
//LOAD ARRAY FROM PSSHORTCUTSBOOK.SWIFT
var PSSCBook = PSShortCutsBook()
#IBOutlet weak var SCOutlet: UISegmentedControl!
#IBOutlet weak var SCtableviewOutlet: UITableView!
#IBAction func SCAction(sender: AnyObject) {
if SCOutlet.selectedSegmentIndex == 1 {
var PSSCBook = PSShortCutsBook()
println("There are \(PSSCBook.shortCutsPS.count) items in this Array")
self.SCtableviewOutlet.reloadData();
} else {
var PSSCBook = PSShortCutsBook2()
println("There are \(PSSCBook.shortCutsPS.count) items in this Array")
self.SCtableviewOutlet.reloadData();
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return PSSCBook.shortCutsPS.count
} else {
return PSSCBook.shortCutsPS2.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("PSCell", forIndexPath: indexPath) as! UITableViewCell
if indexPath.section == 0 {
let (shortCutTitle,shortCutKey) = PSSCBook.shortCutsPS[indexPath.row]
cell.textLabel?.text = shortCutTitle
cell.detailTextLabel?.text = shortCutKey
} else {
let (shortCutTitle,shortCutKey) = PSSCBook.shortCutsPS2[indexPath.row]
cell.textLabel?.text = shortCutTitle
cell.detailTextLabel?.text = shortCutKey
}
/* var PSIcon = UIImage(named: "PSIcon")
cell.imageView?.image = PSIcon */
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Tools"
} else {
return "Help"
}
}
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.
}
}

Swfit: Tableview passing values to Prototype Cell and finding which row a control was triggered

In my app I have two table view controllers.
tableViewController1 has a list of rows with text label and loads some data from Core Data, an important value is a 'deviceid' that I need pretty much for anything in my app.
tableViewController2 has 1-5 rows depending on which row you selected in tableViewController1.
I've implemented a prototype custom cell that has its own class and implemented a label (label2) and a segment control (segment1).
When I select for example the first row on tableViewController1, I see 3 rows in tableViewController2, thus 3 segment controls.
With a protocol I can trigger back to the tableViewController2 that the segment control has changed value but how do I know which one of the three was triggered?
I tried using the didSelectRowAtIndexPath but if the user taps the segment control only then the row is not selected so it doesn't trigger.
Also if I want to pass the 'deviceid' from the tableViewController2 to the prototype cell, is that possible? I tried again with the protocol but had no luck.
Code for what I'm trying to do:
[EDIT] I took the input and managed to get it working without the need for protocol but adding an action at cell level, is this the 'proper' way to do it though?
class TableViewController1: UITableViewController {
var rowItems = ["Row 1", "Row 2", "Row 3"]
var deviceid = "123456789"
var rowToSend: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rowItems.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell1") as! TableViewCell1
cell.label1.text = rowItems[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
rowToSend = indexPath.row
performSegueWithIdentifier("seg1", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "seg1") {
let theDestination = (segue.destinationViewController as! TableViewController2)
theDestination.deviceid = deviceid
theDestination.incomingRow = rowToSend
}
}
}
class TableViewController2: UITableViewController {
var deviceid = ""
var incomingRow: Int = 0
var parameterItems = ["Parameter 1", "Parameter 2", "Parameter 3"]
override func viewDidLoad() {
super.viewDidLoad()
if incomingRow < 2 {
parameterItems = ["Parameter 1", "Parameter 2", "Parameter 3"]
} else {
parameterItems = ["Parameter 1", "Parameter 4", "Parameter 5"]
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return parameterItems.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell2") as! TableViewCell2
cell.label2.text = parameterItems[indexPath.row]
cell.segment1.addTarget(self, action: "controlChanged:", forControlEvents: UIControlEvents.ValueChanged)
return cell
}
func controlChanged(sender: UISegmentedControl) {
let pointInTable: CGPoint = sender.convertPoint(sender.bounds.origin, toView: self.tableView)
let cellIndexPath = self.tableView.indexPathForRowAtPoint(pointInTable)
if let myRow = cellIndexPath?.row {
println("row: \(myRow) with value: \(sender.selectedSegmentIndex) for deviceid: \(deviceid)")
}
}
}
class TableViewCell2: UITableViewCell {
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var segment1: UISegmentedControl!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
The way to get from a control to the index path of the cell is as follows:
func controlChanged(sender: UISegmentedControl) {
let point = sender.convertPoint(CGRectZero toView: self.tableView)
let indexPath = self.tableView(indexPathForRowAtPoint: point)
// your logic based on indexPath
}

Resources