I want to change cell image when music is playing , I am using didselectrow for this when i select row it change image and when i scroll i see many other cell image is also changed i don't why please guide me
here is my code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? NaatListTableViewCell
cell?.btnPlayPause.setImage(UIImage(named: "pause"), for: .normal)
}
try:
var isPlayingIndex = -1
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? NaatListTableViewCell
if indexPath.row == isPlayingIndex {
cell?.btnPlayPause.setImage(UIImage(named: "play"), for: .normal)
}else {
cell?.btnPlayPause.setImage(UIImage(named: "pause"), for: .normal)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? NaatListTableViewCell
if indexPath.row == isPlayingIndex {
cell?.btnPlayPause.setImage(UIImage(named: "pause"), for: .normal)
isPlayingIndex = -1
} else {
// stop current player
//
isPlayingIndex = indexPath.row
cell?.btnPlayPause.setImage(UIImage(named: "play"), for: .normal)
}
}
Instead of changing the image in didSelectRowAt method, you can do it another way by implementing setSelected(_:animated:) method in your custom UITableViewCell and handle the image status there, i.e.
override func setSelected(_ selected: Bool, animated: Bool) {
if selected {
btnPlayPause.setImage(UIImage(named: "pause"), for: .normal)
} else {
btnPlayPause.setImage(UIImage(named: "play"), for: .normal)
}
}
The above method handles the selection and de-selection for all the cells in the tableView in single-selection and multi-selection modes.
After this, you'll not need to write anything in tableView(_:didSelectRowAt:) method.
You need to maintain state for your cell manually. You might have some other data associated with your cell, from what you have asked it seems like a list of music files, you could associate with each music a unique id in its model. Now create a map of type var isPlaying = [Int: Bool]() (assuming you are going with int ids)
Then in didSelectRowAt set the value with corresponding id
self.isPlaying[YOUR_ID] = cell.isSelected
Now in your cellForRowAt method
var imageName = self.isPlaying[YOUR_ID] ? "play" : "pause"
cell?.btnPlayPause.setImage(UIImage(named: imageName), for: .normal)
Related
I have a tableView with 2 custom xib cells. I want to switch the custom cell when user tapped it also adjust the cell height. How do I achieve it? I tried to use container view but then the height would be the same. I want to know if it is possible to do it with two xib for tableView cell? Thank you.
var isContactView: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: "ContactTableViewCell", bundle: nil), forCellReuseIdentifier: "contactCell")
tableView.register(UINib(nibName: "DetailTableViewCell", bundle: nil), forCellReuseIdentifier: "detailCell")
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//if ContactTableViewCell return 40
//if DetailTableViewCell return 150
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//by default the cell view is ContactTableViewCell.
//When user tapped the cell it will change to DetailTableViewCell.
if isContactView {
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
//do something...
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
//do something...
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//not sure how to change the xib in here.
//if cell view is ContactTableViewCell
cell view = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
isContactView = false
tableView.reloadData()
//else
cell view = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
isContactView = true
tableView.reloadData()
}
There are 2 cases:
If there's just single cell to be viewed, then just put the following code in didSelect:
isContactView = !isContactView
tableView.reloadData()
If there are multiple cells in which the condition is to be applied. Please put a key in your data model.
For example:
testArr is the array of objects that you are displaying in tableview. Then keep a key, say isContactView in this model. And put the login based upon this key.
Like in case of cellForRow:
if testArr[indexpath.row].isContactView {
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactTableViewCell
//do something...
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) as! DetailTableViewCell
//do something...
}
And in didselect:
isContactView = !testArr[indexPath.row].isContactView
I am using two images for cell, one i am showing when tableview cell is expand and the other one when cell is collapse
when cell expand i am using arrow-bottom
when cell is collapse arrow-right
for cell expand and collapse i am using below code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let cell = tableView.cellForRow(at: indexPath) as! FAQTableVIewCell
if selectedIndex == indexPath.row{
if self.isCollapse == false{
cell.arrowImage.image = UIImage(named: "arrow-rightt")
self.isCollapse = true
}else{
cell.arrowImage.image = UIImage(named: "arrow-bottom")
self.isCollapse = false
}
}else{
self.isCollapse = true
}
self.selectedIndex = indexPath.row
tableView.reloadRows(at: [indexPath], with: .automatic)
}
but the above code not working properly, first time when i expand cell its not showing bottom arrow, and if i expand two cells then also its not showing properly, pls do help with code
i need when cell expand then i need to show bottom-arrow, when cell in normal(back to its orginal position or collapsed position) then i need to show right-arrow
When you reload rows, they get in cellForRowAt method.
You must apply changes in this method. Store collapsed indexPath and check it in method.
With array:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//use your cell identifier
let cell = tableView.dequeueReusableCell(withIdentifier: "FAQTableVIewCell", for: indexPath) as! FAQTableVIewCell
let image = collapsedCells.contains(indexPath) ? UIImage(named: "arrow-rightt") : UIImage(named: "arrow-bottom")
cell.image = image
//other settings
return cell
}
var collapsedCells = [IndexPath]()
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//use your height values instead 44 and 120
return collapsedCells.contains(indexPath) ? 44 : 120
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let index = collapsedCells.firstIndex(of: indexPath) {
collapsedCells.remove(at: index)
} else {
collapsedCells.append(indexPath)
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
I am working on a location-based reminder app. I show all reminders that user created on a table view. I have also UISwitch on every cell. I want that UISwitch disables/enables reminders individually, not all notifications. I couldn't figure it out.
extension MainViewController: UITableViewDataSource{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! itemTableViewCell
let item = self.items![indexPath.row]
cell.itemTitle?.text = item.itemName
cell.itemSubTitle?.text = item.itemDescription
//switch
let swicthView = UISwitch(frame: .zero)
swicthView.onTintColor = UIColor (named: "DingerBlue")
swicthView.setOn(true, animated: true)
swicthView.tag = indexPath.row
swicthView.addTarget(self, action: #selector(self.SwitchBtn(_:)), for: .valueChanged)
cell.accessoryView = swicthView
let itemToRemove = self.items![indexPath.row]
let notifToRemove: String = itemToRemove.notifID!
return cell
}
#objc func switchDidChanged(_ sender: UISwitch){
print("Switch value is \(sender.isOn)")
if(sender.isOn){
print("on")
UIApplication.shared.registerForRemoteNotifications()
}
else{
print("Off")
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notifToRemove])
}
}
}
I believe your code is not working because cells are reused and actions on specific cells should be handled from the cell class rather than from ViewController. Move this code into the UITableViewCell code.
let swicthView = UISwitch(frame: .zero)
swicthView.onTintColor = UIColor (named: "DingerBlue")
swicthView.setOn(true, animated: true)
swicthView.tag = switchViewTag!
swicthView.addTarget(self, action: #selector(self.SwitchBtn(_:)), for: .valueChanged)
#objc func switchDidChanged(_ sender: UISwitch){
print("Switch value is \(sender.isOn)")
if(sender.isOn){
print("on")
UIApplication.shared.registerForRemoteNotifications()
}
else{
print("Off")
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notifToRemove])
}
}
and add a new property in the UITableViewCell
weak var switchViewTag: Int?
Modify your cellForRowAt delegate method to
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! itemTableViewCell
let item = self.items![indexPath.row]
cell.itemTitle?.text = item.itemName
cell.itemSubTitle?.text = item.itemDescription
cell.switchViewTag = indexPath.row
return cell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
let doLikeBtn = detailCell.contentView.viewWithTag(106) as! UIButton
doLikeBtn.setTitle(String(indexPath.row), for: UIControlState.normal)
doLikeBtn.addTarget(self, action: #selector(doLike(sender:)), for: UIControlEvents.touchUpInside)
...
}
...
func doLike(sender: UIButton) {
selectUserIndex = sender.title(for: UIControlState.normal)!
if sender.image(for: UIControlState.normal) == UIImage(named: "btn_Like.png") {
sender.setImage(UIImage(named: "btn_not_Like.png"), for: UIControlState.normal)
}else {
sender.setImage(UIImage(named: "btn_Like.png"), for: UIControlState.normal)
}
}
If I click one button in table, and then change the image of button, but other some button's images also are changed repeatedly.
I can't understand this.
Please help me!
Best regards.
a UITableViewCell object is reusable—that is for performance reasons,
you should only reset attributes of the cell that are not related to
content.
So you need to update your cell every time cellForRowAt invoked:
also you need to keep track of which cell getting "liked or dislike" so you can add for example a boolean isLike property to YourCustomCell
and toggle it true or false upon doLike func triggered
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.deque... as! YourCustomCell
if cell.isLiked == false {
cell.btnSomething.setImage(UIImage(named: "btn_not_Like.png"), for: UIControlState.normal)
}else {
cell.btnSomething.setImage(UIImage(named: "btn_Like.png"), for: UIControlState.normal)
}
}
Updated for Swift 3/4:
Use lines of code to change/set the UIButton Image in UITableView;
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourTableViewCellStoryboardIdentifier")! as! YourTableViewCellName
if status == 1{
cell.mStatusButtonOutlet.setImage(UIImage(named: "pending_icon"), for: .normal)
}else if status == 2{
cell.mStatusButtonOutlet.setImage(UIImage(named: "approval"), for: .normal)
}else if status == 3{
cell.mStatusButtonOutlet.setImage(UIImage(named: "reject_icon"), for: .normal)
}else{
cell.mStatusButtonOutlet.setImage(UIImage(named: "cancle"), for: .normal)
}
return cell
}
Note: where mStatusButtonOutlet - is your UIButtonOutlet
Enjoy..!
In Swift 4, Below is a simple way to do it
class AddressTableViewCell: UITableViewCell {
#IBOutlet weak var starButton: UIButton!
var buttonObject : (() -> Void)? = nil
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func buttonPressed(sender: UIButton) {
if let buttonAction = self.buttonObject {
buttonAction()
}
}
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "addressTableViewCell", for: indexPath) as! AddressTableViewCell
cell.buttonObject = {
if cell.starButton.currentImage == UIImage(named: "fav") {
cell.starButton.setImage(UIImage(named: "favYellow"), for: .normal)
} else {
cell.starButton.setImage(UIImage(named: "fav"), for: .normal)
}
}
return cell
}
I populated a tableView with an array of dictionaries Now How can I save the cell contents to Core Data and retrieve it in another tableView ?
I loaded an array of dictionaries to a tableView:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SourceTableViewCell
cell.titleLabel.text = sourceFeeds[indexPath.row]["title"]
cell.linkLabel.text = sourceFeeds[indexPath.row]["link"]
return cell
}
Now I want to save those link and title to core data in cell selection
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView.deselectRow(at: indexPath, animated: true)
let cell = self.tableView.cellForRow(at: indexPath) as! SourceTableViewCell
if self.tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCellAccessoryType.none {
self.tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
} else {
self.tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
}
}
I want to mention that "sourceFeeds" array has loaded from plist!
I found the solution of my problem finally!