Is there any way to know when the cancel/dismiss button is tapped on the Apple Watch?
- (void)didDeactivate
Is not an option because that is called whenever the watch goes dark. I'm trying to sync data with the parent iPhone app and this makes it tough to cancel an operation on the parent app.
While you can't get the cancel directly, you can tell which view controller is active (because your code displayed it) and then tell when they switch. So you can set some flags on display and on de-activate, to tell when the view controller with the cancel button goes away.
Think of it another way, if your view controller disappears and another one displays, the activate of the other controller tells you the watch did not sleep.
Unfortunately, the current version of WatchKit has no method to determine if the Cancel button is tapped. The closest you'll get is the didDeactivate event that you've already mentioned.
Related
I have noted recently that each of my app view has one particular bug/behaviour: if user taps too fast on a UI component when the view appears, the tap is simply ignored. If the user wait a bit before tapping, the tap works.
Storyboard is used for the storyboard, tap gesture recognisers are on UIImageview and using IOS 10.2.
Through different forums i have read about the following options:
nest the call of "present view controllers" in main thread
Call CFRunLoopWakeup before presentviewcontroller
Add programatically the TapGesturerecognizer
change the states of "delays touches end" and "delays touches began"
disable 3d touch option as similar symptoms was reported to happen in other apps
All above have been unsuccessful.
Anyone would have met similar issues with the first tap just after the view load?
[Update: I realise this misbehaviour is not specific to this app. Two tests to try:
create an xCode Project for iPhone and two view controllers Controller A and Controller B. Two buttons : a button on Controller A view to go to Controller B view and a button Back in Controller B view to go back to Controller A view. Tap to go from View A to B, tap back in B and try immediately to tap on button to go to B. First tap doesn't work either.
Go in Settings of the iPhone. Tap On Notifications. Press On Settings to go back to Main Settings screen, Tap immediately back on Notifications. If fast enough, first tap doesn't work. Second tap works or waiting a bit before first tap.
Question is now: this looks like a common problem across iPhone apps. Would you know if there would be a common setting somewhere? or is this a common bug for given IOS version ?
]
Stephane
This is a general problem (the moment when the view controller is changed, the first tap will be ignored), but this is not a bug that will happen only because the switch view controller's animation has not yet been completed. If you set the animation to false , then the view controller can immediately respond to your click, no matter how fast (anyway faster than your hand) :)
Is there a way to prevent the user from dismissing a modal controller?
I think it is pretty common to want to "block" the main Watch App interface while asking the user to open the iPhone counterpart or to perform some action there.
My current solution is to present again the controller when it gets dismissed but its clunky.
There's a somewhat kludgy way to get around this issue using reloadRootControllers. When you call reloadRootControllers(withNamesAndContexts:) with the name of a WKInterfaceController that you've named in your storyboard, it has a similar effect to presenting that controller modally. However, since it's now the root controller, it doesn't have a cancel button. I don't really like this, but it does get the job done.
Note this method is deprecated since watchOS 4.
Apple Documentation on reloadRootControllers(withNamesAndContexts:)
The trick is to make the modal screen fullscreen and change the inset top value for your main group.
You can't prevent a modal interface controller from being dismissed, as the system automatically dismisses it when the title is tapped.
Since your code isn't asked if it should happen, but only knows that it is happening, there's no way to intercept or cancel that action. The WKInterfaceController documentation briefly touches on this.
When the user taps the title string, WatchKit automatically dismisses the modal interface without taking any further actions.
What can you do?
While you don't know when the Cancel title is tapped, there is a hack which "hides" the Cancel title.
This may confuse users who might wonder how to dismiss the modal, or mislead others into thinking the modal couldn't be dismissed.
What does the HIG recommend?
Circumventing a Human Interface Guideline would likely degrade the entire user experience.
The top-left corner of the modal sheet is reserved for the Close button, which dismisses the interface.
Some users might be frustrated or annoyed if
there is no apparent way to cancel, or
the modal presents itself again after repeatedly being cancelled.
Since the user expects to be able to dismiss the modal, perhaps you could allow them to do just that, then simply display some form of reminder in the presenting interface controller (to log in, or enable permissions).
iOS 7 introduces edge swiping to navigate backwards in a navigation controller (so long as you don't override the leftBarButtonItem, among other things).
Imagine I'm implementing an app similar to Apple Notes. In Apple's app, once the user taps into a note, there is a Back button on the top left, and a Done button on the top right. This view controller is automatically saved after the user navigates away. Even if the user swipes backwards while still editing the note, it will auto-save.
One way to implement this is to write to disk on each key stroke. However, I'm looking for a more efficient implementation.
Which method should I override to perform my auto-save?
To be clear, the auto-save code should be invoked in these three cases:
The user taps the Back button
The user swipes backwards
The user taps the Done button
So far, I've been implementing the save logic in viewWillDisappear, this minimizes the amounts of writes, and also takes care to save if the user kills the app.
Additionally, instead of implementing save logic in the Done button, the Done button can simply call:
[self.navigationController popViewControllerAnimated:YES];
... (e.g. via a delegate, or unwind segue) and it will automatically save as well. All three code paths will go through viewWillDisappear.
Although it could technically be implemented in viewDidDisappear, if the previous view controller needs to display the updated data, this method will be too late.
For more complex view controllers (e.g. those that have destructive behavior once the view controller is dismissed), there are several other things to consider:
Should the save be called if a modal is presented above the current view controller? (e.g. In Apple Notes, imagine that the share button launched a modal; should it save when you tap on this button?). If it is important not to save at this time, you can read the value of presentedViewController. If it has a value, that means viewWillDisappear is being called because a modal is being presented above it.
Should the save be called if a view controller is pushed on to the current navigation stack? (e.g. Again, in Apple Notes, if the share button used a push instead of a modal, should it save?) You can check the value of isMovingFromParentViewController in this case.
If the user taps the home button to quit your app, should it save?
If the user begins swiping backwards then cancels the swipe to stay on the current screen, should it save?
Imagine the view controller is in a modal, when the modal is dismissed should the destructive action happen? Check isBeingDismissed in this case.
Same as above, but imagine the view controller is the second page in a navigation controller than is being presented.
I have a situation in my app where a navigation controller pushViewController:animated:YES is triggered by a user. The user can also trigger a popViewController:animated:YES by tapping another control. The intent is that the popViewController is the undo or inverse of the pushViewController.
However, if the user triggers the popViewController:animated:YES while the pushViewController animation is still happening, I get a message logged to the console:
2014-08-22 08:26:36.601 MyApp[22380:60b] nested pop animation can result in corrupted navigation bar
2014-08-22 08:26:36.960 MyApp[22380:60b] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
And indeed, the navigation bar does get corrupted: the back button is no longer visible. I have to go do something else then come back to the affected page in my app to get it working properly again.
What can I do to avoid this race condition? My first thought was protect the popViewController call with a check to see if a current navigation animation is already occurring, and waiting for that to finish (or even canceling the popViewController call completely). However, I haven't been able to find a way of detecting that an action is already occurring.
There are two solutions to this problem. I suggest you to implement first one.
1 . Avoid user interaction on multiple controls at a time by setting exclusive touch to them.
Set exclusiveTouch property to YES for those controls if they shares superView(parent view) else you will have to set this property YES to their parent views.
2 . Implement UINavigationControllerDelegate protocol in that view controller where user is tapping multiple controls at a time.
– navigationController:willShowViewController:animated:
– navigationController:didShowViewController:animated:
Set a flag when first delegate method gets called & reset it in second. Use this flag on every push/pop operation.
I'm trying to add some finer control to the Storyboard controller and I hit a blockage with the back button.
I have a basic Storyboard with push transition. I want to be able to catch when the user presses on the back button (the one generated automatically) and decid if I want the view to go back or not.
The scenario is to show a message to the user asking if he wants to go back warning him that he is going to lose his work if he does,
Sounds simple, yet I can't find how to do it.
Any ideas
You don't get any sort of message by default when the back button is pressed. If you want to provide this sort of functionality, you have two options:
1) Provide a custom back button and set it as the leftNavigationItem of your UIViewController's navigation bar
2) Subclass UINavigationController and override a method such as popToRootViewController:animated:
Try using UIAlertView Delegate.
In your buttonPressed Action, provide an alert view with message with two buttons YES and NO.
define button at index action for YES and NO -ie- YES: dismiss current view and NO: remain on current view.
Search Apple Docs on alert view delegate