Change bar button item programmatically after user presses it Swift - ios

I am trying to make a feature where if the user presses the speaker button (a bar button item), then a speaker with a slash through it will replace the original button. Is there an easy way of doing this? I know that it must be done programatically but I can't figure out how to replace the speaker button with a different button.
[Here is a screenshot of my storyboard]
: https://i.stack.imgur.com/EL3df.png

Add an action for UIBarButtonItem on your UIViewController class by control dragging it into the ViewController's declaration. Then change the item
#IBAction func barButtonAction(_ sender: UIBarButtonItem) {
sender.image = UIImage(named: "myNewImage")
}

Related

How to access a right item button on navigation bar in XCUITest?

I am writing UITest cases for my iOS Swift app. In the app I have created a custom right item button on the navigation bar in this way:
let barButtonItem = UIBarButtonItem(customView: customView)
navigationItem.rightBarButtonItem = barButtonItem
Now I don't know how to access this custom right item button in XCUITest and really need some help. Thanks in advance.
You cannot access a UIBarButtonItem, because it is not a real UIElement (it is not a UIView subclass), but you probably want to access the UIButton inside your right bar button item anyway.
There are several ways how you could access the button, here are two ideas:
1. Query the first button in the navigation bar
let rightNavBarButton = XCUIApplication().navigationBars.children(matching: .button).firstMatch
XCTAssert(rightNavBarButton.exists)
That way you access the first UIButton inside a UINavigationBar.
This only works if there is only one button in your navigation bar. So it will break when you add another button.
2. Use an accessibility identifier
You can define a accessibility identifier for the button inside your right bar button item and use that to access it during the test:
In your app:
let barButtonItem = UIBarButtonItem(customView: customView)
barButtonItem.accessibilityIdentifier = "navbarRightItem"
navigationItem.rightBarButtonItem = barButtonItem
In your test:
let rightNavBarButton = XCUIApplication().navigationBars.buttons["navbarRightItem"]
XCTAssert(rightNavBarButton.exists)
Just make sure you are using accessibilityIdentifier and not accessibilityLabel. Because accessibilityLabel will be read by VoiceOver for handicapped users and should contain useful text.
You have to assign an accessibilityIdentifier to the button
barButtonItem.accessibilityIdentifier = “barButtonItemID”
If didn’t work set IsAccessibilityElement to YES/true

How to detect when the RPSystemBroadcastPickerView is tapped

I am using RPSystemBroadcastPickerView to start a system-wide screen recording from my app. The RPSystemBroadcastPickerView is completely autonomous in starting the recording and everything, which I guess makes sense - only user can start the screen recording by explicitly tapping the button.
I need to know when the RPSystemBroadcastPickerView is tapped. Right now the UI is showing keyboard, which I want to keep showing (it is a chat app). However, the form showing the list of broadcast extensions to pick one is being shown under the keyboard. See following image:
This effectively prevents the user to start the broadcast. If I knew when the user tapped RPSystemBroadcastPickerView, I could manually hide the keyboard at that moment. Any suggestions?
I did not find any callbacks for that, but you can create your transparent button, add it above the RPSystemBroadcastPickerView. When user will tap on your button you will be able to hide the keyboard and than transfer the action to the RPSystemBroadcastPickerView using the code:
for subview in screenSharingProviderPickerView.subviews {
if let button = subview as? UIButton {
button.sendActions(for: UIControlEvents.allTouchEvents)
}
}
I found similar solution to accepted answer, but you don't need to create transparent button.
I just add additional target-action pair to the picker button dispatch table, with #selector which will be fired, when button is pressed.
// picker is an instance of RPSystemBroadcastPickerView
for subview in picker.subviews {
if let button = subview as? UIButton {
button.addTarget(self, action: #selector(pickerAction), for: .touchUpInside)
}
}
// You can also accept _ sender: UIButton as parameter, if you need to.
#objc func pickerAction() {
// called when user press on RPSystemBroadcastPickerView
}
Note: Keep in mind that, if Apple change hierarchy of this view in the future, you probably need to update application as well.

Keep search bar cancel button tint color even when keyboard dismiss

I have a search bar with cancel button in my navigation bar and when keyboard dismisses, my cancel button changes color and become inactive until I click on it again. Is there a way to keep my cancel button state the same every time?
This is before I dismiss keyboard
and this is after I dismiss keyboard
I want my cancel button stay the same before and after keyboard dismissal. Thank you for your help!
I think you you can’t ,the way i did it is made button on the right with a width ,when the user press on search bar,the button width change,and even if the the user search and dissmiss keyboard it still active,but when pressed the width is bacl to zero,and search bar is end edliting
Then when cancel is pressed just make width of it is zero
implementaion:
1-add you a button to the right of tabbar-for constrains for the button:your desired bottom contrain,and width is zero,your desired height,trailing is also zero.
2-for tab bar constrains: trailing must be zero,the rest as you like
3- dont forget to use UISearchBarDelegate
4-in viewdidload set yoursearchbar.delegate = self
5-
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
//wcha.hey = hello.text!
this will fire when tuching search bar for first time
self.allview.layoutIfNeeded()
yourcancelbutton.constant = your desired width
}
6-
#IBAction func yourcancelbutton(_ sender: Any) {
yourbutton.constant = 0
self.view.endEditing(true)
}

Swift - Start recording audio when a user taps a uitabbaritem

My iOS app uses a tab bar controller, and when a user taps the "record" icon uitabbaritem in the tab bar, I want the icon image to change and audio to start recording straight away, then when the new "record" image is tapped, I want the image to revert back to the original image. I am having trouble implementing both the image switch and starting the audio recording because I don't know how to properly access the uitabbaritem or the tabbarcontroller.
In Swift, how do I access the uitabbaritem so I can perform these actions?
Presumably you'll want to show some kind of UI while recording, correct? You could simply allow the tab bar item to perform its usual function and switch to/load a view controller. In the view controller, immediately kick off recording.
You can do as below to assign image to tab bar.
let myTab = self.tabBarController!.viewControllers?[0].tabBarItem as UITabBarItem! //get the desire tab by passing index as 0,1,2,3... Currently i am pointing to first tab.
myTab.image = UIImage(named: "image1")//This image will appear when tab is not selected
myTab.selectedImage = UIImage(named: "image2")//This image will appear when tab is selected
Now to check wether you are clicking same tab or not, implement the delegate method,
func tabBarController(tabBarController: UITabBarController, didSelectViewController viewController: UIViewController) {
if viewController.tabBarItem.tag == 0 { // assuming this is your desired so called record tab
if !self.isRecordSelected {// create a property isRecordSelected of Bool type
tabBarItem.selectedImage = UIImage(named: "new record image")//This image will appear when tab is recording starts.
self.isRecordSelected = true
} else {
tabBarItem.selectedImage = UIImage(named: " revert image")//This image will appear when tab is recording stops.
self.isRecordSelected = false
}
}
}
Give tag number to each tab, so that it will be easy for identification. Set the UITabBarDelegate delegate in your class.

How do I use a switch statement to find if a UIButton is pressed?

I’m making an ios application and am having trouble using a switch statement to see if a UIButton element was pressed.
This is who I want the end product to work: I have multiple uncolored images (by uncolored I mean white, a UIImage). When an uncolored image is tapped a subview opens with colored boxes (UIButtons, 24 of them, each with individual colors.). When a colored box button is selected and the back button on the toolbar is pressed, the subview closes and the original view re-appears with the uncolored image (the one selected to open the subview) now colored with the desired color selected in the subview.
I want to use a switch statement to find which uncolored image and which color was selected (all UIButton elements). I do not know what to put as an expression in the switch statement because I’m dealing with UIButtons. The rest of the switch statement compares the value of the UIButton element to see if it’s equal to YES (when the button is pressed), and if it is, it returns a string. I also want to know how to connect an IBAction to a UIImage (so when the images are tapped a subview opens).
I'm a little rusty on iOS development but you could probably do the following:
Set the buttons to the same event handler and use the sender attribute to get to the tag element of the button which you can specify to each button.
- (IBAction) doStuff:(id) sender {
UIButton *button = (UIButton*) sender;
switch(button.tag)
{
//do stuff
}
If this doesn't work out for you, you can use any of the button properties you see fit to differentiate between them such as title, title color and so on.
For best practices i'd advise you to also check if the sender is of type UIButton before trying to cast it into an object.
For Swift 3.0, we do not need to observe the tags any more. Just keep a reference to your buttons (IBOutlet or some private variable), and switch on the button itself, using the Identifier Pattern.
import UIKit
class Foo {
// Create three UIButton instances - can be IBOutlet too
let buttonOne = UIButton()
let buttonTwo = UIButton()
let buttonThree = UIButton()
init() {
// Assign the same selector to all of the buttons - Same as setting the same IBAction for the same buttons
[buttonOne, buttonTwo, buttonThree].forEach{(
$0.addTarget(self, action: Selector(("buttonTapped")), for: .touchUpInside)
)}
}
func buttonTapped(sender: UIButton) {
// Lets just use the Identifier Pattern for finding the right tapped button
switch sender {
case buttonOne:
print("button one was tapped")
case buttonTwo:
print("button two was tapped")
case buttonThree:
print("button three was tapped")
default:
print("unkown button was tapped")
break;
}
}
}
// Example
let foo = Foo()
foo.buttonTapped(sender: foo.buttonOne)

Resources