Problem:
IF User "Login" the i want show "Logout" option in cell and vice versa. but i created UI in Storyboard as
I have created custom UITableView class and cellForRowAtIndexPath look like
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// var cell : UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell!
let cell : UITableViewCell? = menuListView.cellForRowAtIndexPath(indexPath)
if indexPath.row == 20
{
let titleLabel = cell?.contentView.viewWithTag(100) as! UILabel
if(NSUserDefaults.standardUserDefaults().integerForKey("UserID") <= 0 ){
//logout
cell?.contentView.backgroundColor = UIColor(red: 6.0/255, green: 46.0/255, blue: 107.0/255, alpha: 1.0)
titleLabel.text = "Login"
}else{
//user is login
cell?.contentView.backgroundColor = UIColor.redColor()
titleLabel.text = "Logout"
}
}
return cell!
}
but i am getting nil cell. i set Datasource,Delegate,table connection.How to fix that?
Fixed by using following code. use tableviews delegate method willDisplayCell.
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 20
{
let titleLabel = cell.contentView.viewWithTag(100) as! UILabel
if(NSUserDefaults.standardUserDefaults().integerForKey("UserID") <= 0 ){
//logout
cell.contentView.backgroundColor = UIColor(red: 6.0/255, green: 46.0/255, blue: 107.0/255, alpha: 1.0)
titleLabel.text = "Login"
}else{
//user is login
cell.contentView.backgroundColor = UIColor.redColor()
titleLabel.text = "Logout"
}
}
}
Related
I understand that Firestore is asynchronous. I'm just having some trouble returning values for the cellForRowAt and numberOfRowsInSection methods. It's not returning any cells/rows because the return is outside the closure, but I cannot place the return inside of the closure. How do I go about circumventing this issue?
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//Return the count how many workouts exist for each date.
var counter = 0
Firestore.firestore().collection("/users/\(self.userIdRef)/Days/\(dayIdArray[section])/Workouts/").getDocuments { (querySnapshot, error) in
if error == nil && querySnapshot != nil {
counter = querySnapshot?.count ?? 0
}
}
return counter
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: self.cellID, for: indexPath)
Firestore.firestore().collection("/users/\(self.userIdRef)/Days/\(dayIdArray[indexPath.section])/Workouts/").getDocuments { (querySnapshot, err) in
if let err = err
{
print("Error getting documents: \(err)");
}
else
{
let firstValue = querySnapshot!.documents[indexPath.row]
let myData = firstValue.data()
let myDayRef = myData["workout"] as? String ?? ""
cell.textLabel?.text = "\(myDayRef)"
cell.textLabel?.textAlignment = .center
cell.accessoryType = .disclosureIndicator
cell.layer.backgroundColor = UIColor.clear.cgColor
cell.textLabel?.textColor = UIColor(red: 0.1333, green: 0.2863, blue: 0.4, alpha: 1.0)
cell.textLabel?.font = UIFont(name: "HelveticaNeue", size: 20)
}
}
return cell
}
You should reload your tableView after filling the cells as explained here. Something like this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: self.cellID, for: indexPath)
Firestore.firestore().collection("/users/\(self.userIdRef)/Days/\(dayIdArray[indexPath.section])/Workouts/").getDocuments { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)");
} else {
let firstValue = querySnapshot!.documents[indexPath.row]
let myData = firstValue.data()
let myDayRef = myData["workout"] as? String ?? ""
cell.textLabel?.text = "\(myDayRef)"
cell.textLabel?.textAlignment = .center
cell.accessoryType = .disclosureIndicator
cell.layer.backgroundColor = UIColor.clear.cgColor
cell.textLabel?.textColor = UIColor(red: 0.1333, green: 0.2863, blue: 0.4, alpha: 1.0)
cell.textLabel?.font = UIFont(name: "HelveticaNeue", size: 20)
tableView.reloadData()
}
}
return cell
}
Notice the tableView.reloadData().
SO, UICollectionView is being a real pain for me right now. Consider I have a UIViewController which has a UICollectionView embedded in it. Well each cell of the CollectionView is almost the entire width of the UIViewController. And each cell contains some buttons and images. When I select one button and tend to make the button retain its state, the CollectionView reuses the cell and kind of duplicates the cell states across other cells as well. However when I try to put the cells in an array and kind of want to check the states of cells in that array, the cellForItemAt method overwrites those cells. I am so confused. Please help. Even prepareForReuse in UICollectionViewCell isn't helping. Here is some code:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! AddressCollectionViewCell
cell.shopAddressDetailLbl.text = ""
cell.addressObj = addresses[indexPath.row]
cell.configureCellForAddress(cell.addressObj)
cell.cellTag = indexPath.row
cell.cellDelegate = self
if addressCells.contains(cell) == false {
addressCells.append(cell)
} else {
if cell.isAddressConfirmed == true {
cell.confirmAddress.setTitle("CONFIRMED", for: .normal)
cell.confirmAddress.isEnabled = false
cell.confirmAddress.backgroundColor
= UIColor(red: 0, green: 100/255, blue: 0, alpha: 1)
addressCells[indexPath.row] = cell
}
}
return cell
}
extension AddressesCollectionViewController: AddressCollectionViewCellDelegate {
func confirmBtnPressed(confirmAddressObj: Address, cell:AddressCollectionViewCell) {
for cellTemp in addressCells {
if cellTemp == cell && cellTemp.isAddressConfirmed == false {
if let dele = addressCollectionViewDelegate {
cellTemp.isAddressConfirmed = true
dele.configureCellsAccordingToChanges(cell: cellTemp)
}
}
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
cellTag = 0
confirmAddress.setTitle("Confirm Address", for: .normal)
confirmAddress.backgroundColor = APP_UNIVERSAL_COLOR
confirmAddress.isEnabled = true
}
Any help is more than appreciated.
🙌 #Vadian, #Abu Ul Hassan 👍
Pretty slick! To others who need help in this regard. Vadian suggested in comments that I just need to update and monitor my model and thats exactly what I did. SO here it goes:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! AddressCollectionViewCell
cell.shopAddressDetailLbl.text = ""
cell.addressObj = addresses[indexPath.row]
cell.configureCellForAddress(cell.addressObj)
cell.cellTag = indexPath.row
cell.cellDelegate = self
if addresses[indexPath.row].isConfirmed! == true {
cell.confirmAddress.setTitle("CONFIRMED", for: .normal)
cell.confirmAddress.isEnabled = false
cell.confirmAddress.backgroundColor = UIColor(red: 0, green: 100/255, blue: 0, alpha: 1)
} else {
cell.confirmAddress.setTitle("Confirm Address", for: .normal)
cell.confirmAddress.isEnabled = true
cell.confirmAddress.backgroundColor = APP_UNIVERSAL_COLOR
}
return cell
}
extension AddressesCollectionViewController: AddressCollectionViewCellDelegate {
func confirmBtnPressed(confirmAddressObj: Address, cell:AddressCollectionViewCell) {
if confirmAddressObj.isConfirmed! == false {
if let dele = addressCollectionViewDelegate {
cell.isAddressConfirmed = true
dele.configureCellsAccordingToChanges(cell: cell)
}
}
}
}
And its ALIVE :D
I am creating a polling app with several different polls to select from. To do this I created a View Controller in the storyboard called PollSelectorTableViewController. It looks like this:
It is a static table cell and when I press it, it transitions to SubPollsTableViewController. This however, is not part of the storyboard.
This is the code within the SubPollsTableViewController (excluding where I am having the problem) and it works perfectly:
import UIKit
class SubPollsTableViewController: UITableViewController {
var polls:[String]
static var pollSelectOptions:[String] = [""]
let blueColor = UIColor(red: 0.0, green: 122.0/255.0, blue: 1.0, alpha: 1.0)
let redColor = UIColor(red: 1.0, green: 41.0/255.0, blue: 0.0, alpha: 1.0)
init(setPolls:[String]){
self.polls = setPolls
print(self.polls)
super.init(style: .plain)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return polls.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(indexPath)
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
if (indexPath.row == 0){
cell.textLabel?.text = polls[indexPath.row]
cell.textLabel?.font = cell.textLabel?.font.withSize(50.0)
cell.textLabel?.textAlignment = NSTextAlignment.center
}
else if (indexPath.row == (polls.count - 1)){
cell.textLabel?.text = polls[indexPath.row]
cell.textLabel?.textColor = redColor
cell.textLabel?.font = cell.textLabel?.font.withSize(25.0)
cell.textLabel?.textAlignment = NSTextAlignment.center
}
else{
cell.textLabel?.text = polls[indexPath.row]
cell.textLabel?.textColor = blueColor
cell.textLabel?.font = cell.textLabel?.font.withSize(21.0)
cell.textLabel?.textAlignment = NSTextAlignment.center
}
return cell
}
*note that the code is not finished
From here I try to make it that when a cell is clicked on, it changes to a View Controller (named PollViewController) that I defined in the storyboard. Here is an image of the View Controller:
What I did to try and get it to work is:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print (indexPath)
if(polls[indexPath.row] == "Background Checks"){
print("Background Checks Accessed")
SubPollsTableViewController.pollSelectOptions = ["Increase Drastically","Increase Slightly","Stay the Same","Decrease Slightly","Decrease Drastically"]
actioncall()
}
}
func actioncall() {
if let PVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PollViewController") as? PollViewController {
PVC.selectOptions = SubPollsTableViewController.pollSelectOptions
self.present(PVC, animated: true, completion: nil)
}
}
This should cause the SubPollsTableViewController to change to the PollViewController, but instead my exception breakpoint stops it at
self.present(PVC, animated: true, completion: nil)
Letting it run anyway brings up "libc++abi.dylib: terminating with uncaught exception of type NSException"
Why am I getting this error? How do I fix this problem so that they switch? The text in the PollViewController is just placeholder text by the way. I got the code based off of several different sources within and outside Stack Exchange but it still isn't working.
Your code to show the PollViewController is correct, this types of exceptions are related with outlets connection so you can verify if your outlets are connected correctly in your PollViewController.
I have a tableview inside a viewcontroller. I have a little function to select all rows in the tableview. When I first display the viewcontroller and hit the select all button the function does not work. However, if I firstly select a row and then press the select all button, the function works as it should and all rows are selected. I'm not sure why this is happening. The tableview's delegate and data source have been set up in the storyboard.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:myTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! myTableViewCell
cell.accessoryType = .None
if allJobsSelected {
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.contentView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.selectedBackgroundView = bgColorView
cell.accessoryType = .Checkmark
cell.highlighted = false
cell.selected = true
// cell.accessoryType = .Checkmark
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.None)
self.tableView(self.tableView, didSelectRowAtIndexPath: indexPath)
}
var job: Jobs!
job = jobs[UInt(indexPath.row)] as! Jobs
cell.reports2JobTitle.text = job.jobTitle
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.allowsMultipleSelection = true
if let cell:myTableViewCell = tableView.cellForRowAtIndexPath(indexPath) as? myTableViewCell {
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.contentView.backgroundColor = UIColor(red: 250/255, green: 182/255, blue: 17/255, alpha: 1)
cell.selectedBackgroundView = bgColorView
cell.accessoryType = .Checkmark
cell.highlighted = false
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.Bottom)
}
}
#IBAction func doSelectAll(sender: UIBarButtonItem) {
let totalRows = tableView.numberOfRowsInSection(0)
for row in 0..<totalRows {
tableView.selectRowAtIndexPath(NSIndexPath(forRow: row, inSection: 0), animated: false, scrollPosition: UITableViewScrollPosition.None)
}
}
It would probably be a good idea to move this line:
self.tableView.allowsMultipleSelection = true
to your viewDidLoad
You are not guaranteed that the didSelect is called immediately -- it might be that each select is turning off the previous one and then a single didSelect is being called on the last row.
Anytime I tap segmented control in UICell, immediately some other cell gets this segmented control in the same position. It looks like segmented control recognizes that not only this particular one was tapped but also some other one in other cell.
Have you ever encountered issue like this?
this is my custom cell implementation:
class QuestionYesNoCustomCellTableViewCell: UITableViewCell {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var segmentControl: ADVSegmentedControl!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
segmentControl.items = ["TAK", "NIE"]
segmentControl.font = UIFont(name: "Avenir-Black", size: 12)
segmentControl.borderColor = UIColor.grayColor()
segmentControl.selectedIndex = 1
segmentControl.selectedLabelColor = UIColor.whiteColor()
segmentControl.unselectedLabelColor = UIColor.grayColor()
segmentControl.thumbColor = UIColor(red: 46.0/255.0, green: 204.0/255.0, blue: 113.0/255.0, alpha: 1.0)
segmentControl.addTarget(self, action: "segmentValueChanged:", forControlEvents: .ValueChanged)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func segmentValueChanged(sender: AnyObject?){
if segmentControl.selectedIndex == 0 {
segmentControl.thumbColor = UIColor(red: 231.0/255.0, green: 76.0/255.0, blue: 60.0/255.0, alpha: 1.0)
segmentControl.selectedLabelColor = UIColor.whiteColor()
segmentControl.unselectedLabelColor = UIColor.grayColor()
}else if segmentControl.selectedIndex == 1{
segmentControl.thumbColor = UIColor(red: 46.0/255.0, green: 204.0/255.0, blue: 113.0/255.0, alpha: 1.0)
segmentControl.selectedLabelColor = UIColor.grayColor()
segmentControl.unselectedLabelColor = UIColor.whiteColor()
}
}
Also, I think it is worth to provide my tableView delegate methods implemented
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (dict2 as NSDictionary).objectForKey(dictKeysSorted[section])!.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: QuestionYesNoCustomCellTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! QuestionYesNoCustomCellTableViewCell
cell.questionLabel.text = (dict2 as NSDictionary).objectForKey(dictKeysSorted[indexPath.section])![indexPath.row] as? String
if indexPath.row % 2 == 0 {
cell.backgroundColor = UIColor(red: 245.0/255.0, green: 245.0/255.0, blue: 245.0/255.0, alpha: 1.0)
}
else {
cell.backgroundColor = UIColor(red: 225.0/255.0, green: 225.0/255.0, blue: 225.0/255.0, alpha: 0.7)
}
return cell
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return dictKeysSorted[section]
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCellWithIdentifier("CellHeader") as! CustomHeaderCell
headerCell.backgroundColor = UIColor(red: 20.0/255.0, green: 159.0/255.0, blue: 198.0/255.0, alpha: 1.0)
headerCell.headerLabel.text = dictKeysSorted[section]
return headerCell
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 70.0
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return dictKeysSorted.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 110.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
To recap what the problem actually is: In every tableView cell there is a segment control. When I change the position of the one located in first row, I scroll down and see that segment control in row 5 also has been moved despite the fact it should be in the default position.
Thanks in advance
EDIT:
I recognized one of the biggest problem in solutions below - they are good as long as you don't use section in tableView. The thing is, from what I have discovered right now, in each sections the rows are counted over from 0.
This might be the cause when you are using reusing the cells, when you scroll the cell you changed will be shown again for another row.
To avoid this when you reuse cell make sure you reset the data in it also
In your case you have to check if the segmented value is changed then change the segmented control value also in cellForRowAtIndexPath
Please let me know if you need more explanation.
Here is a sample project for you sampleTableReuse
It's because of reusable nature of UITableViewCells. You must keep track in your datasource selected segment index for each row. Then in cellForRowAtIndexPath you must set it properly for each cell.
example
define somewhere an enum with possible Answers:
enum Answer {
case Yes
case No
case None
}
then define and init your answers' array:
var answer = [Answer](count: numberOfQuestions, repeatedValue: .None)
in your cell's implementation add a method to configure a cell with Answer
func setupWithAnswer(answer: Answer)
{
var selectedIdex = UISegmentedControlNoSegment
switch answer {
case .Yes: selectedIdex = 0
case .No: selectedIdex = 1
default: break
}
self.segmentedControl.selectedSegmentIndex = selectedIdex
}
and finally, in your cellForRowAtIndex do after dequeuing
cell.setupWithAnswer(answer: self.answers[indexPath.row])