Swift: How to access `UITableViewCell` from other UI Function - swift

I have a UITableView which have some section inside. In one of the section, there is a UIDatePicker. I try to implement the reset date to my datePicker but i get some litle problem. I need to access cell.accessoryType from my UIDatePickerAction . Below my snippet code :
#IBAction func datePickerClaimedAction(_ sender: UIDatePicker) {
self.dateClaimedBy = datePickerClaimed.date
self.labelDateClaimed.text = programProperties.showDateFormatter.string(from: datePickerClaimed.date)
self.buttonDeleteDateClaimed.isHidden = false
// some code to access `cell.accessory`
}
I read some question about this but its still not work. Any other suggest or answer will help for me. Thanks in Advance

I solved it.
First, i make a variable var indexRow: IndexPath?. And then. I cast the indexPath from
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { .. } function.
I need cell from section 2 with row 4 so i add case like:
if indexPath.section == 2 && indexPath.row == 4 {
self.indexRow = indexPath
}
In my DatePicker Action, I use this
let cell = tableView(tableView, cellForRowAt: indexRow!)
So I can get access to cell.accessoryType = .disclosureIndicator to specific cell. Thanks in Advance

Related

Textfield values deleted when scrolling tableview?

I have tableview cell with a textfield but when I add new row and scroll tableview up or down disappeared textfield values deleted. I make lots of research about that previous question about that in 2015 and its not answered correctly. How can I fix this issue? How can I use textfield delegate method if it is working for this? Here my code:
var i = 0
while i <= taskArrForRead.count {
let indexPath = IndexPath(row: i, section: 0)
let cell = self.tableView.cellForRow(at: indexPath) as? taslakDuzenlemeCell
if let item = cell?.taslakTextField.text! {
arrayOfNames.append(item)
}
i = i + 1
}
In this code I get all textfield values from tableview but if tableview scroll disappeared values turn with default values. How can I fix it? Thanks.
Here my tableview code:
extension taslakOlusturmaController: UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return taskArrForRead.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "taslakCell", for: indexPath) as! taslakDuzenlemeCell
cell.taslakTextField.text = taskArrForRead[indexPath.item]
cell.taslakTextField.delegate = self
return cell
}
func textFieldDidEndEditing(_ textField: UITextField) {
print(textField.text!)
self.arrayOfNames.append(textField.text!)
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "taslakCell", for: indexPath) as! taslakDuzenlemeCell
cell.taslakTextField.text = taskArrForRead[indexPath.item]
print(arrayOfNames[indexPath.item])
}
}
With textfield delegate method I can get deleted textfield values but I can't bring it again to textfield. User can't see value after scroll again also I can get deleted values with didEndDisplaying cell method too.
You could use the method PrepareForReuse to set the text back when the cell recreated again.

Trying to bind an output to my tableviewCell UI Element in RxSwift

I have an output that lives in my VM and based on some change I want my textfield that resides in my custom tableviewCell to change in some way. I am unsure about how to have my UItextfield that lives in the tableviewcell bind to my output.
let index = IndexPath(row: 0, section: 0)
if let cell = tbl.cellForRow(at: index) as? TableViewCell {
print(cell.textF.text)
// Do whatever you want
}
I am not sure when you want to get the data, but if you want to do this when the user touches the cell, just implement the following method of UITableViewDelegate:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? YourTableViewCellClass {
let cellLabelText = cell.yourTextField.text
// Do whatever you want with cellLabel
}
}

Index out of range for indexPath swift

I am making an app that requires the user to tap on multiple cells in order to select them. when they tap on a cell, a .Checkmark accessory item will appear. For some reason though whenever I try and get to that VC the app crashes and I get the following error messages on line 8(if !checked[indexPath.row]):
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: InstrumentTableCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? InstrumentTableCell
cell.configurateTheCell(recipies[indexPath.row])
if !checked[indexPath.row] {
cell.accessoryType = .None
} else if checked[indexPath.row] {
cell.accessoryType = .Checkmark
}
return cell
}
and this is my working checked method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
if cell.accessoryType == .Checkmark {
cell.accessoryType = .None
checked[indexPath.row] = false
} else {
cell.accessoryType = .Checkmark
checked[indexPath.row] = true
}
}
}
Your problem is that you only store items in your checked array when tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) is called. However, that method is only called when you actually select a row.
tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) on the other hand is called each and every time you need to render a new table cell.
So when you in cellForRowAtIndexPath asks:
if !checked[indexPath.row]
then you can not be sure that checked actually contains anything. For instance the first time you start rendering your cells, your checked array does not contain any values and therefore it crashes when you ask it for a value on a position that it does not have a value for.
One solution could be to initialize your checked array to contain all false values. I'm guessing you have some model array called recipies so you could do something like:
for (index, _) in recipies.enumerate() {
checked.append(false)
}
Or as #AaronBrager suggests in the comments below (which is way prettier :))
checked = Array(count:recipies.count, repeatedValue:false)
that way you are sure that your checked array is properly initialized with the same number of elements as you have recipies.
Another option could be to let the individual elements in recipies know whether or not they are checked.
Hope this makes sense and helps you.

How to set uitableviewcellselectionstyle.none to static cells?

Sorry I really cant find this anywhere.
I need to set my selection style to none so that the rows dont highlight when i click on it. Also, i need rows to be selectable as I have some rows which needs expanding and collapsing. I know the piece of code is UITableViewCellSelectionStyle.None but I have no idea where I can implement it. Thanks!
EDIT ADDED IN CODES
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 7
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
// Set height for date picker
if indexPath.section == 0 && indexPath.row == 2 {
let height:CGFloat = datePicker.hidden ? 0.0 : 216.0
return height
}
return super.tableView(tableView, heightForRowAtIndexPath: indexPath)
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Expanding and collapsing date picker
UITableViewCellSelectionStyle.None
let datePickerIndexPath = NSIndexPath(forRow: 1, inSection: 0)
if datePickerIndexPath == indexPath {
datePicker.hidden = !datePicker.hidden
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.tableView.beginUpdates()
// apple bug fix - some TV lines hide after animation
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.tableView.endUpdates()
})
}
}
The codes are mainly for the datepicker that i have implemented. everything works fine but clicking on the cell highlights the whole row in the default selection color.
Hard to know where to best implement it without seeing your code, but you can definitely put it in your cellForRowAtIndexPath when you dequeue/initialize your cell. Just call yourCell.selectionStyle = .None before return yourCell
cell.selectionStyle = .None
When you write the code after equal(=) , just press dot(.) so that many type of functionality will be pop up like this-
And for your second issue just put some value in array to check that is working correctly or not.
I have had the same issue, the solution for me was:
self.tableView.allowsSelection = true
in storyboard, manually select all the static cells and change selection from "default" to "none"
for those cells are allowed to be selected, change the selection to "Default".
It would appear as if only some cells can be selected.
You can still handle selection for those exclusive cells in didSelectRowAt by checking indexPath.
Hope that helps.
Just found a way to programmatically insert the selection style setting for static cells, instead of using storyboard:
In viewWillAppear, use:
tableView.cellForRow(at: yourIndexPath1)?.selectionStyle = .none
tableView.cellForRow(at: yourIndexPath1)?.selectionStyle = .none
...

How to add a custom cell to a dynamicly generated tableview?

Nearly during a week i'm trying to figure out how i can append a static-/custom tableviewcell to a dynamically generated tableview. I'm populating the cells based on the data i'm getting from the database. Basically what i'm trying to accomplish is like the following picture from the app ClassDojo:
As you may know and see, you can add add as many groups as you want with the ClassDojo app, but the latest cell, in this case Voeg een nieuwe klas toe, will always stay at the bottom of the tableview. That's exactly what i'm trying to do.
What i tried to do till this moment is trying to calculate the latest cell in the tableview and trying to append my custom cell, but unfortunately i couldn't get my head around it.
I would really appreciate if someone can help me out with this.
Thanks in advance.
Please let me know if you guys need any code.
---------EDITED POST---------
I did accomplish to assign my custom cell thanks to #Slayter, but now i'm facing with the problem that my custom cell is immediately overwritten by my dynamically created cells (with Alamofire).
Any help would be appreciated.
ClassDojo iOS Engineer here! More than happy to share how we do this.
Like Slayter mentioned, we do
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count + 1 // Add one for your custom cell
}
But in addition we also do the following:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = nil;
if self.indexIsForCustomCell(indexPath) {
cell = tableView.dequeueReusableCellWithIdentifier(CustomCell.reuseIdentifier)
// Additional configuration
} else {
cell = tableView.dequeueReusableCellWithIdentifier(RegularCell.reuseIdentifier)
// Additional configuration
}
return cell
}
Where CustomCell looks something like this (not exact):
class CustomCell: UITableViewCell {
static let reuseIdentifier = "CustomCell"
// More code
}
And regular cell looks like:
class RegularCell: UITableViewCell {
static let reuseIdentifier = "RegularCell"
// More code
}
The reason your dynamic cells are getting overwritten is because of the line
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as UITableViewCell
Notice that you are using the same cellIdentifier regardless of whether or not it is the custom cell or the regular cells. This means that most likely you are doing the following:
self.tableView.registerClass(RegularCell.class, forIdentifier: "new group")
self.tableView.registerClass(CustomCell.class, forIdentifier: "new group")
When you should be doing:
self.tableView.registerClass(RegularCell.class, forIdentifier: RegularCell.reuseIdentifier)
self.tableView.registerClass(CustomCell.class, forIdentifier: CustomCell.reuseIdentifier)
OR
self.tableView.registerClass(RegularCell.class, forIdentifier: "regularCellReuseIdentifier")
self.tableView.registerClass(CustomCell.class, forIdentifier: "customCellReuseIdentifier")
By using the same identifier key, you are telling the UITableView to treat both cells as the same type. So when it needs to reclaim memory for a new cell being drawn on screen, it's going to use RegularCell and CustomCell interchangeably.
Hope this helped and thanks for checking out our App!
================= EDIT =================
Realized that I forgot to add the indexIsForCustomCell method. Here it is:
func indexIsForCustomCell(indexPath : NSIndexPath) -> Bool {
if self.myData.count > 0 {
return indexPath.section == 0 && indexPath.row == (self.myData.count+1)
}
return indexPath.section == 0 && indexPath.row == 0
}
It's pretty simple. You just need to tell the tableView to expect one more cell than what is in your data source.
Example
In your numberOfRowsInSection method, you will have something like this:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count + 1 // Add one for your custom cell
}
Then in your cellForRowAtIndexPath method you just need to add some custom logic for that indexPath
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as UITableViewCell
if indexPath.row < myData.count {
// configure cell as normal
} else {
// Add your custom cell logic here
}
return cell
}