Change the UIButton title when click on UITableviewCells - ios

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.

Related

Quiz app option button background color change

When we click on the wrong option in the quiz application, the background color is red and the background color of the correct option is green. how can I do that? My model :
struct QuizModel {
let q : String
let a : [String]
let correctAnswer : Int
}
my question :
QuizModel(q: "Aşağıdakilerden hangisi ilk yardımın amaçlarından biri değildir?", a: [
"A) İlaçla tedavi etmek","B) Durumun kötüleşmesini önlemek","C) Hayati tehlikeyi ortadan kaldırmak","D) Yaşamsal fonksiyonların sürdürülmesini sağlamak"], correctAnswer: 0)
answer func :
func checkAnswer(userAnswer : Int)-> Bool {
if userAnswer == quiz[questionNumber ].correctAnswer {
return true
}else{
return false
}
}
user tapped option button :
#objc func TappedButton(_ sender : UIButton){
let userAnswer = sender.tag
let userRightGot = quizBrains.checkAnswer(userAnswer: userAnswer)
if userRightGot {
sender.backgroundColor = .green
score += 1
scoreLabel.text = "\(score)"
}else{
sender.backgroundColor = .red
failScore += 1
failScoreLabel.text = "\(failScore)"
}
The method affects only the currently tapped button, you have to update the state of the other buttons, too.
Something like this, button0-button3 are the references to the buttons, you have to add IBOutlets if there are none.
var buttons = [button0, button1, button2, button3]
// please name methods with starting lowercase letter
#objc func tappedButton(_ sender : UIButton) {
let userAnswer = sender.tag
let correctAnswer = quiz[questionNumber].correctAnswer
for button in buttons {
button.backgroundColor = button.tag == correctAnswer ? .green : .red
}
if userAnswer == correctAnswer {
score += 1
scoreLabel.text = "\(score)"
} else {
failScore += 1
failScoreLabel.text = "\(failScore)"
}
}

Change sound button image on clicking another button swift 2.2

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")
}

how to use button action in UITapGestureRecognizer

I want to call this method on tap function :
#IBAction func Likes(sender: UIButton!) {
if let QuotesDetail = self.Array_Quote.object(at: sender.tag) as? NSDictionary {
if let quote_id = QuotesDetail.object(forKey: "quote_id") {
if (sender.isSelected) {
self.api_addQuoteToFavourite(qt_id: "\(quote_id)", indexP: intmax_t(sender.tag))
sender.isSelected = false
}
else {
self.api_addQuoteToFavourite(qt_id: "\(quote_id)", indexP: intmax_t(sender.tag))
sender.isSelected = true
}
}
}
}
my tap function :
#objc func handleTap(sender:UITapGestureRecognizer) {
if let label = sender.view as? UILabel {
if let QuotesDetail = self.Array_Quote.object(at: (label.tag)) as? NSDictionary {
}
}
}
You just need to pass UIButton which is having tag.
let btn = UIButton()
btn.tag = 0//you can set whatever you want.
self.Like(sender:btn)
you have to handle sender.isSelected = false as you are passing new object. Actually it should be same button which you have bind to Like method.
If you have same tag of button and label then get your button using viewWithTag and pass that button.
if let btn = self.view.viewWithTag(label.tag) as? UIButton {
self.Like(sender:btn)
}
Like shoulb be like as it is a function.

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.

How to toggle a Button Inside a table View

I have a custom cell in my table view which contain a button and name of audio file. when i am tapping in button the relevant audio is playing and when tapping again it audio stops. My problem is when i am tapping the same button it is ok but when i am tapping in any button different then current cell then my process is not working. Can any one show me the right direction to do this . My code is below . Thanks in advance..
var isAudioPlaying = false
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return designCellAtIndexPath(indexPath)
}
private func designCellAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = NSBundle.mainBundle().loadNibNamed("ExtendedDesign", owner: self, options: nil)[4] as! UITableViewCell
cell.frame = CGRectMake(0.0, 0.0, UIScreen.mainScreen().bounds.size.width, cell.bounds.height)
cell.contentView.frame = cell.bounds
cell.selectionStyle = UITableViewCellSelectionStyle.None
btnPlayPause = cell.viewWithTag(1) as! subclassedUIButton
btnPlayPause.addTarget(self, action: "btnPlayPauseTapped:", forControlEvents: .TouchUpInside)
btnPlayPause.urlString = arrAttractionList[indexPath.row].audio.url
let lblAttractionName = cell.viewWithTag(2) as! UILabel
lblAttractionName.text = arrAttractionList![indexPath.row].name
return cell
}
My Button Methode is:
func btnPlayPauseTapped(sender: subclassedUIButton) {
if !isAudioPlaying {
isAudioPlaying = true
sender.setImage(UIImage(named: "Button_Pause"), forState: .Normal)
AudioHandler.sharedManager().playAudio(sender.urlString)
} else {
isAudioPlaying = false
sender.setImage(UIImage(named: "Button_Play_Menu.png"), forState: .Normal)
AudioHandler.sharedManager().audioPlayer?.pause()
}
}
// Custome class for UIButton
class subclassedUIButton: UIButton {
var indexPath: Int?
var urlString: String?
}
You have to manage other flag for your current cell's audio you have to play. Set current cell index and manage that.
let cell: UITableViewCell = NSBundle.mainBundle().loadNibNamed("ExtendedDesign", owner: self, options: nil)[4] as! UITableViewCell
This is not the correct way to add a cell to a table view. You should call registerNib(_:forCellReuseIdentifier:) (usually in the viewDidLoad() method) and then dequeueReusableCellWithIdentifier(_:forIndexPath:) in your cellForRowAtIndexPath(_:) delegate method.
The registerNib(_:forCellReuseIdentifier:) isn't needed if you design your cell with a template in the storyboard.
But you really need to use table views the way they were designed to be used. What you have now might seem to work, but it's going to have problems and make your life miserable if you don't use table views the way they were intended to be used.
Also, you don't want to be referencing your subviews with viewWithTag(_:). You want to wire up proper IBOutlets in Interface Builder. Or at least creating properties in your UITableView subclass to access the subviews.
Finally I did it here is my code to do this. First Declare Two variables in class:
var currentCellIndex :int = -1
var previousCellIndex : int = -1
func btnPlayPauseTapped(sender: subclassedUIButton) {
currentCellIndex = sender.indexPath!
if currentCellIndex == previousCellIndex {
if !isAudioPlaying {
isAudioPlaying = true
AudioHandler.sharedManager().stopAudioPlayer()
sender.setImage(UIImage(named: "Button_Play_Menu.png"), forState: .Normal)
} else {
isAudioPlaying = false
AudioHandler.sharedManager().playAudio(sender.urlString)
sender.setImage(UIImage(named: "Button_Pause"), forState: .Normal)
}
} else {
let indexPath = NSIndexPath(forRow: previousCellIndex, inSection: 0)
tblAttractinList.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
isAudioPlaying = false
sender.setImage(UIImage(named: "Button_Pause"), forState: .Normal)
AudioHandler.sharedManager().playAudio(sender.urlString)
previousCellIndex = sender.indexPath!
}
}
Thank You all of you for your help! :)

Resources