How to get the selected element of the iOS Voiceover - ios

I have an iOS Swift App and i want to detect which element is selected by the voiceover.
Have tried to send an UIAccessibilitySwitchControlStatusDidChangeNotification but i don't get this to work.
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "handleVoiceoverSelection",
name: UIAccessibilitySwitchControlStatusDidChangeNotification,
object: nil)
...
func handleVoiceoverSelection(){
println("!!!! element selected !!!!")
}
Is there any way?

Maybe check out UIAccessibilityFocus?
https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIAccessibilityFocus_Protocol/index.html

Related

How to print out the language when keyboard changes in iOS?

I have multiple keyboards in my Xcode iOS Simulator. I'm running Swift (I need the code to work in Swift), and when they keyboard input type is changed in my app (e.g. from English to Spanish), I want to know which language it has been changed to.
I have a function in my ViewDidLoad:
NotificationCenter.default.addObserver(self,
selector: #selector(changeInputMode(_:)),
name: UITextInputMode.currentInputModeDidChangeNotification, object: nil)
and this function that supports it.
#objc func changeInputMode(_ notification: Notification)
{
let inputMethod = UITextInputMode.activeInputModes.description
print("keyboard changed to \(inputMethod.description)")
}
The inputMethod description prints out this for me:
[<UIKeyboardInputMode: 0x6000027a28a0>, <UIKeyboardInputMode: 0x6000027ab2f0>, <UIKeyboardInputMode: 0x6000027bc9b0>, <UIKeyboardInputMode: 0x6000027bca50>, <UIKeyboardInputMode: 0x6000027b8ff0>, <UIKeyboardInputMode: 0x6000027b9090>]
I would like to get the language in simpler terms, such as "english" or "en" or something like that. How can this be achieved?
I also tried the following:
let language = UITextInputMode.currentInputMode()?.primaryLanguage
print(language)
but I got an error:
'currentInputMode()' is unavailable in iOS: APIs deprecated as of iOS 7 and earlier are unavailable in Swift
Thanks for your help in advance.

Swift: Listen to physical button up/down events on iOS device

I would like to perform one action when the user presses either volume button, and another when they stop pressing it, similar to what I can do by overriding touchesBegan() and touchesEnded.
I'm aware I can list to the volume level on change like so:
NotificationCenter.default.addObserver(self, selector: #selector(volumeChanged), name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"), object: nil)
#objc func volumeChanged(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
// do something here, such as a switch based off of "volumeChangeType"
}
}
}
However, once the user has turned the volume up or down all the way, events are no longer fired. Also, no event is fired when the user stops pressing the button. This makes sense, because I'm actually listening to a volume change event, not a volume button press event.
Is there a way to listen to physical button presses in iOS?
Take a look at this GitHub Repo which looks like it provides everything that you're asking for.

How to check that user is back from Settings

I am sending local notifications to my users, and I want to show the relevant title on the notification settings button.
If local notifications are off, this title should be "Notifications: off", and if local notifications are on, this title should be something like "Preferences".
Right now I'm checking this in viewDidLoad and viewDidAppear, and it works.
if UIApplication.sharedApplication().currentUserNotificationSettings()?.types.rawValue == 0 {
//the first title
} else {
//the second title
}
Except one case. If my user is changing notifications in the phone settings from "on" to "off" or vice versa, and after that he is back — the title is not changing (because this viewController already loaded and did appear).
How could I check that user is back from the Settings?
You can observe this notification when your app is come to foreground from inactive, the selector will be called everytime your app is opened again from background:
Put in viewDidLoad:
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.reloadData), name: UIApplicationWillEnterForegroundNotification, object: UIApplication.sharedApplication())
Put in viewDidDissapear or deinit:
NSNotificationCenter.defaultCenter().removeObserver(self)
Swift 5.5:
NotificationCenter.default.addObserver(
self,
selector: #selector(yourFunction),
name: UIApplication.willEnterForegroundNotification,
object: UIApplication.shared
)
And:
deinit {
NotificationCenter.default.removeObserver(self)
}

iOS Support External Keyboard Without Displaying One

Given a UIViewController, I would like to receive text input only from the external keyboard. Think UIKeyCommand but for any character (not just 'modified' ones).
However, when I try to implement that using UIKeyInput, it seems that iOS desperately wants to display a keyboard if there is no external one connected.
Is there any way to circumvent that? Specifically, to have the options to receive keystrokes from the keyboard if, and only if, one is connected?
After fiddling with a iPad for an hour, I finally have a good solution for this in swift. The other methods are weak or use 3rd party software. The reason why UIKeyboardWillShowNotification is getting fired even when an external keyboard is being used for an iPad is the shortcut bar existing. In order to disable the shortcut bar, do this:
let item : UITextInputAssistantItem = textField.inputAssistantItem
item.leadingBarButtonGroups = []
item.trailingBarButtonGroups = []
This covers most cases of what you need, but UIKeyboardWillShowNotification can still be fired if someone plugs their keyboard in at certain points of use. If you have the screen adjust, you can't afford any case for the user to experience this. Plus, you might want the shortcut bar for some reason. Regardless of what your desires are, this covers all cases of an external keyboard being used:
Add to viewDidAppear
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(LoginViewController.keyboardWillShow), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(LoginViewController.keyboardWillHide), name: UIKeyboardWillHideNotification, object: nil)
whenever you leave the view add this to anything that makes you leave
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
also add it to the deinit{} method to be thourough.
Now use these functions:
func keyboardWillShow(notification: NSNotification) {
// This code is an alternate way of checking for keyboard
var userInfo: [NSObject: AnyObject] = notification.userInfo!
let firstFrame = userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue
let secondFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue
let firstRect = firstFrame.CGRectValue()
let secondRect = secondFrame.CGRectValue()
let diff = abs(firstRect.origin.y - secondRect.origin.y)
let isFirstBigger = firstRect.origin.y > secondRect.origin.y
if firstRect != secondRect && diff != 55 {
if !isFirstBigger {
//animateViewToDefaultPosition()
} else {
//animateViewToPositionWhenKeyboardActive()
}
}
}
func keyboardWillHide() {
//animateViewToDefaultPosition()
}
The 55 is the height of the shortcut bar. You can remove it's functionality if you don't have one. The !isFirstBigger is used to check for when they unhook the keyboard and hook it back in during text field editing. It is also important that diff != 55 during that check because with a shortcut bar this would be the case when you did not want to animate the screen.
This is by far the best method I have seen after scouring Stack Overflow. If anyone finds a bug in the functionality, let me know, but I am confident it will take care of the pesky shortcut bar external keyboard issues. I hope this helps everyone else out there confused by all this!

In Swift, how to ivalidate NSTimer in AppDelegate when application going background?

I need to translate my iOS application from obj-c to swift. I have a NStimer in ViewController that loads metadata from shoutcast every 30 seconds, but when application resign active it stops, when enter foreground it runs again.
Edit: OK. Problem solved! I added two observers in viewDidLoad with name UIApplicationWillResignActiveNotification and UIApplicationWillEnterForegroundNotification, like below:
override func viewDidLoad() {
NSLog("System Version is \(UIDevice.currentDevice().systemVersion)");
super.viewDidLoad()
self.runTimer()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "invalidateTimer", name: UIApplicationWillResignActiveNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "runTimer", name: UIApplicationWillEnterForegroundNotification, object: nil)
}
and I made two functions. First one for run timer:
func runTimer(){
loadMetadata()
myTimer.invalidate()
NSLog("timer run");
myTimer = NSTimer.scheduledTimerWithTimeInterval(30.0, target: self, selector: "loadMetadata", userInfo: nil, repeats: true)
let mainLoop = NSRunLoop.mainRunLoop()
mainLoop.addTimer(myTimer, forMode: NSDefaultRunLoopMode)
}
and second to stop it:
func invalidateTimer(){
myTimer.invalidate()
NSLog("timer invalidated %u", myTimer);
}
I hope this can help someone. :)
I suggest you use the appropriate system for your task: https://developer.apple.com/library/ios/documentation/iphone/conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW56
Apps that need to check for new content periodically can ask the
system to wake them up so that they can initiate a fetch operation for
that content. To support this mode, enable the Background fetch option
from the Background modes section of the Capabilities tab in your
Xcode project. (You can also enable this support by including the
UIBackgroundModes key with the fetch value in your app’s Info.plist
file.)...
When a good opportunity arises, the system wakes or launches your app
into the background and calls the app delegate’s
application:performFetchWithCompletionHandler: method. Use that method
to check for new content and initiate a download operation if content
is available.

Resources