Change sound button image on clicking another button swift 2.2 - ios

I am creating a Tableview inside which is Tableviewcell and on cell there is a label and sound button. For each label there is a sound on button click. When I click for the first time on btn1 the sound plays and the button image changes to "pause" when I click again the same button sound stops and the image changes to "play" works perfectly in this manner but when I click for the first time on one button let suppose btn1 and without clicking it again (stoping sound) I click on btn2, the sound of the btn1 stops and the image of btn1 nor btn2 changes. I want that when I click on btn 2,3, or 4 the previous sound should stop, the image of previous button (means all buttons except the current) should change to "play" and the current clicked button should change to "pause" and the sound of the previous click should stop and the current clicked should play.
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var titleLable: UILabel!
#IBOutlet weak var sound: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
class ViewController: UIViewController , UITableViewDataSource , UITableViewDelegate , GADInterstitialDelegate {
var countsNumberOfButtonClicks = 0
var countsNumberOfInfoBtnClicks = 0
var isFirstTime = false
var player : AVAudioPlayer! = nil
var titleAlert: String!
#IBOutlet weak var myTableView: UITableView!
var toggleState = 1
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell.
{
let myCell = self.myTableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! TableViewCell
myCell.titleLable.text = self.Duck[indexPath.row]
myCell.sound.tag = indexPath.row
myCell.sound.addTarget(self, action: #selector(self.playSound), forControlEvents: .TouchUpInside)
return myCell
}
#IBAction func playSound(sender: UIButton) {
if toggleState == 1 {
let fullName: String = self.Duck[sender.tag]
let fullNameArr = fullName.componentsSeparatedByString(" ")
let path = NSBundle.mainBundle().pathForResource(fullNameArr[0], ofType:"wav", inDirectory: "sounds")
let fileURL = NSURL(fileURLWithPath: path!)
do {
player = try AVAudioPlayer(contentsOfURL: fileURL)
player.prepareToPlay()
} catch {
print("Problem in getting File")
}
player.play()
sender.setImage(UIImage(named: "pause.png"), forState: UIControlState.Normal)
print("toggle state 1")
toggleState = 2
}
else {
player.pause()
toggleState = 1
sender.setImage(UIImage(named: "play.png"), forState: UIControlState.Normal)
print("Toggle state else")
}
Simulator result

In you class, declare a variable,
var currentlyPlaying : UIButton?
And wherever you play the sound, store the button which played the sound in this variable and whenever this variable is about to be change, reset the previous ones image and store the new one.
#IBAction func playSound(sender: UIButton) {
if currentlyPlaying != sender || toggleState == 1 {
//Set image in previous
currentlyPlaying?.setImage(UIImage(named: "play.png")
if player != nil{
player.pause()
}
let fullName: String = self.Duck[sender.tag]
let fullNameArr = fullName.componentsSeparatedByString(" ")
let path = NSBundle.mainBundle().pathForResource(fullNameArr[0], ofType:"wav", inDirectory: "sounds")
let fileURL = NSURL(fileURLWithPath: path!)
do {
player = try AVAudioPlayer(contentsOfURL: fileURL)
player.prepareToPlay()
} catch {
print("Problem in getting File")
}
player.play()
sender.setImage(UIImage(named: "pause.png"), forState: UIControlState.Normal)
//Store new
currentlyPlaying = sender
print("toggle state 1")
if sender != currentlyPlaying{
toggleState = 2
}
myTableView.reloadData()
}
else {
player.pause()
toggleState = 1
sender.setImage(UIImage(named: "play.png"), forState: UIControlState.Normal)
print("Toggle state else")
}

Related

How to refresh UITableView when UICell is reused

I have an UIViewController with a UITableView inside. In that table I have few rows and each row have few buttons. When the user click a button then the icon of the button is changed. I managed to save the status of the buttons in an object but I have issues with a bug which is selecting randomly other buttons when I check the selected button.
Here is my code:
// MODEL
class ChecklistItem: NSObject, NSCoding {
// Recorded values
var vehiclePass = 0 // 0 = unchecked, 1 = pass, 2 = fail
var trailerPass = 0 // 0 = unchecked, 1 = pass, 2 = fail
var vehicleComment = String()
var trailerComment = String()
}
// Set the cell of UITableView.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Constants.checklistCell, for: indexPath) as! ChecklistCell
let itemCategory = itemSections[indexPath.section]
let item = itemCategory.checklistItems[indexPath.row]
titleForSelectedQuestion = item.descript
cell.delegate = self
cell.configCell(item)
// 0 = questions is not checked yet ( white icon ), 1 = question was checked as PASS ( green icon ), 2 = question was checked as FAIL ( red icon )
if item.vehiclePass == 0 {
// vehicle pass = white icon & vehicle fail = white icon
cell.vehiclePassButton.setImage(UIImage(named: Constants.whiteTickIcon), for: UIControl.State.normal)
cell.vehicleFailButton.setImage(UIImage(named: Constants.whiteCrossIcon), for: UIControl.State.normal)
}
if item.trailerPass == 0 {
// trailer pass = white icon & trailer fail = white icon
cell.trailerPassButton.setImage(UIImage(named: Constants.whiteTickIcon), for: UIControl.State.normal)
cell.trailerFailButton.setImage(UIImage(named: Constants.whiteCrossIcon), for: UIControl.State.normal)
}
if item.vehiclePass == 1 {
// vehicle pass = green icon & vehicle fail = white icon
cell.vehiclePassButton.setImage(UIImage(named: Constants.greenTickIcon), for: UIControl.State.normal)
cell.vehicleFailButton.setImage(UIImage(named: Constants.whiteCrossIcon), for: UIControl.State.normal)
}
if item.vehiclePass == 2 {
// vehicle pass = white icon & vehicle fail = red icon
cell.vehiclePassButton.setImage(UIImage(named: Constants.whiteTickIcon), for: UIControl.State.normal)
cell.vehicleFailButton.setImage(UIImage(named: Constants.redCrossIcon), for: UIControl.State.normal)
}
if item.trailerPass == 1 {
// trailer pass = green icon & trailer fail = white icon
cell.trailerPassButton.setImage(UIImage(named: Constants.greenTickIcon), for: UIControl.State.normal)
cell.trailerFailButton.setImage(UIImage(named: Constants.whiteCrossIcon), for: UIControl.State.normal)
}
if item.trailerPass == 2 {
// trailer pass = white icon & trailer fail = red icon
cell.trailerPassButton.setImage(UIImage(named: Constants.whiteTickIcon), for: UIControl.State.normal)
cell.trailerFailButton.setImage(UIImage(named: Constants.redCrossIcon), for: UIControl.State.normal)
}
print("For section \(indexPath.section) row: \(indexPath.row) - vehicle status = \(item.vehiclePass)")
print("For section \(indexPath.section) row: \(indexPath.row) - trailer status = \(item.trailerPass)")
return cell
}
}
extension ChecklistVC: ChecklistCellDelegate{
// Check if user pressed Pass or Fail btn for Vehicle/Trailer and scroll to next question
func tappedOnVehicleOrTrailerButtons(vehiclePassBtn: UIButton, vehicleFailBtn: UIButton, trailerPassBtn: UIButton, trailerFailBtn: UIButton, selectedCell: ChecklistCell) {
let indexPath = questionsTableView.indexPath(for: selectedCell)
let item = itemSections[indexPath?.section ?? 0].checklistItems[indexPath?.row ?? 0]
if vehiclePassBtn.isSelected {
item.vehiclePass = 1
}
if vehicleFailBtn.isSelected {
item.vehiclePass = 2
}
if trailerPassBtn.isSelected {
item.trailerPass = 1
}
if trailerFailBtn.isSelected {
item.trailerPass = 2
}
displayChecksLeft()
questionsTableView.reloadData()
print("For section \(indexPath?.section ?? 0) row: \(indexPath?.row ?? 0) - vehicle status = \(item.vehiclePass)")
print("For section \(indexPath?.section ?? 0) row: \(indexPath?.row ?? 0) - trailer status = \(item.trailerPass)")
if (vehiclePassBtn.isSelected || vehicleFailBtn.isSelected) && (trailerPassBtn.isSelected || trailerFailBtn.isSelected) {
displayChecksLeft()
scrollDown()
}
if (vehicleFailBtn.isTouchInside || trailerFailBtn.isTouchInside) {
self.lastIndexPath = indexPath
self.performSegue(withIdentifier: Constants.goChecklistAddComment, sender: nil)
}
}
}
Here is the code for the Cell:
protocol ChecklistCellDelegate {
func tappedOnVehicleOrTrailerButtons(vehiclePassBtn: UIButton, vehicleFailBtn: UIButton, trailerPassBtn: UIButton, trailerFailBtn: UIButton, selectedCell: ChecklistCell)
func tapGestureOnCell(_ selectedCell: ChecklistCell)
}
class ChecklistCell: UITableViewCell {
// Interface Links
#IBOutlet weak var questionName: UILabel!
#IBOutlet weak var vehiclePassButton: UIButton!
#IBOutlet weak var vehicleFailButton: UIButton!
#IBOutlet weak var trailerPassButton: UIButton!
#IBOutlet weak var trailerFailButton: UIButton!
#IBOutlet weak var vehicleCommentLabel: UILabel!
#IBOutlet weak var trailerCommentLabel: UILabel!
#IBOutlet weak var tagIconImageView: UIImageView!
#IBOutlet weak var tagNameLabel: UILabel!
#IBOutlet weak var defectImageView: CustomImageView!
// Constraints Links
#IBOutlet weak var vehicleCommentHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var trailerCommentHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var tagIconHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var tagNameBottomConstraint: NSLayoutConstraint!
#IBOutlet weak var defectImageHeightConstraint: NSLayoutConstraint!
// Properties
var delegate: ChecklistCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
let longTapGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.tapEdit(sender:)))
addGestureRecognizer(longTapGesture)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
// Detect when the user press Long Tap on any cell
#objc func tapEdit(sender: UITapGestureRecognizer) {
delegate?.tapGestureOnCell(self)
}
// Config the cell for Defect and Damage Check
func configCell(_ checklistItem: ChecklistItem){
questionName.text = checklistItem.descript
defectImageView.image = UIImage(named: String(checklistItem.imagesPath?.last ?? String()))
vehicleCommentLabel.text = checklistItem.vehicleComment
trailerCommentLabel.text = checklistItem.trailerComment
tagIconImageView.image = UIImage(named: Constants.tagIcon)
}
// Function to change the icon when the user press Pass or Fail Btn
func changeIconOnBtnTap(checkedBtn: UIButton, uncheckedBtn: UIButton){
if checkedBtn.isSelected == true {
checkedBtn.isSelected = true // user can't uncheck the button
uncheckedBtn.isSelected = false // the unchecked button is white now
}else {
checkedBtn.isSelected = true
uncheckedBtn.isSelected = false
}
}
// Check if the user press Pass or Fail btn for Vehicle or Trailer
#IBAction func passOrFailBtnTapped(_ sender: UIButton) {
sender.isSelected = true
delegate?.tappedOnVehicleOrTrailerButtons(vehiclePassBtn: vehiclePassButton,
vehicleFailBtn: vehicleFailButton,
trailerPassBtn: trailerPassButton,
trailerFailBtn: trailerFailButton,
selectedCell: self)
}
}
Here is a capture with the bug:
Thanks for reading this.
The problem is here tappedOnVehicleOrTrailerButtons
if vehiclePassBtn.isSelected {
item.vehiclePass = 1
}
if vehicleFailBtn.isSelected {
item.vehiclePass = 2
}
if trailerPassBtn.isSelected {
item.trailerPass = 1
}
if trailerFailBtn.isSelected {
item.trailerPass = 2
}
you entirely depend on the buttons isSelected property which state can be dequeued to change the model values , but you should check the current model value and act accordingly
Since you send this parameter , selectedCell: ChecklistCell use it like the other method
let indexPath = tableView.indexPath(for:cell)!
let itemCategory = itemSections[indexPath.section]
let item = itemCategory.checklistItems[indexPath.row]
// then check the value in item and go on
another thing also don't reload the whole table here
questionsTableView.reloadData()
but only the affected indexPath
questionsTableView.reloadRows([indexPath],for:.none)
and put it at end of the function
Here is the fix if someone want to implement the same functionality:
// Config the cell for Defect and Damage Check
func configCell(_ checklistItem: ChecklistItem){
questionName.text = checklistItem.descript
// Detect when user press Pass or Fail on any button and execute the assigned function to change the icon
vehiclePassButton.addTarget(self, action: #selector(vehiclePassButtonTapped), for: UIControl.Event.touchUpInside)
vehicleFailButton.addTarget(self, action: #selector(vehicleFailButtonTapped), for: UIControl.Event.touchUpInside)
trailerPassButton.addTarget(self, action: #selector(trailerPassButtonTapped), for: UIControl.Event.touchUpInside)
trailerFailButton.addTarget(self, action: #selector(trailerFailButtonTapped), for: UIControl.Event.touchUpInside)
}
#objc func vehiclePassButtonTapped(){
changeIconOnBtnTap(checkedBtn: vehiclePassButton, uncheckedBtn: vehicleFailButton)
}
#objc func vehicleFailButtonTapped(){
changeIconOnBtnTap(checkedBtn: vehicleFailButton, uncheckedBtn: vehiclePassButton)
}
#objc func trailerPassButtonTapped(){
changeIconOnBtnTap(checkedBtn: trailerPassButton, uncheckedBtn: trailerFailButton)
}
#objc func trailerFailButtonTapped(){
changeIconOnBtnTap(checkedBtn: trailerFailButton, uncheckedBtn: trailerPassButton)
}
// Function to change the icon when the user press Pass or Fail Btn
func changeIconOnBtnTap(checkedBtn: UIButton, uncheckedBtn: UIButton){
if checkedBtn.isSelected{
checkedBtn.isSelected = true // user can't uncheck the button
uncheckedBtn.isSelected = false // the unchecked button is white now
} else{
checkedBtn.isSelected = false
}
checkedBtn.isSelected = false // reset button status
uncheckedBtn.isSelected = false
}
Thanks Sh_Khan for trying to help me !!!

Backend not updating after first tap and grabbing previous value after sequential taps

I am working on a "to do" app in Swift and using Firebase as my backend.
On the first tap on my checkbox to signal that a task has been done, the UI updates and the variable should become true (a checkmark appears) but firebase and the local instance of the bool value for that item do not update to false. After a second tap, the UI continues to have normal functionality (the checkmark disappears); but firebase and the local instance both update to true. Following taps from then on are reversed (True for no checkmark and false for checkmark). When I stop the simulator in Xcode and re-run, the values and UI that load in are correct. It is not until I try and tap on the checkmark that I get the incorrect functionality again. Firebase only updates after the second tap and change in UI. I have include just the code that pertains to the checkbox. I think the problem happens in the doneHit function but I am not quite sure why its happening.
Please help. If there is an easier way to go about this, that would be helpful too.
protocol TaskCellDelegate {
func doneHit(cell : TaskCell)
}
class TaskCell : UITableViewCell {
var delegate : TaskCellDelegate?
#IBOutlet weak var label: UILabel!
#IBOutlet weak var checkBox: CheckBox!
#IBOutlet weak var detailLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
checkBox.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
}
func buttonClicked(sender:UIButton) {
delegate?.doneHit(self)
}
}
class CheckBox: UIButton {
//images
let checkedImage = UIImage(named: "checkedbox")
let unCheckedImage = UIImage(named: "uncheckedbox")
//bool propety
var isChecked:Bool = false{
didSet {
if isChecked == true{
self.setImage(checkedImage, forState: .Normal)
}
else {
self.setImage(unCheckedImage, forState: .Normal)
}
}
}
override func awakeFromNib() {
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
}
func buttonClicked(sender:UIButton) {
if(sender == self){
if isChecked == false {
isChecked = true
} else {
isChecked = false
}
}
}
}
func doneHit(cell:TaskCell) {
if let ip = tableView.indexPathForCell(cell) {
var task = tasks[ip.row]
task.done = cell.checkBox.isChecked
if task.done == true {
task.completedBy = "Completed by: \(self.user)"
cell.label.textColor = UIColor.grayColor()
}
else {
task.completedBy = ""
cell.label.textColor = UIColor.blackColor()
}
let taskNameRef = self.ref.childByAppendingPath("tasks/\(task.title)")
let completedByData = ["completedBy": "\(self.user)"]
let doneData = ["done": task.done]
taskNameRef.updateChildValues(completedByData)
taskNameRef.updateChildValues(doneData)
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! TaskCell
// Configure the cell...
cell.selectionStyle = .None
let idx = tasks[indexPath.row]
if let label = cell.viewWithTag(1) as? UILabel {
label.text = idx.title
if idx.done == true {
label.textColor = UIColor.grayColor()
} else {
label.textColor = UIColor.blackColor()
}
if let checkBox = cell.viewWithTag(2) as? CheckBox {
checkBox.isChecked = idx.done
}
if let userCompleted = cell.viewWithTag(3) as? UILabel {
if idx.done == true {
userCompleted.text = "Completed By: \(idx.completedBy)"
}
else {
userCompleted.text = ""
}
}
}
print("Task.done is: \(idx.done)")
print("isChecked is:\(cell.checkBox.isChecked)")
cell.delegate = self
return cell
}
Figured it out myself after 3 days. I scrapped the Checkbox class and turned the checkbox into a UIImageView and added a gesture recognizer. The rest was just moving the Checkbox logic into the TaskTVC class under the doneHit method.

Issue with updating clicked table view cell

I have an issue that has been vexing me for a while and I feel like I am so close. Here is the situation. I have a tableview that holds different calculus videos and I would like to give my students the ability to download the videos for playing offline. That part works fine. The problem I am having is that when the user clicks on the download button, the download button should hide and show an activity indicator as well as a progress bar (all of which are in a custom cell). I have two problems:
1) The download button does not automatically hide and show the activity view unless I scroll away from it and come back to it.
2) If I do scroll down all of a sudden random cells will not have the download button anymore.
This must be due to the fact that cells are being reused but I thought I was doing things properly although obviously there is a mistake. I will post the relevant code snippets below:
cellForRowAtIndexPath Code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("VideoCell", forIndexPath: indexPath) as! TableViewCell
let currentVideo = videos[indexPath.section][indexPath.row]
cell.downloadButton.addTarget(self, action: "downloadButtonPressed:", forControlEvents: .TouchUpInside)
cell.video = currentVideo
return cell
}
Custom Table View Cell Code:
class TableViewCell: UITableViewCell {
#IBOutlet weak var videoTitleLabel: UILabel!
#IBOutlet weak var progressView: UIProgressView!
#IBOutlet weak var customAccessoryView: UIView!
#IBOutlet weak var downloadButton: UIButton!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
let userDefaults = NSUserDefaults.standardUserDefaults()
var video: Video? {
didSet {
updateUI()
}
}
private func updateUI() {
guard let video = video else {
print("video should not be nil")
return
}
videoTitleLabel.text = video.title
if video.downloadStatus.isDownloading {
progressView.hidden = false
progressView.progress = video.downloadStatus.downloadProgress
downloadButton.hidden = true
activityIndicator.hidden = false
activityIndicator.startAnimating()
} else {
progressView.hidden = true
activityIndicator.stopAnimating()
}
if video.downloadStatus.isSaved {
activityIndicator.stopAnimating()
progressView.hidden = true
downloadButton.hidden = true
}
}
Download request
func downloadButtonPressed(sender: UIButton) {
let buttonPosition = sender.convertPoint(CGPointZero, toView: self.tableView)
guard let indexPath = self.tableView.indexPathForRowAtPoint(buttonPosition) else {
print("Error getting index path from button press")
return
}
let section = indexPath.section
let row = indexPath.row
print("Button pressed at section \(section) and row \(row)")//correct row and section
//Code to save Video to Documents directory goes here
let currentVideo = videos[section][row]
guard !currentVideo.downloadStatus.isSaved else {
print("Video is already saved")
return
}
guard let url = currentVideo.url else {
print("Video not found...url is invalid")
return
}
let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
Alamofire.download(.GET, url, destination: destination)
.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
let progress = Float(totalBytesRead) / Float(totalBytesExpectedToRead)
currentVideo.downloadStatus.isDownloading = true
currentVideo.downloadStatus.downloadProgress = progress
}.response { request,response,data, error in
if let error = error {
print("Failed with error: \(error)")
} else {
print("Downloaded file successfully")
currentVideo.downloadStatus.isDownloading = false
currentVideo.downloadStatus.isSaved = true
self.saveDownloadStatusInDefaultsForVideo(currentVideo, isSaved: true)
}
print("Files currently in the documents directory:")
self.printDocumentsDirectoryContents() //file is there
}
}
In your class TableViewCell you're setting the property hidden of downloadButton to true under certain circumstances.
If you want the button to be visible by default set the property explicitly to false when reusing the cell

UIBarButtonItem changing image for Play/Pause button

I'm trying to make a play/pause button that toggles between custom images as it is pressed. Here is a snippet of the code.
Everything works fine but the button doesn't change. I've also tried using the .image property instead of the .setBackGroundImage method but then the button just goes blank on click.
Here is the code
import UIKit
import AVFoundation
class ViewController: UIViewController {
var audioPlayer = AVAudioPlayer()
var pauseImage:UIImage?
var playImage:UIImage?
#IBOutlet weak var btnPlayPause: UIBarButtonItem!
#IBOutlet weak var sldVolume: UISlider!
#IBAction func sldVolumeChanged(sender: AnyObject) {
audioPlayer.volume = sldVolume.value
}
#IBAction func actPressedPlayPause(sender: AnyObject) {
if audioPlayer.playing {
audioPlayer.pause()
btnPlayPause.setBackgroundImage(playImage, forState: .Normal, barMetrics: .Default)
} else {
audioPlayer.play()
btnPlayPause.setBackgroundImage(pauseImage, forState: .Normal, barMetrics: .Default)
}
}
#IBAction func actStopPressed(sender: AnyObject) {
audioPlayer.stop()
audioPlayer.currentTime = 0
}
override func viewDidLoad() {
super.viewDidLoad()
var pauseImagePath = NSBundle.mainBundle().pathForResource("pause", ofType: "png")
pauseImagePath = pauseImagePath!.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
pauseImage = UIImage(contentsOfFile: pauseImagePath!)
var playImagePath = NSBundle.mainBundle().pathForResource("play", ofType: "png")
playImagePath = playImagePath!.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
playImage = UIImage(contentsOfFile: pauseImagePath!)
var audioPath = NSBundle.mainBundle().pathForResource("minuetcminor", ofType: "mp3")
audioPath = audioPath!.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
var error : NSError? = nil
audioPlayer = AVAudioPlayer(contentsOfURL: NSURL(string: audioPath!), error: &error)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
had the same problem here! Had two of us confused as to why it wasn't working, I think it's a change in Swift 2/Xcode 7 beta
Just do this:
btnPlayPause.image = UIImage(named: "myImage.png")
Hope that helps!
Seems like this question has got a lot of strange answers. The truth is there's no non-hacky way to change an image in already existing UIBarButtonItem. Instead, unfortunately, you have to re-create it.
I've made a helper method to do this:
func changeBarButtonItemImage(_ item: UIBarButtonItem, image: UIImage, navItem: UINavigationItem) -> UIBarButtonItem? {
let buttonItem = UIBarButtonItem(image: image, style: item.style, target: item.target, action: item.action)
buttonItem.isEnabled = item.isEnabled
if let leftIndex = navItem.leftBarButtonItems?.index(of: item) {
var items: [UIBarButtonItem] = navItem.leftBarButtonItems!
items[leftIndex] = buttonItem
navItem.leftBarButtonItems = items
return buttonItem
}
if let rightIndex = navItem.rightBarButtonItems?.index(of: item) {
var items: [UIBarButtonItem] = navItem.rightBarButtonItems!
items[rightIndex] = buttonItem
navItem.rightBarButtonItems = items
return buttonItem
}
return nil
}
Usage:
if let image = UIImage(named: showingFilter ? "icon_filter_active.png" : "icon_filter.png") {
if let buttonItem = changeBarButtonItemImage(self.filterButton, image: image, navItem: navigationItem) {
self.filterButton = buttonItem
}
}
Take note that I also copy isEnabled property, because, in my case, in some situations, I was changing button icon while in the disabled state.
The #IBAction should use sender as UIButton instead of AnyObject or Any. Also, once that is done, the button can be directly accessed from inside the function using sender. (This is Swift 3)
#IBAction func actPressedPlayPause(sender: UIButton) {
if audioPlayer.playing {
audioPlayer.pause()
sender.setBackgroundImage(UIImage(named: "playimage.png"), for: .normal)
} else {
audioPlayer.play()
sender.setBackgroundImage(UIImage(named: "pauseimage.png"), for: .normal)
}
}
Try using below line of code:
btnPlayPause.setImage(image, forState: .Normal)
this works for me.

Change the UIButton title when click on UITableviewCells

I make simple player with VK Api. I want to do this.
When I clicked first track and then second change first button title "stop" to "play" automatically.
How to do it?
My play/stop button action.
func playAction(sender: UIButton!) {
if sender.currentTitle == "P" {
let track = dataOfTracks[sender.tag] as trackDoc
let url = NSURL(string: track.data.url)
player = AVPlayer(URL: url!)
player.play()
sender.setTitle("S", forState: UIControlState.Normal)
} else if sender.currentTitle == "S" {
sender.setTitle("P", forState: UIControlState.Normal)
player.pause()
}
}
EDIT CODE DETAILS:
don't reallocate every time the button. It must be another outlet of the SongsTableViewCell class (same as the label). And set the target/action from the Interface Builder (add #IBAction in front of "func cellSongClicked" and ctrl-drag from IB)
2.add the following property to your class:private var currentSong : Int?
3) method cellForRowAtIndexPath:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SongTitleCell", forIndexPath: indexPath) as SongsTableViewCell
let songDic : NSDictionary = arrSongs.objectAtIndex(indexPath.row) as NSDictionary
cell.lblSongTitle.text = songDic.objectForKey("SongTitle") as? String
cell.btnPlayPause.tag = indexPath.row
var title : String
if let _currentSong = currentSong {
title = indexPath.row == _currentSong ? "Stop" : "Play"
} else {
title = "Play"
}
cell.btnPlayPause.setTitle(title, forState: UIControlState.Normal)
return cell
}
4) And the action:
#IBAction func cellSongClicked (sender : AnyObject ){
var remote = GetSongData()
remote.delegate = self
var btnCurrentPressed = sender as UIButton
//Play Selected Song
let songDic : NSDictionary = arrSongs.objectAtIndex(btnCurrentPressed.tag) as NSDictionary
var rowsToReload = [NSIndexPath]()
var stopCurrent = false
if let _currentSong = currentSong {
if btnCurrentPressed.tag == _currentSong {
stopCurrent = true
} else {
rowsToReload.append(NSIndexPath(forRow: _currentSong, inSection:0))
}
}
rowsToReload.append(NSIndexPath(forRow: btnCurrentPressed.tag, inSection:0))
currentSong = stopCurrent ? nil : btnCurrentPressed.tag
self.tableView.reloadRowsAtIndexPaths(rowsToReload, withRowAnimation: .None)
}
You don't have to change the title of the button every time. You could use something like this:
func viewDidLoad {
playButton.setTitle("Play", forState: UIControlState.Normal)
playButton.setTitle("Stop", forState: UIControlState.Selected)
}
Then in your callback method you just change the state of the button and the text will get updated too:
func playAction(sender: UIButton!) {
// Selected means the content is playing
if !sender.selected {
let track = dataOfTracks[sender.tag] as trackDoc
let url = NSURL(string: track.data.url)
player = AVPlayer(URL: url!)
player.play()
} else {
player.pause()
}
// update the state of the button
sender.selected = !sender.selected
}
I consider this to be a more clean solution since you are not comparing strings anymore to make your decision and you are actually using the binary state of the button to keep track of the current state of your content(which is also binary, either playing or not).
If you have more questions, I would be more than happy to help you further, just let me know.

Resources