I am using swift. I have a Bar Button Item that I would like to change the Identifier from Play to Stop in code. Is this possible and how do you do It?
#IBOutlet var StartStopButton: UIBarButtonItem!
#IBAction func StartAlarm(sender: AnyObject) {
onOffIndicator.hidden = false
StartStopButton.Identifier = ?????
}
Unfortunately you can't change the identifier so you have to set the whole bar button item. You have to do the following:
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Stop, target: self, action: "startAlarm:")
To make it nicer you can define an array of UIBarButtonSystemItems and an index like so:
let myArray = [UIBarButtonSystemItem.Start, UIBarButtonSystemItem.Stop]
var index = 0
Then you can do:
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: myArray[++index % myArray.count], target: self, action: "startAlarm:")
By the way, remember to use non-capitalized function and variable names ;)
Swift 5
#IBOutlet var StartStopButton: UIBarButtonItem!
#IBAction func StartAlarm(sender: AnyObject) {
onOffIndicator = !onOffIndicator
if onOffIndicator {
StartStopButton.image = UIImage(systemName: "stop")
} else {
StartStopButton.image = UIImage(systemName: "play")
}
}
Related
In my app, I have a toolbar with UIBarButtonItems.
In most circumstances, the UIBarButtonItems are set via storyboard, and look as follows:
In a special case, I have to replace one UIBarButtonItem programmatically. This is done with the following code:
let rotatingButton = UIButton(type: .custom)
rotatingButton.setImage(UIImage(named: "LocalizationInUseNoFix"), for: .normal)
rotatingButton.addTarget(self, action: #selector(localizationButtonTapped), for: .touchUpInside)
rotatingButton.rotateStart()
let barButtonItem = UIBarButtonItem(customView: rotatingButton)
leftBarButtonItems![2] = barButtonItem
When the rotatingButton is displayed in the toolbar, it placed at a different position. It is shifted to the right, as you can see here:
How can I achieve to place both UIBarButtonItems at the same position?
EDIT:
By now I realized that the horizontal shift of the programmatically created UIBarButtonItem is not always the same, without any changes to the code: Sometimes it is shifted left, and not right:
EDIT 2:
I found a workaround:
If I set a width constrain to my button like
rotatingButton.widthAnchor.constraint(equalToConstant: 40).isActive = true
then the button is apparently always correctly placed. But I hate to hard-code constraints like this.
Is there a more elegant way to do it?
Try the below steps to perform your task:
Store left bar button items into an NSMutableArray
Replace desired UIBarbuttonItem
Set leftbarbuttonitems to this new array
Hope this steps will work
When you set the image on UIBarButton programmatically, the contentmode of the leftBarButtonItems becomes 'left' and rightBarButtonItems become 'right'. But from storyboard, it is centered. Set the image and adjust the contentMode as required.
All are working fine for Navigationbar and Toolbar
class ViewController: UIViewController {
#IBOutlet weak var toolbar: UIToolbar!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func leftAction(_ sender: Any) {
}
#IBAction func rightAction(_ sender: Any) {
}
#IBAction func changeLeftItems(_ sender: Any) {
if let items = self.navigationItem.leftBarButtonItems {
var addItems = [UIBarButtonItem]()
addItems.append(contentsOf: items)
let barItem = UIBarButtonItem(title: "3", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.leftAction(_:)))
addItems.append(barItem)
self.navigationItem.leftBarButtonItems = addItems
}
if let items = self.toolbar.items {
var addItems = [UIBarButtonItem]()
addItems.append(contentsOf: items)
let barItem = UIBarButtonItem(title: "L3", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.leftAction(_:)))
addItems.insert(barItem, at: 2)
self.toolbar.setItems(addItems, animated: true)
}
}
}
This is the best solution I found so far:
Get the width of a view of another bar button item using key value coding. This is from Jeremy W. Sherman’s answer here.
Please note that it does not use any private API, see the discussion there. The worst thing that can happen is that the view property of the UIBarButtonItem cannot be accessed. In this case, I use a default value:
var leftBarButtonItems = self.navigationItem.leftBarButtonItems
let rotatingButton = UIButton(type: .custom)
rotatingButton.setImage(UIImage(named: "LocalizationInUseNoFix"), for: .normal)
rotatingButton.addTarget(self, action: #selector(localizationButtonTapped), for: .touchUpInside)
rotatingButton.rotateStart()
// Get the width of the bar button items if possible, else set default
let leftmostBarButtonItem = leftBarButtonItems![0]
let barButtonItemWidth: CGFloat
if let leftmostBarButtonItemView = leftmostBarButtonItem.value(forKey: "view") as? UIView {
barButtonItemWidth = leftmostBarButtonItemView.frame.size.width
} else {
barButtonItemWidth = 40.0
}
rotatingButton.widthAnchor.constraint(equalToConstant: barButtonItemWidth).isActive = true
let barButtonItem = UIBarButtonItem(customView: rotatingButton)
leftBarButtonItems![2] = barButtonItem
self.navigationItem.leftBarButtonItems = leftBarButtonItems
This is working fine for me. Best way is identify item to replace and change the content
#IBAction func changeLeftItems(_ sender: Any) {
if let items = self.toolbar.items {
var addItems = [UIBarButtonItem]()
addItems.append(contentsOf: items)
let barItem = UIBarButtonItem(title: "L5", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.leftAction(_:)))
addItems.remove(at: 1)
addItems.insert(barItem, at: 1)
self.toolbar.setItems(addItems, animated: true)
}
}
I have one drop down image with one text field , uipicker. So when user press text field - uipicker will open to select the value and one done button will be there for uipicker. When user press that uipicker done button selected data will be added to text field value.
But i have added one image view at right corner of textfield. When user press text field and when uipicker open , that uiimageview will rotate upside and down. And when user press done button, that imageview will come normla postion.
Butthe problem is, my done action button is in seperate nsobject class.And my uiimage view in one view controller. What i did is ?. I just call the view controller uiimage view to nsobject class and i am making the image rotation.
But its crashing when i press done button .
Here my code in view controller :
lazy var ctDataPicker = CTDataPickerplayer()
#IBOutlet weak var sportsDropImage: UIImageView!
#IBOutlet weak var hobbiesDropImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
ctDataPicker.hobimage? = hobbiesDropImage as UIImageView!
ctDataPicker.spoimage? = sportsDropImage as UIImageView!
}
extension CricketFanViewController:UITextFieldDelegate{
func textFieldDidBeginEditing(textField: UITextField) {
selectedText = textField
if textField == Experience {
hobbiesDropImage.transform = CGAffineTransformMakeRotation(3.14)
sportsDropImage.transform = CGAffineTransformMakeRotation(0.0)
ctDataPicker = CTDataPickerplayer()
let indexPos = Hobbeies.indexOf(Experience.text!) ?? 0
ctDataPicker.showPicker(self, inputText: textField, data: Hobbeies,selectedValueIndex: indexPos)
}
else if textField == playedTeam{
hobbiesDropImage.transform = CGAffineTransformMakeRotation(0.0)
sportsDropImage.transform = CGAffineTransformMakeRotation(3.14)
ctDataPicker = CTDataPickerplayer()
let indexPos = Sports.indexOf(playedTeam.text!) ?? 0
ctDataPicker.showPicker(self, inputText: textField, data: Sports, selectedValueIndex: indexPos)
}
}
}
My NSObject class code:
import Foundation
import SwiftCountryPicker
class CTDataPickerplayer: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
var dataPicker: UIPickerView!
var inputText:UITextField!
var parent:UIViewController!
var pickerData: [String]!
var feetStr = String()
var inchStr = String()
var hobimage:UIImageView!
var spoimage:UIImageView!
func showPicker(parent:UIViewController,inputText:UITextField, data: [String], selectedValueIndex: Int){
self.inputText = inputText
self.parent = parent
self.pickerData = data
if dataPicker == nil {
dataPicker = UIPickerView(frame: CGRectMake(0,0,parent.view.frame.size.width, 216))
dataPicker.backgroundColor = UIColor.whiteColor()
dataPicker.dataSource = self
dataPicker.delegate = self
dataPicker.selectRow(selectedValueIndex, inComponent: 0, animated: true)
_selectedValue = self.pickerData.count > 0 ? self.pickerData[selectedValueIndex] : ""
}
inputText.inputView = dataPicker
// ToolBar
let toolBar = UIToolbar()
toolBar.barStyle = .Default
toolBar.translucent = true
toolBar.tintColor = UIColor(hex: "B12420")
toolBar.backgroundColor = UIColor.whiteColor()
toolBar.sizeToFit()
// Adding Button ToolBar
let doneButton = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(CTDataPickerplayer.doneClick))
let spaceButton = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .Plain, target: self, action: #selector(CTDataPickerplayer.cancelClick))
toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
toolBar.userInteractionEnabled = true
inputText.inputAccessoryView = toolBar
}
func doneClick() {
hobimage.transform = CGAffineTransformMakeRotation(0.0)
spoimage.transform = CGAffineTransformMakeRotation(0.0)
}
My app crash in done action button code here :
hobimage.transform = CGAffineTransformMakeRotation(0.0)
spoimage.transform = CGAffineTransformMakeRotation(0.0)
You made hobimage and spoimage "implicitly unwrapped optionals (Type UIImageView!.)
Think of the ! operator as the "crash if nil" operator. Any time you reference an implicitly unwrapped optional and it's nil, you crash.
Therefore either hobimage or spoimage is probably nil. You probably forgot to connect the outlets in Interface builder.
The problem is with your ctDataPicker, you have it initialized lazily at the top of your vc and assigning your imageViews in viewDidLoad. Now again you are intiailizing same object in your extension CricketFanViewController:UITextFieldDelegate
ctDataPicker = CTDataPickerplayer()
let indexPos = Sports.indexOf(playedTeam.text!) ?? 0
ctDataPicker.showPicker(self, inputText: textField, data: Sports, selectedValueIndex: indexPos)
Please check here and decide what is your requirement.
I'm creating a Pomodoro Timer. And I want change the Play bar button item to Pause when I press on it. I've already created the IBOutlet for this button and IBAction.
#IBOutlet weak var playButton: UIBarButtonItem!
#IBAction func startTimer(sender: AnyObject) {
self.playButton = UIBarButtonItem(barButtonSystemItem: .Pause, target: self, action: nil)
}
But this doesn't work. Please help.
try this,
func play() {
var pauseButton = UIBarButtonItem(barButtonSystemItem: .Pause, target: self, action: "pause") //Use a selector
navigationItem.rightBarButtonItem = pauseButton
//other stuff
}
func pause() {
var playButton = UIBarButtonItem(barButtonSystemItem: .Play, target: self, action: "play") //Use a selector
navigationItem.rightBarButtonItem = playButton
//other stuff
}
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.
I am trying to toggle between the play button and pause button in swift. I have a bar button item in the toolbar whose identifier is initially set to the play. I tried to search and found out the following piece of code but it does not work, looks like it works when the bar button is in the navigation bar
self.navigationItem.setLeftBarButtonItem(UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Play, target: self, action: "TheMethodThatTheButtonShouldCall"), animated: true)
You need to set items on UIToolbar to update toolbar items: call func setItems(_items: [AnyObject]?,animated animated: Bool) with your new items to update the toolbar's items
Source: https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIToolbar_Class/index.html#//apple_ref/occ/instm/UIToolbar/setItems:animated:
Implemented your question with the code as below. works in Swift 2. Please note I connected the IBAction outlet to playBtn
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBOutlet var sliderVal: UISlider!
#IBOutlet var theToolbar: UIToolbar!
var mySound = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().pathForResource("ColdPlay", ofType: "mp3")
do {
mySound = try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: path!))
}
catch{
print("error caught")
}
}
#IBAction func playBtn(sender: UIBarButtonItem) {
let theBarbuttonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Pause, target: self, action: "pauseBtn:")
let arrayBarButtonItem = [theBarbuttonItem]
theToolbar.setItems(arrayBarButtonItem, animated: true)
mySound.play()
}
#IBAction func pauseBtn(sender: UIBarButtonItem) {
let theBarbuttonItemB = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Play, target: self, action: "playBtn:")
let arrayBarButtonItemB = [theBarbuttonItemB]
theToolbar.setItems(arrayBarButtonItemB, animated: true)
mySound.pause()
}
}