I have a custom cell with a UITextView in it and outlet for that UITextView is in the customCell file.
Now in my viewController I have tableView and I create and add that custom cell into my table.
After this I can't access UITextView and get its data as its outlet in the customCell file. I can't move the outlet to my viewController as I need it there.
How can I do this (access the UITextView in my viewController)?
You can set that delegate of cell's textView with your viewController, First set its delegate inside your cellForRowAtIndexPath
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! CustomTableCell
cell.textView.delegate = self
cell.textView.tag = indexPath.row //In case you have multiple textView
return cell
}
Now you can get this textView inside its UITextViewDelegate method.
func textViewDidBeginEditing(textView: UITextView) {
print(textView.text)
}
You need to declare a local variable in your viewController to get the data of your UITextView. Then implement the tableViews delegate method
//this is your local variable declared in viewCOntroller
var myTextViewText: String?
//And this is your delegate method
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! YourCell
myTextViewText = cell.textView.text //here you will get the text of your cell's textView
}
Related
I have a DynamicTableView and every Cell has an ImageView. How do I make an Action with knowing the indexPath.row?
The only way I know is to make a TapGestureRecognizer – that works but I then don't know which row I clicked.
So I need something like DidSelectRowAt from the TableView:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
This Action should only happen when I press the ImageView not the whole Row, therefore I can't use DidSelectRowAt from the TableView.
Thats what I did right now:
class DownloadsViewController: UITableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tap = UITapGestureRecognizer(target: self, action: #selector(DownloadsViewController.tappedMe))
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DownloadsViewCell
cell.fileInfo.image = UIImage(named: "detail1")
cell.fileInfo.addGestureRecognizer(tap)
cell.fileInfo.isUserInteractionEnabled = true
}
func tappedMe(){
print(arrayDocuments(IndexPath.row))
}
}
My whole DownloadViewContoller Class Code is here
My DownloadViewCell Screenshot is here
Does anyone have an Idea?
Thank you!
Add a property to your cell: var indexPath: IndexPath.
In cellForRowAtIndexPath: do cell.indexPath = indexPath
In your cell subclass add tapGestureRecognizer to UIImageView which triggers method in cell subclass.
Make a delegate protocol for your cell:
protocol YourCellDelegate: class {
func imagePressed(indexPath: IndexPath)
}
Make your ViewController adopt this protocol.
In your cell subclass add property weak var delegate: YourCellDelegate?
In cellForRowAtIndexPath: do cell.delegate = self
In cell tapRecognizer selector call delegate method delegate?.imagePressed(indexPath: indexPath)
In your viewController you'll receive imagePressed method call with indexPath as an argument.
Just set the ImageView like you had before, and then just add a blank Button over it and use the method from the Answer from Ilya V. with the IBAction
Did you try to get cell by
recognizer.view
on tap gesture method and
func indexPath(for cell: UITableViewCell) -> IndexPath?
returns an index path representing the row and section of a given table-view cell.
Here is a solution that uses a custom UIImageView subclass.
Create a subclass of UIImageView - MyImageView (or something else more appropriate)
Create a delegate for the subclass - MyImageViewDelegate
Add a delegate method called myImageViewTapped(imageView: MyImageView)
Override the touchesEnded method to call the delegate method
Add a property in MyImageView called indexPath that stores the index path of the cell that this image view is in.
In your table cells, use MyImageView instead of a regular UIImageView.
Set the delegate of the MyImageView to self i.e the VC.
Set isUserInteractionEnabled to true
In cellForRowAtIndexPath, set the image view's indexPath to the indexPath parameter
Now implement the delegate method and in the method, you will know which image view is tapped by accessing indexPath!
You can use property "tag" imageView to save indexPath.row and use it later in the selector
class DownloadsViewController: UITableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DownloadsViewCell
cell.fileInfo.image = UIImage(named: "detail1")
cell.fileInfo.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(tappedMe(_ :)))
cell.fileInfo.addGestureRecognizer(tap)
}
#objc func tappedMe(_ sender: AnyObject){
print("Tap to imageView in cell No. - \(sender.view.tag)")
}
}
I have a UITableView Controller class, and inside of it is a String array.
The Table view has 1 cell prototype and in it a UICollectionView with 1 cell prototype.
The CollectionView is populated by passing the array into the tableview cell, which is a UICollectionView Delegate and DataSource.
When I make changes to the array inside the TableViewController, and call self.tableView.reloadData(), the CollectionView inside the cell does NOT update.
How do I fix this?
Thank you
EDIT:
Code in TableViewController:
#IBAction func addToArrayAction(sender: AnyObject) {
self.testArray.append("Ant-Man")
self.tableView.reloadData()
}
var testArray = ["Guardinas", "Iron Man", "Avengers", "Captain America"]
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("collectionContainerCell", forIndexPath: indexPath) as! TableViewCell
cell.testArray = self.testArray
return cell
}
Code in UITableViewCell:
var testArray: [String]?
override func awakeFromNib() {
super.awakeFromNib()
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = self.collectionView.dequeueReusableCellWithReuseIdentifier("collectionViewCell", forIndexPath: indexPath) as! CollectionViewCell
cell.movieTitleLabel.text = self.testArray![indexPath.item]
cell.movieYearLabel.text = "2016"
return cell
}
Please try to call reloadData of UICollectionView on every update in array.
If you are using only one cell in UITableView then you can reload in cellForRowAtIndexPath method of UITableView else you can can call after calling of reloadData of UITableView.
After I added cell.collectionView.reloadData(), CollectionView scrolling is so slow in my project. How to solved that kind of problem.
I've got a tableView in the ViewController & an array called toDo, in the TableView I've a cell and in the cell I got textView.
the textView is editable (The user can change the text in the textView).
After the user changes the text - I want the cell to save it to the toDo array, but whenever I reloaddata the text disappears.
Here is what I tried:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: TableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath:indexPath) as! TableViewCell
cell.textField.text = toDo[indexPath.row]
cell.textField.delegate = self
return cell
}
**I have a got a test button that whenever I click it reload data.
Try this out - set the tag on the text field and implement textFieldDidEndEditing: to update your model before reloading the table view.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: TableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath:indexPath) as! TableViewCell
cell.textField.text = toDo[indexPath.row]
cell.textField.tag = indexPath.row
cell.textField.delegate = self
return cell
}
func textFieldDidEndEditing(textField: UITextField) {
toDo[textField.tag] = textField.text
}
I think that the problem is that, whenever the system needs to re-render the cell, the method func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) is called; that happens before your text view has a chance to save its content in the data model. In your case every time you press the button. I assume you save the content of the text field using optional func textFieldDidEndEditing(_ textField: UITextField) delegate method. You can add a println("SAVING") in such method, and a println("RE-RENDERING CELL") in the tableView(...) method and see the what the sequence of events is. Nots sure if this could help, but I would try that.
I have a custom class for a table cell that is connected to a switch within the table cell (with an action) and I want to be able to to communicate to the TableViewController that the action happened as well as the path of the cell. The way that initially came to mind was if I could use some function in UITableViewCell to get the TableViewController of the table the cell is part of, as my custom class is (rather obviously) a subclass of UITableViewCell. Please tell me if I'm missing something.
To get a reference to the containing view controller, I add a weak property on the cell subclass.
#property (nonatomic, weak) UITableViewController *viewController;
You can assign this value in cellForRowAtIndexPath:
For accessing each cell in TableView
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as YourTableViewCell
cell.mainTextLabel.text = self.venueService.mainCategoriesArray()[indexPath.row]
return cell
}
For getting selected cell in TableView
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell;
print(currentCell)
}
Reaching from TableViewCell to TableView
self.superview //// self is TableViewCell and its superview represents TableViewController
hope that helps
You should make the ViewController the target of the switch action.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SwitchCell", forIndexPath: indexPath) as! SwitchTableViewCell
cell.onSwitch.addTarget(self, action: Selector("cellSwitchDidChange:"), forControlEvents: .ValueChanged)
cell.label.text = "This is a Switch"
return cell
}
func cellSwitchDidChange(sender: UISwitch) {
let origin = sender.convertPoint(CGPointZero, toView: tableView)
let indexPath = tableView.indexPathForRowAtPoint(origin)!
// do something
}
I'm working in Swift with one TableViewController with one prototype cell. The cell has a reuse identifier specified in the storyboard, but it never dequeues properly. I always get the "unexpectedly found nil while unwrapping an Optional value" error.
I've properly registered the class as follows:
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "myNewCell")
The offending code is:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("myNewCell") as UITableViewCell
let textField = cell.viewWithTag(123) as UITextField
textField.text = "test"
return cell
}
I feel like I've tried everything here but it never properly gives a cell with that identifier. Even using the fallback (if nil, create a cell with that identifier) still gives the error. It's definitely having trouble getting a cell with that identifier, but it's registered and specified in the storyboard... Any assistance is greatly appreciated!
When using cell prototypes, you do not call registerClass. The storyboard does that for you. If the cell prototype has its identifier specified, then just all dequeueReusableCellWithIdentifier and it should find your cell prototype without incident.
I'd suggest checking the spelling/capitalization of the identifier in storyboard and make sure it is identical to what is used in cellForRowAtIndexPath code.
I notice that you are trying to access a cell's label using a tag number. Nowadays, when dealing with custom cell layouts, we'd generally create our own table view subclass, e.g.:
// CustomTableViewCell.swift
import UIKit
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var customTextField: UITextField! // note, I would use something other than textLabel to avoid confusion with base class
}
We'd then go to our cell prototype and specify its base class:
We'd also set the cell prototype's identifier:
We'd then hook up the outlet between the cell prototype and our custom class #IBOutlet.
Having done all of that, the cellForRowAtIndexPath would be:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myNewCell", forIndexPath: indexPath) as CustomTableViewCell
cell.customTextField.text = "Row \(indexPath.row)"
return cell
}
If dequeueReusableCellWithIdentifier is giving you problems then just don't use it.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = UITableViewCell()
let textField = cell.viewWithTag(123) as UITextField
textField.text = "test"
return cell
}