This is a followup to a question I asked yesterday, I thought I had a solution based upon the answer received, but I'm having a new difficulty.
I have a single ViewController with two UITableViews (PropertyTypeListand PropertyDetailList)
I essentially want to treat this like a Master Detail View, When a row in PropertyTypeList is selected PropertyDetailList updates to an array based upon that selection. (I need it to be in one ViewController)
The problem was that I couldn't get the row selected from didSelectRowAtIndexPath into cellForRowAtIndexPath where I populate the tables through an If Statement to determine which tableview is in play.
I am now getting the currently selected row through a variable (currentRowInTypeList) and using that value to switch which array is loaded into PropertyDetailList.
Even though currentRowInTypeList is updating with each click the table isn't. What am I missing?
my code follows:
#IBOutlet weak var propertyTypeList: UITableView!
#IBOutlet weak var propertyDetailList: UITableView!
var testarray = ["test1", "test2"]
var testarray2 = ["test3", "test4"]
var currentRowInTypeList: Int = 0
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int
{
if tableView == propertyTypeList {
return projectSources.count;
}
else {
if currentRowInTypeList == 0 {
return testarray.count
} else {
return testarray2.count
}
}
}
func tableView(tableView: UITableView!,
cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
let cell:UITableViewCell = UITableViewCell(style:UITableViewCellStyle.Default, reuseIdentifier:"Cell")
if tableView == propertyTypeList {
cell.textLabel?.text = projectSources[indexPath.row]
return cell
}
else
{
if currentRowInTypeList == 0 {
cell.textLabel?.text = testarray[indexPath.row]
return cell
} else {
cell.textLabel?.text = testarray2[indexPath.row]
return cell
}
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let cell:UITableViewCell = UITableViewCell(style:UITableViewCellStyle.Default, reuseIdentifier:"Cell")
if tableView == propertyTypeList {
currentRowInTypeList = indexPath.row
println(currentRowInTypeList)
} else {
}
}
Just call propertyDetailList.reloadData()
In your code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let cell:UITableViewCell = UITableViewCell(style:UITableViewCellStyle.Default, reuseIdentifier:"Cell")
if tableView == propertyTypeList {
currentRowInTypeList = indexPath.row
propertyDetailList.reloadData()
println(currentRowInTypeList)
} else {
}
}
Related
I have one UIPickerView and one label inside expandable UITableViewCell and in the code I made 1 section and 3 cells all like first cell.
I did manage the data for every cell but my problem is when I select something from the first picker and I go to second picker and select something , my fist selection will be changed to same row order from the second picker .
To make it short how can I make the 3 pickers separate from each other and change every cell's label to the selected row from the same cell not else
This is a screenshot to my view :
And this my code :
import UIKit
let cellID = "cell"
class callViewController: UITableViewController {
var selectedIndexPath : NSIndexPath?
var tapped = false // when the first cell tapped it will be true
var flag = true
// These strings will be the data for the table view cells
let sections: [String] = ["Department:", "Team:", "Service:"]
override func awakeFromNib() {
super.awakeFromNib()
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
//number of sections
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
// header for the secation
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Required Info:"
}
//number of rows in section
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
//get the cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier(cellID, forIndexPath: indexPath) as! callCustomCell
cell.titleLabel.text=self.sections[indexPath.row]
// now reload the appropriate pickerData
if indexPath.row == 0{
cell.inputArrry=cell.departments
cell.picker.reloadAllComponents()
}
else if indexPath.row == 1{
cell.inputArrry=cell.teams
cell.picker.reloadAllComponents()
}
else if indexPath.row == 2{
cell.inputArrry=cell.services
cell.picker.reloadAllComponents()
}
if indexPath.row != 0{
cell.userInteractionEnabled = tapped
if (!tapped){
cell.backgroundColor=UIColor.clearColor()
}
else {
cell.backgroundColor=UIColor.whiteColor()
}
}
if indexPath.row==0{
cell.backgroundColor=UIColor.whiteColor()
cell.userInteractionEnabled=true
}
return cell
}
// method to run when table view cell is tapped
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 && flag {
flag = false
tapped = true
tableView.reloadRowsAtIndexPaths([
NSIndexPath(forRow: 1, inSection: 0),
NSIndexPath(forRow: 2, inSection: 0)], withRowAnimation: .Automatic)
}
let previousIndexPath = selectedIndexPath
if indexPath == selectedIndexPath {
selectedIndexPath = nil
}
else {
selectedIndexPath = indexPath
}
var indexPaths : Array<NSIndexPath> = []
if let previous = previousIndexPath {
indexPaths += [previous]
}
if let current = selectedIndexPath {
indexPaths += [current]
}
if indexPaths.count > 0 {
tableView.reloadRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
(cell as! callCustomCell).watchFrameChanges()
}
override func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
(cell as! callCustomCell).ignoreFrameChanges()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
for cell in tableView.visibleCells as! [callCustomCell] {
cell.ignoreFrameChanges()
}
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath == selectedIndexPath {
return callCustomCell.expandedHeight
} else {
return callCustomCell.defaultHeight
}
}
}
Use tags in the attribute inspector tab in the storyboards and then make if statements to change what is returned
if (pickerView.tag == 0) {
// Do something
} else if (pickerView.tag == 1 {
// Do something
} else {
// Do something
}
You could even use a switch statement too. Might look cleaner.
By default each section should show maximum three cells. If any cell contains more than three cells, it should display 'show more' option.If show more is tapped I want to display the rest of the cells in that particular section. Two days I spent, nothing worked out.Segments at the top of the table. Depend on segment selected, tableview load the cells. This code for each segment each section varies, so the func cellForRowAtIndexPath: becomes big seriously very big. I roughly added code. This code is what i have tried.
if segmentName == .Feature || segmentName == .Services
{
if indexPath.section == 0
{
if boolShowFullFeature[indexPath.section] == false
{
if indexPath.row == showCells
{
return createShowMoreCell(indexPath.section)
}
else
{
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! SearchListViewCell
var firstTitle = "", secondTitle = "", thirdTitle = "", recomendValue = "", starValue = ""
(firstTitle, secondTitle, thirdTitle, recomendValue, starValue) = model.foodValue[indexPath.row]
cell.configureCell(firstTitle, secondTitle: secondTitle, thirdTitle: thirdTitle, recomendValue: recomendValue, starValue: starValue)
return cell
i had actually done this before. here is sample code:
var objects = [["1","2","3"],["q","w","e","r","t","y"],["z","x","c","v","b","n","m"]]
var sec = ["sec a","sec b","sec c"]
var showallSec = 0
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sec.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let items = objects[section].count
if items > 3{
if section == showallSec-1{
return items
}
return 4
}
return items
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let object = objects[indexPath.section][indexPath.row]
cell.textLabel!.text = object
if(indexPath.section != showallSec-1){
if(indexPath.row == 3){
cell.textLabel!.text = "show more"
}}
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sec[section]
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if(indexPath.row == 3){
showallSec = indexPath.section + 1
tableView.reloadData()
}
}
What I'm trying to achieve is, when a cell in UITableview is tapped, it will expand and display custom cell1, other cells will remain custom cell2.
What I achieved so far is expand the cell, but the custom cell will not change.
After initial investigation, I thought it's the currentRow value wasn't changed. But then I realized if it isn't changed, the row won't expand. Thank you for your help.
Here are the code:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var currentRow = 0
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == currentRow {
let cell:selectedWeatherViewCell = self.weatherCityTable.dequeueReusableCellWithIdentifier("selectedWeatherCell") as! selectedWeatherViewCell
cell.selectedCityLabels.text = city[indexPath.row]
cell.selectedTempLabels.text = tempertureF[indexPath.row]
cell.backgroundColor = UIColor.redColor()
return cell
} else {
let cell:cityWeatherViewCell = self.weatherCityTable.dequeueReusableCellWithIdentifier("cityWeatherViewCell") as! cityWeatherViewCell
cell.cityLabels.text = city[indexPath.row]
cell.tempLabels.text = tempertureF[indexPath.row]
cell.backgroundColor = UIColor.orangeColor()
return cell
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedRowIndex = indexPath
currentRow = selectedRowIndex.row
tableView.beginUpdates()
tableView.endUpdates()
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == currentRow {
return 260
} else {
return 100
}
}
}
You need to reload the affected row(s) in order for the cell type to change -
var currentRow:Int?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var reloadRows=[NSIndexPath]()
if self.currentRow != nil && indexPath.row != self.currentRow! {
reloadRows.append(NSIndexPath(forRow: self.currentRow!, inSection: indexPath.section))
}
self.currentRow=indexPath.row
reloadRows.append(NSIndexPath(forRow: self.currentRow!, inSection: indexPath.section))
tableView.reloadRowsAtIndexPaths(reloadRows, withRowAnimation: UITableViewRowAnimation.Automatic)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
I am using table view for selecting objects. I want to select muliple objects in a tableview. I am using following code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: ContactCell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier) as! ContactCell
let row = indexPath.row
let person=contacts[row]
cell.setCell(person.nameLabel,image: "")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let row = indexPath.row
let person=contacts[row]
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
if cell.accessoryType == .Checkmark
{
cell.accessoryType = .None
}
else
{
cell.accessoryType = .Checkmark
}
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
My tableview looks like this:
I selected the "Kate" then I scroll down to bottom and "Test" is marked too. But why? I selected just "Kate". How can I prevent this?
It is selected "too", because inside a UITableView cells are reused...
let cell: ContactCell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier) as! ContactCell
If you want to solve this problem, the best way would be to save each cells state inside the array, which is holding your data of the UITableView... This is the best way.
Another way would be to declare a Dictionary of type [Int: Bool] and save your selected states to this... the Int key would be the row index, and its value could be true for selected, or false for not...
UPDATE
Following an example on how to solve your problem
class CustomTableViewController: UITableViewController {
#IBOutlet weak var contactsTableView: UITableView!
lazy var contactsArray: [[String: AnyObject]] = [[String: AnyObject]]()
//This method is to convert your contacts string array, into the array you need
private func appendContactsToContactsArray (contacts: [String]) {
for contact in contacts {
contactsArray.append(["name": contact, "selected": false])
}
contactsTableView.reloadData()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contactsArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: ContactCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ContactCell
cell.textLabel?.text = contactsArray[indexPath.row]["name"] as? String
if (isCellSelectedAtIndexPath(indexPath)) {
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
} else {
cell.accessoryType = UITableViewCellAccessoryType.None
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (isCellSelectedAtIndexPath(indexPath)) {
contactsArray[indexPath.row]["selected"] = false
} else {
contactsArray[indexPath.row]["selected"] = true
}
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
private func isCellSelectedAtIndexPath (indexPath: NSIndexPath) -> Bool {
return contactsArray[indexPath.row]["selected"] as? Bool ?? false
}
}
You're seeing this effect because cells are cached and reused. Note the word "Reusable" in dequeueReusableCellWithIdentifier.
Make "selected" a property of a contact or person. Set it true or false when a row is selected or deselected. Reload your data and set the accessory type in cellForRowAtIndexPath.
I have a UITableView with 3 prototyped cells (ex. 1st cell: image, 2nd cell: Description, 3. Links,...).
I would like to hide them if for a cell the data from the backend is empty (Ex. if there is no image, hide the first cell). In order to do that, I have override the heightForRowAtIndexPath function in this way:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
switch (indexPath.row) {
case 0:
if event?.photo_urls.count == 0{
return 0
}
else{
return 80.0
}
case 1:
if event?.description == ""{
return 0
}
else{
return 90.0
}
default:
return 100.0
}
}
and hidden the cell by doing
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch (indexPath.row) {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("PhotoCell", forIndexPath: indexPath) as! UITableViewCell
if event?.photo_urls.count != 0 {
// ...
}
else{
cell.hidden = true
}
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("DesCell", forIndexPath: indexPath) as! UITableViewCell
if event?.description != "" {
// ...
}
else{
cell.hidden = true
}
return cell
default:
let cell = tableView.dequeueReusableCellWithIdentifier("PhotoCell", forIndexPath: indexPath) as! UITableViewCell
return cell
}
}
Until here no problem, it works properly!
Now, THE PROBLEM is that I would like to make the cells dynamics according to the cell contents (ex. description height). In order to do that, I have used
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 80.0
}
and if I comment the heightForRowAtIndexPath the cells are actually dynamics but I can't hide them anymore.
Do you have any suggestion on how to be able to hide the cells if they are empty and apply the automatic dimension according to their content?
lets say you have dynamic data and you want to show it in tableview so you need to create an array of your data to display.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet
var tableView: UITableView
var items: [String] = ["We", "Heart", "nothing" ,"" ,"imageurl", "", "xyz"]
override func viewDidLoad() {
super.viewDidLoad()
reloadTableAfterSorting()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func reloadTableAfterSorting(){
for var i = 0; i < self.items.count; i++
{
if self.items[i] == ""{
self.items.removeAtIndex(2)
}
}
self.tableView.reloadData()
}
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) {
println("You selected cell #\(indexPath.row)!")
}
}
For that i recommend you to sort the array before displaying it in the table view. Hiding the cell is not a good idea and its not good according to Apple recommendations. So you can do one thing except hiding the cell: remove the index from the array. In this way you can always have data to show in table and it will behave properly. So don’t try to hide the cell just pop the index from array.