deselectRowAtIndexPath not doing anything - ios

I've been writing a small Swift app.
I'm now using a tableview and try to select a row, change an image and deselect the row.
My custom UITableViewCell class looks like this:
class SelectFriendTableViewCell: UITableViewCell {
#IBOutlet weak var friendNameLabel: UILabel!
#IBOutlet weak var friendSelectedImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
And my TableViewController has these functions:
Building the cells:
//Build the cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SelectFriend", forIndexPath: indexPath) as! SelectFriendTableViewCell
//Default image is unselected
cell.friendSelectedImage.image = UIImage(named: "unselected")
//Get the label text
cell.friendNameLabel.text = friendList[indexPath.row]
return cell
}
Do stuff when cell is selected (didSelectRowAtIndexPath)
//Cell was selected
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier("SelectFriend", forIndexPath: indexPath) as! SelectFriendTableViewCell
//Check wheter the cell is or not selected
if(cell.friendSelectedImage.image == UIImage(named: "unselected"))
{
//if it's unselected, select it and add the user to the invited list
cell.friendSelectedImage.image = UIImage(named: "selected")
//Add to the invited list, the label can't be null
invitedList += [cell.friendNameLabel.text!]
}
else if(cell.friendSelectedImage.image == UIImage(named: "selected"))
{
//if it's selected, unselect it and remove the user from the invited list
cell.friendSelectedImage.image = UIImage(named: "unselected")
//Find the invited in the array and remove it
for(var i=0; i < invitedList.count; i++)
{
if(invitedList[i] == cell.friendNameLabel.text!)
{
invitedList.removeAtIndex(i)
break
}
}
}
else
{
print("error geting image")
}
//Trying to deselect the row, doesn't seem to be working
tableView.deselectRowAtIndexPath(indexPath, animated: false)
}
What I'm seeing:
There's also the problem that the label is disappearing.

dequeueReusableCellWithIdentifier did not get the previous cell, you should use cellForRowAtIndexPath
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//get the cell,
let cell = tableView.cellForRowAtIndexPath(indexPath) as! SelectFriendTableViewCell
//do some work
}

Related

UIImages as icons in side push menu

I would like to preface this by saying I am new to iOS.
I am currently trying to create a side push menu that when clicked on has icons beside each menu item. I currently have the side push menu working with several menu items listed, however, I am really struggling trying to get the images beside each item.
I have written the side push menu and list items programmatically with the code below.
import UIKit
class SideMenuTable: UITableViewController {
let sideMenuImages = [UIImage(named: "Main"), UIImage(named: "Departments"), UIImage(named: "Deliveries"), UIImage(named: "Warehouse"), UIImage(named: "Help")]
var menu = [Menu]()
#IBOutlet weak var test: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Change Menu View"
menu = [
Menu(title: "Main"),
Menu(title: "Departments"),
Menu(title: "Deliveries"),
Menu(title: "Warehouse"),
Menu(title: "Help")
]
}
override func viewWillAppear(_ animated: Bool) {
if tableView.isHidden {
if let selectionIndexPath = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: selectionIndexPath, animated: animated)
}
} else if tableView.isFocused {
if let selectionIndexPaths = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: selectionIndexPaths, animated: animated)
}
}
super.viewWillAppear(animated)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menu.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "sideCell", for: indexPath)
let menuSide: Menu
// var image: UIImage = UIImage(named: ".png")
menuSide = menu[indexPath.row]
cell.textLabel!.text = menuSide.title
cell.textLabel?.textAlignment = .center
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if(indexPath.section == 1) {
if(indexPath.row == 3) {
dismiss(animated: true, completion: nil)
performSegue(withIdentifier: "Warehouse", sender: self)
} else {
NSLog("NO SELECTION AVAILABLE")
}
}
}
}
As you can see from the picture below.
]1
I have started to attempt to solve my problem by inserting a UIImage into the prototype cells.
However, when I connect the UIImage as an outlet into the code above I receive this error. (NOTE: in the code above the outlet is named test)
It is here where I am getting stuck.
I need to connect this outlet in order to add icons for the various menu items I have.
What am I missing?
Is there a different solution to this problem of creating icons for menu items?
Do I need to create a separate subclass?
You need to create a custom class for UITableviewcell where you need to create IBOutlet to imageview and label.
Now you can access it in your cellForRowAtIndexPath method.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "sideCell", for: indexPath) as YourCustomCell
let menuSide: Menu
var image: UIImage = UIImage(named: ".png")
menuSide = menu[indexPath.row]
cell.customLabel!.text = menuSide.title
cell.customLabel?.textAlignment = .center
Cell.imgViewName.image = image
return cell
}
Here customLabel and imgViewName is the name of your IBOutlets which you need to drag in you custom cell from storyboard also provide the name of custom cell in your storyboard by selecting that particular cell.
if your not want to create custom class then please set any tag on your uiimageview and uilabel and use as below
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let lblmenu : UILabel = cell.contentView.viewWithTag(12) as! UILabel
lblmenu.text = ArrMenuoption[indexPath.row] as? String
let img : UIImageView = cell.contentView.viewWithTag(11) as! UIImageView
img.image = UIImage.init(named: ArrMenuoptionimg[indexPath.row] as! String )
return cell }

When scroll table view content change

i have custom table view cell that having rating stars. i'm using https://github.com/hsousa/HCSStarRatingView for rating View.
there is my code for table view and cell view.
class RatingTableViewCell: UITableViewCell {
var value : CGFloat = 0.0
#IBOutlet weak var starRatingView: HCSStarRatingView!
#IBOutlet weak var titleLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
initStarRatingView()
starRatingView.addTarget(self, action: #selector(DidChangeValue(_:)), for: .valueChanged)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
private func initStarRatingView() {
var scalingTransform : CGAffineTransform!
scalingTransform = CGAffineTransform(scaleX: -1, y: 1);
starRatingView.transform = scalingTransform
starRatingView.emptyStarImage = #imageLiteral(resourceName: "strokStar")
starRatingView.halfStarImage = #imageLiteral(resourceName: "halfStar")
starRatingView.filledStarImage = #imageLiteral(resourceName: "fillStar")
starRatingView.allowsHalfStars = true
}
#IBAction func DidChangeValue(_ sender: HCSStarRatingView) {
self.value = sender.value
}
class RatingViewController: CustomViewController,UITableViewDelegate,UITableViewDataSource {
var values : [CGFloat] = [0.5,0.0,0.0,0.0,0.0,0.0,0.0]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RatingTableViewCell", for: indexPath) as! RatingTableViewCell
values[indexPath.row] = cell.value
cell.starRatingView.value = values[indexPath.row]
return cell
}
//MARK: _Table data source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
values.count
}
}
there is a problem when i scroll table view. dequeue Reusable Cell data is wrong. how can update value data for each cell?
The problem is that you are storing the value in the cell. Take a look at those two lines:
let cell = tableView.dequeueReusableCell(withIdentifier: "RatingTableViewCell", for: indexPath) as! RatingTableViewCell
values[indexPath.row] = cell.value
You dequeue a cell and assign it's value to values[indexPath.row]. The problems that you are noticing when scrolling are caused by the fact that the reused cell was previously used for a different indexPath, which means that their value (that you assign to values[indexPath.row]) is meant for its previous indexPath.
To fix that, I would advise getting rid of the value variable in RatingTableViewCell. Instead, define a protocol RatingTableViewCellDelegate that will be used to inform the RatingViewController about the new value.

How to hide a custom class label in a table view cell?

I have a table view controller with a custom cell and a CustomCell class. The code in the VC looks like this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Actual", for: indexPath as IndexPath) as! CustomCell
let mySeries = series[indexPath.row] as Series
cell.mySeries = mySeries
return cell
}
The CustomClass code is the following:
class CustomCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var seasonLabel: UILabel!
#IBOutlet weak var episodeLabel: UILabel!
var mySeries: Series! {
didSet {
nameLabel.text = mySeries.name
seasonLabel.text = mySeries.season
episodeLabel.text = mySeries.episode
}
}
Everything works fine so far. But I made the cells editable and the reordering symbol (three stripes) is now laying over my episodeLabel. So I'd like to hide this label until the editing is done. The editing function for reordering looks like this:
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to toIndexPath:IndexPath) {
let customCell = CustomCell()
customCell.episodeLabel.isHidden = true
let rowToMove = series[fromIndexPath.row]
series.remove(at: fromIndexPath.row)
series.insert(rowToMove, at: toIndexPath.row)
}
This is the part which is working. But when I create an instance of the CustomCell class (customCell) and insert this line in the function above I get an fatal error because nil is found:
customCell.episodeLabel.isHidden = true
Same behavior when I create a function hideEpisodeLabel() in the CustomCell class and call it from the VC. What am I doing wrong?
you must get cell instance in moveRowAt func
let customCell= tableView.cellForRowAtIndexPath(indexPath) as? SeriesCell
customCell.episodeLabel.isHidden = true
}
This additional method hides the label in the desired way:
override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
let customCell = tableView.cellForRow(at: indexPath) as? CustomCell
customCell?.episodeLabel.isHidden = true
return true
}
To bring the label back I have to reload the table view. This can be done by overriding the setEditing method:
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
if(!editing) {
tableView.reloadData()
}
}
Now, in the 'cellForRowAt indexPath:' method I only have to set the label to: isHidden = false.

how implement a button in customized UITableViewCell in Swift 3?

I tried to use this solution but is not working.
what I want i s a button in my customized cell that knows data from the array that is used from the tableview (later I'll apply it to CoreData), for example, print the value of the array that generated the tableview.
but I cannot understand how to do it
I have a customized cell class, where I tried to use both a button action or a outlet button (with tags):
import UIKit
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var myCellImage: UIImageView!
#IBOutlet weak var myCellLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
and a ViewController where is my tableview with an extension
extension ViewController {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comicsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
cell.myCellLabel.text = String(indexPath.row)
cell.myCellButton.tag = indexPath.row
cell.myCellButton.addTarget(self, action: Selector("logAction:"), for: .touchUpInside)
return cell
}
func logAction(sender: UIButton) {
let titleString = self.comicsArray[sender.tag]
let firstActivityItem = "\(titleString)"
let activityVC = UIActivityViewController(activityItems: [firstActivityItem], applicationActivities: nil)
self.present(activityVC, animated: true, completion: nil)
}
}
EDIT:
solved with help of abdullahselek by adding in subclasses cell:
public var dataFromTableView : String!
and implementing:
#IBAction func myCellButtonTapped(_ sender: UIButton) {
guard dataFromTableView != nil else {return}
print("pushed \(dataFromTableView!)")
}
and in cellForRowAt :
cell.data = comicsArray[indexPath.row]
Add a dictionary or object model property to your custom tableviewcell like
public var data: Dictionary!
And set this data property
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.data = comicsArray[indexPath.row]
}
Then you button can reach data with in your tableviewcell

iOS swift UIButton in TableView Cell

I have a tableView with custom cell. in my custom cell I have a like button. for like Button I wrote a function to change state from .normal to .selected like this:
FeedViewCell
class FeedViewCell: UITableViewCell {
#IBOutlet weak var likeButton: UIButton!
var likes : Bool {
get {
return UserDefaults.standard.bool(forKey: "likes")
}
set {
UserDefaults.standard.set(newValue, forKey: "likes")
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.likeButton.setImage(UIImage(named: "like-btn-active"), for: .selected)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func likeBtnTouch(_ sender: AnyObject) {
print("press")
// toggle the likes state
self.likes = !self.likeButton.isSelected
// set the likes button accordingly
self.likeButton.isSelected = self.likes
}
}
FeedViewController :
class FeedViewController: UIViewController {
#IBOutlet var feedTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Register Cell Identifier
let feedNib = UINib(nibName: "FeedViewCell", bundle: nil)
self.feedTableView.register(feedNib, forCellReuseIdentifier: "FeedCell")
}
func numberOfSectionsInTableView(_ tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.feeds.count
}
func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeedCell", for: indexPath) as! FeedViewCell
return cell
}
}
But my problem is when I tap like button in cell with indexPath.row 0 the state of button in cell with indexPath.row 3 change state too.
where is my mistake?
thanks
You didn't post all your code, but I can tell you that for this to work the #IBAction func likeBtnTouch(_ sender: AnyObject) { } definition must be inside the FeedViewCell class definition to make it unique to a particular instance of the cell.
As a rule of thumb, I normally ensure that all the UI elements inside my cell are populated in cellForRowAtIndexPath when using dequeued cells. Also it should be set from an external source. I.o.w not from a property inside the cell. Dequeuing cells reuse them, and if not setup properly, it might have some leftovers from another cell.
For example, inside cellForRowAtIndexPath:
self.likeButton.isSelected = likeData[indexPath.row]

Resources