How to change an UIImageView into a custom cell - swift

I have an UIImageView in a custom cell (#IBOutlet var imageSquadra: UIImageView!) and in the TableViewController I initialize this imageView:
let squadra = DataManager.sharedInstance.arrayCori[indexPath.row]
cell.imageSquadra.image = squadra.sfondo1
Now I need to change the image touching up inside the cell with an other image, and return to the previous image touching up into an other cell.
Is it hard to do?
EDIT: or if was easier, would be fine apply a CAFilter like a shadow to the image.

On your tableview set multiple selection to NO:
tableView.allowsMultipleSelection = false
Then you want something like this on your TableViewController
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Store which indexPath has been selected in a global variable
tableView.reloadData()
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
tableView.reloadData()
}
In your cellForRow method you want something like...
cell.useSelectedImage(indexPath == storedIndexPath)
And finally in your custom cell class you want to add a method that does similar to this
func useSelectedImage(bool:useSelected)
{
self.myImage = useSelected ? "selectedImage" : "unselectedImage"
}
My Swift is a bit rusty... but you should be able to get the general idea from what I've done here

Related

Get cell label text when selected

I am trying the get the Text in Label ID nameLabel when i click on the cell
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
NSLog("You selected cell number: \(indexPath.row)!")
// get text in label nameLabel
}
With MVC you get this information from the model, not from the view.
Since you have the indexPath of the cell, you can use that to get the object that the cell is displaying from the data source.
I think you should have a data Model to keep all the data of your cells. When you select a cell, this function will be called
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// indexPath is the cell you selected
// you can use indexPath.row to get the data from the data Model
}
Your Data Model may be a dic or an Array / set and so on.
Assuming that you have a custom cell (In the code snippet I assumed that its class name is MyCustomCell), containing a label (In the code snippet I assumed that the label's name is nameLabel), it should something like:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
NSLog("You selected cell number: \(indexPath.row)!")
// get text in label nameLabel
let selectedCell = tableView.cellForRowAtIndexPath(indexPath) as! MyCustomCell
// here is the text of the label
let string = selectedCell.nameLabel.text
}

How to modify a custom cell inside of DidSelectRowAtIndexPath

A custom cell class has the override func layoutSubviews() where the detailTextLabel of each cell is given the title "Jim". Upon clicking on DidSelectRowAtIndexPath, is there a way to change the detail text of the cell permanently(to stop the cell from constantly making the detail Jim), to let's say "Bob"?.
//This function is in the custom cell UserCell
class CustomCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
detailTextLabel?.text = "Jim"
}
///........
}
//In the viewController with the tableView outlet
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//.....
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellId, forIndexPath: indexPath) as! CustomCell
//......
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
/* Code I need to convert the detailTextLabel.text to equal "Bob" upon clicking on certain cell */
}
The cell itself shouldn't be used to hold state for any data, but only to display it. Create a mutable array property on the controller to hold the underlaying data (strings). Set the new cells' text properties by reading this array, and in tableView:didSelectRowAtIndexPath: change the value in the array at the index for "Bob" to "Jim". Whenever the tableView reloads it will now read the updated value from the dataSource.
In addition to the UITableViewDelegate protocol also study the UITableViewDataSource protocol. By default the UITableViewController class conforms to both of these protocols and is assigned as each on its .tableView property (if you introspect its self.tableView.delegate and self.tableView.datasource values you will receive back the original UITableViewController). If you manually created your own tableview controller class that inherits from UIViewController, then you will need to assign both of these properties on the tableView in order for it to function properly.
Very simple, do it like this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
detailTextLabel?.text = "Bob"
}

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
}

Why can't I select TableView cells?

This is the flow of my app:
First, the TableView is set to hidden. There is a UITextField in the center of the screen. When the user types something and hits Go, this code is run:
self.view.layoutIfNeeded()
UIView.animateWithDuration(0.5, animations: {
self.textFieldConstraint.constant = -230
self.tableView.hidden = false
self.goButton.hidden = true
self.view.layoutIfNeeded()
}, completion: nil)
At this point, the tableview is populated. When a row is selected, I need to manipulate the data that is populating it.
However, absolutely nothing happens when I tap a cell.
What am I doing wrong?
My TableView code is here:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: SearchResultsTableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! SearchResultsTableViewCell
cell.label.text = searchResultsNames[indexPath.row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResultsUrls.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("HELLO")
}
And, I have set the dataSource and delegate properly.
I also want to clarify that the tableView populates and scrolls properly; it just won't do anything when I tap a cell.
Update:
I've discovered that for some reason, I can select the cells when I press and hold them. It is not what I want, so does anybody know how to fix this?
I have just used your code to create a simple table, selection is working fine and logging out HELLO as expected. Can you check the values of Selection in the attributes inspector? Here is mine, which has Selection set to Single Selection.
And here is the code I used for my simple table
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var searchResults = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
searchResults.append("Testing 1")
searchResults.append("Testing 2")
searchResults.append("Testing 3")
searchResults.append("Testing 4")
searchResults.append("Testing 5")
tableView.dataSource = self
tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath)
cell.textLabel?.text = searchResults[indexPath.row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("HELLO")
}
}
I also tried hiding and showing the tableView which made no difference on selection.
EDIT & SOLUTION:
In the comments below, we discovered that the issue is related to a tapGestureRecogniser on the view, This was identified by the op only being able to make a selection by holding a tap on the cell. The gesture has to fail before the selection can be made, the op managed to solve the problem by referring to this other SO Answer
if you use "tap" gesture, you can't select table cell. (but, if you click and drag to right a cell, you can select it.)
Check gesture first.
And if your code has self.tableView.allowsSelection = false, replace false to true or delete this line.
My problem has been caused by the tap gesture recognizer on the view controller itself (I had BaseTableViewController I was extending from). Probably it was interfering with the gesture recognizers of UITableView.
In your viewDidLoad, or wherever you set up your view, make certain that your table view even allows selections. That can be controlled with the allowSelection property.
Something like:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.allowsSelection = true
}
If you have a gesture recognizer, just type gestureRecognizer.cancelsTouchesInView = false
For me I was implementing another did select row method, so I erased it and typed "didSelect..." and selected the first one in the suggested methods, which is this for swift 3:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row #: \(indexPath)")
}
Try disabling and then enabling the user interaction Enabled property in the attribute inspector of your tableView
Looks something like this
I met the same problem as you and solved it by removing the below code
self.view.layoutIfNeeded()
you can try it.

Change UITableViewCell's height after tableview is shown

I have a tableview, and each tableviewcell has a button.
I want to change current cell height when cell's button clicked.
How can I do this? Thank you!
Create an array that holds your selected cells index's
var selectedCellIndexs : NSMutableArray = []
In didSelectRowAtIndexPath indexPath: NSIndexPath) function add:
self.selectedCellIndexs.addObject(indexPath)
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
Now in the tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath), all you need to do is check if the cell is part of the selected array and if it is return a different value.
if (self.selectedCellIndexs.containsObject(indexPath)) {
return selectedHeight
}
return notSelectedHeight
Remember to that if you want to deselect a cell you will need to remove the index path from your selectedCellIndexs when the cell is clicked.
NOTE: This is the basic work flow for when the user selects the cell to change the height. A bit more work is needed to get the cell from the button action.
You should store all tableviewcell's height in an NSMutableArray.
When user clicks on tableviewcell's button, update height in NSMutableArray.
After that reload your UITableView.
Hope this helps.
Globally declare a mutableArray.
var buttonPressedIndexPaths : NSMutableArray = []
in cellForRowAtIndexPath() method
cell?.button.tag = indexPath.row
cell?.button.addTarget(self, action: "onButtonAction:", forControlEvents: UIControlEvents.TouchUpInside)
copy paste these methods
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
if(buttonPressedIndexPaths.containsObject(indexPath))
{
return 90;//button pressed cell height
}
else
{
return 44;//normal
}
}
func onButtonAction(sender:UIButton)
{
var indexPath : NSIndexPath = NSIndexPath(forRow: sender.tag, inSection: 0)//section may differ based on ur requirement
if(buttonPressedIndexPaths.containsObject(indexPath))
{
buttonPressedIndexPaths.removeObject(indexPath)
}
else
{
buttonPressedIndexPaths.addObject(indexPath)
}
tableView.reloadData();
}