How can I make my app permanently display volume instead of ringer? - ios

How can I make my app permanently display volume instead of ringer while the user is in my app. Currently when using the application the app displays the ringer sound adjuster.

You can use MPVolumeView .
let volumeViewHolder = UIView(frame: CGRect(x: 20, y: 100, width: view.bounds.size.width - 40, height: 200))
volumeViewHolder.backgroundColor = UIColor.gray
let volumeView = MPVolumeView(frame: volumeViewHolder.bounds)
volumeView.showsRouteButton = true
volumeView.showsVolumeSlider = true
volumeViewHolder.addSubview(volumeView)
view.addSubview(volumeViewHolder)
Its just a demo. You can have your version with frames and styling as per your requirements

Related

Airplay support iOS

I'am trying to add airplay for my audio app. Here is my code
let buttonView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
let routerPickerView = AVRoutePickerView(frame: buttonView.bounds)
routerPickerView.tintColor = UIColor.white
routerPickerView.activeTintColor = UIColor.white
buttonView.addSubview(routerPickerView)
self.btnsStack.addArrangedSubview(buttonView)
This works well with my Mac, but when I try to play it with my Samsung Smart TV, there is a loader keeps on spinning. I tried connecting my TV with other apps like Spotify and it works.
Found my solution, so for casting airplay with smart tv one line of code is must
player?.allowsExternalPlayback = false
player is your AVPlayer.

iOS UI Test: Wait for exist fails for dynamically added button

My application does a SDK auto update and initialization when it launches. When it completed I am adding a button to check if auto update and initialization are completed in my UI test:
let hiddenButton = UIButton(frame: CGRect(x: 0, y: 0, width: 1, height: 1))
hiddenButton.setTitle("databaseUpdated", for: .normal)
hiddenButton.accessibilityIdentifier = "databaseUpdated"
self.view.addSubview(hiddenButton)
I have tried following lines to check it but it always fails:
XCTAssertTrue(app.descendants(matching: .button)["databaseUpdated"].waitForExistence(timeout: 60))
XCTAssertTrue(app.children(matching: .button)["databaseUpdated"].waitForExistence(timeout: 60))
XCTAssertTrue(app.otherElements["databaseUpdated"].waitForExistence(timeout: 60))
XCTAssertTrue(app.buttons["databaseUpdated"].waitForExistence(timeout: 60))
I have confirmed that my button is in view hierarchy using Debug View Hierarchy:
UPDATE
I have decided to add the button in viewDidLoad with different identifier and update it when SDK is initialized:
private let button = UIButton(frame: CGRect(x: 0, y: 0, width: 1, height: 1))
override public func viewDidLoad() {
super.viewDidLoad()
button.isAccessibilityElement = true
button.accessibilityTraits = .button
button.accessibilityIdentifier = "initial"
view.addSubview(button)
}
when SDK is initialized it is set to:
button.accessibilityIdentifier = "databaseUpdated"
and here is what I see when I inspect the button in view debugger:
still test is failing to find it.
UPDATE 2
I am able to find the button using Accessibility Inspector:
Check if the ViewController that you add the button is visible when you run the query. If not your query will fail.

Swift: how to create FDWaveformview Dynamically

I want to show wave of multiple audios in scrollview using swift4 and xcode 9. I am using cocoapos library FDWaveFormView for showing wave of audio file. For this I have to create fdwaveformview dynamically. Fdwaveformview works fine if I create this in story board. But it shows an error when create dynamically in swift class.
Code:
for index in selectedAudios {
audioQueue.append(AVPlayerItem(url: index as! URL))
print("aduio url: \(index)")
let waveForm = FDWaveformView(frame: CGRect(x: 0, y: 0, width: 300, height: 150)) // error
audio_scroll_view.addSubview(waveForm!)
}
Screen Shot Of Error
Error: FDWaveformView initializer is inaccessible due to 'internal' protection level
Solution:
let frame = CGRect(x: 0, y: 0, width: 300, height: 100)
let waveform = FDWaveformView()
waveform.frame = frame
audio_scroll_view.addSubview(waveform)

Reproducing Music App's NavigationBar Animation

In my project I want to achieve a very similar animation like in the Artist-ViewController of the stock Music App.
When the UITableView scrolls to a specific offset the navigationBar's tintColor, the color of the title and the color of the statusbar changes.
To achieve that I added an UIView (I named it containerView) as a subView of the UINavigationBar and inside that containerView I added a UIBlurEffect. Now when the tableView scrolls I am listening to scrollViewDidScroll to change the earlier named attributes which works really good.
containerView.frame = CGRect(x: 0, y: -(statusBarHeight), width: UIScreen.main.bounds.width, height: frame.height + statusBarHeight)
containerView.clipsToBounds = true
insertSubview(containerView, at: 0)
let blurEffect = UIBlurEffect(style: .extraLight)
overlayView.effect = blurEffect
overlayView.backgroundColor = unOverlayColor
let height = frame.height + statusBarHeight
overlayView.frame = CGRect(x: 0, y: containerView.frame.height, width: containerView.frame.width, height: height)
containerView.addSubview(overlayView)
My only problem is that the containerView is placed above the UINavigationBar's navigationItems and therefore hides them.
So my question is how can I add the containerView behind the navigationItems to the UINavigationBar?
I figured out that it has to be something with the way how navigationBars are handled in iOS 11 because on iOS 10 everything works fine.

How can I properly place a UIButton on top of a loaded SFSafariViewController?

I have read many articles about the SFSafariViewController and I believe that it offers splendid functionality in iOS apps. However, when I load my SFSafariViewController, I intentionally hide the navigation bar because I want one custom fixed button in the upper left corner to dismiss the view controller.
override func viewDidAppear(_ animated: Bool) {
let safariViewController = PSSafariViewController(url: URL(string: blogUrl)!, entersReaderIfAvailable: true)
present(safariViewController, animated: false) {
var frame = safariViewController.view.frame
let OffsetY: CGFloat = 44
frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY)
frame.size = CGSize(width: frame.width, height: frame.height + OffsetY)
safariViewController.view.frame = frame
let btn: UIButton = UIButton(frame: CGRect(x: 100, y: 400, width: 100, height: 50))
btn.backgroundColor = UIColor.green
btn.setTitle("Click Me", for: .normal)
btn.addTarget(self, action: #selector(PSBlogViewController.buttonAction), for: UIControlEvents.touchUpInside)
btn.tag = 1 // change tag property
btn.isOpaque = true
safariViewController.view.addSubview(btn)
safariViewController.view.bringSubview(toFront: btn)
print(btn.description)
}
}
As you can see, I alter the frame so that the bar at the top is not visible. That code runs fine. But when I try to add a UIButton, it appears briefly and then is covered when I run the app. It's a simple blog reader app that uses the SFSafariViewController. Maybe Apple doesn't want developers running around messing with this, but any solutions or workarounds to make the button stay visible are greatly appreciated!
Here's the info about the button: 0x7f950b618db0; frame = (100 400; 100 50); tag = 1; layer = CALayer: 0x60000023ab60
Why don't you use one of the other WebView classes to get the extra functionalities you desire?
5.1.1 (iv) SafariViewContoller must be used to visibly present information to users; the controller may not be hidden or obscured by
other views or layers. Additionally, an app may not use
SafariViewController to track users without their knowledge and
consent.
It is definitely true that Apple won't want the SFSafariViewController to be obscured. However, I did figure out that when I present it, in the completion block I can add a button and what was causing trouble was that I had to increase the zPosition of the layer of the button's view like so:
present(safariViewController, animated: false) {
var frame = safariViewController.view.frame
let OffsetY: CGFloat = 44
frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY)
frame.size = CGSize(width: frame.width, height: frame.height + OffsetY)
safariViewController.view.frame = frame
self.btn = UIButton(frame: CGRect(x: 5, y: 50, width: 50, height: 50))
self.btn.layer.cornerRadius = 25
self.btn.backgroundColor = UIColor(red: 0, green: 170/255, blue: 240/255, alpha: 0.5)
self.btn.setTitle("←", for: .normal)
self.btn.addTarget(self, action: #selector(safariViewController.buttonAction(sender:)), for: .touchUpInside)
self.btn.tag = 1 // change tag property
self.btn.isOpaque = true
safariViewController.view.addSubview(self.btn)
safariViewController.view.bringSubview(toFront: self.btn)
self.btn.layer.zPosition = safariViewController.view.layer.zPosition + 1
for subview in safariViewController.view.subviews {
subview.isUserInteractionEnabled = false
}
self.btn.isEnabled = true
self.btn.isUserInteractionEnabled = true
//print(self.btn.description)
}

Resources