Subview keeps moving when I push and pop navigation controller - ios

image before pushing
This is what it's supposed to look like originally. The slider's added as a subview of the main view from Xib file on viewWillLoad, and I don't add it again if the subview exists on viewDidLoad. When I push, I call hidesBottomBarWhenPushed on the other view controller.
This is what I happens when I pop back:
image after popping
I have no idea why the subview does that.

Whatever you have set for bottom slider in viewDidLoad is the first time setting when view comes appear on screen. After that you have hide slider on push action, and goes to second view….right?
But when you come back to your view with pop, then how view can identify that it have show or hide that slider…? So, when you come back-I mean pop that time viewWillAppear is called. Put you code there…
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// whatever you want to do, this is just for suggestion
if (bottomSlider.hidden == TRUE) {
bottomSlider.hidden = FALSE;
}
else {
bottomSlider.hidden = TRUE;
}
}

Related

iOS - pop a view controller by panning on the left edge, navigation bar disappears

So iOS 7 introduced this new feature that you can pop a view controller by panning on the left edge. Here is my problem: I have two view controllers, A and B, that are connected by a push segue. Both of the controllers have navigation bars (by embedding A in a navigation controller). The navigation bar in B will be hidden once the user enters B's scene, and can be shown if the user taps on the scene. If the user pans on the left edge of B while the navigation bar is hidden, the navigation bar in A will be hidden as well, which means that there is no way for the user to return further back from A. So is there a way to enforce A to always show the navigation bar regardless of B has hidden the bar or not? Or is there a easy way to prevent the pan gesture from taking effect? I read this post which suggested a way of preventing the pan, but I can't locate the property in storyboard.
EDIT: So I disabled the interactive pop gesture recognizer but that only solved half of the problem. The other half is that if I click the back button on the child view controller navigation bar when the navigation bar is disappearing, I am navigated back to the parent view controller without a navigation bar. I tried calling [self.navigationController setNavigationBarHidden:NO] in viewWillAppear and then viewDidLoad but it does not work. Is this some sort of bug in the SDK or am I missing something?
Here is the code for hiding the navigation bar in the child view controller
- (void)hideNavigationBar
{
if (self.navigationBarHidden == NO)
{
[UIView animateWithDuration:UINavigationControllerHideShowBarDuration animations:^{
self.navigationController.navigationBar.alpha = 0.0;
self.previewCollectionView.alpha = 0.0;
} completion:^(BOOL finished) {
self.navigationBarHidden = YES;
}];
}
}
Yes, you can enforce the navigation bar's appearance in the A viewController's -viewWillAppear method.
Also, since you cannot find the interactivePopGestureRecognizer property in the storyboard, you can use this line in the A viewController's -viewDidLoad method:
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
EDIT:
In the viewWillAppear method, you will have to call:
[self.navigationController setNavigationBarHidden:NO];
self.navigationController.navigationBar.alpha = 1.0;
I see a couple problems with your situation:
You disable the interactive pop gesture and you hide the nav bar from view controller B. How is the user supposed to intuitively go back?
The animation that hides your navbar in B may be causing the issue. If it's anything longer than a split second, that animation may not complete in time before you hit the back button and -viewWillAppear fires on A.
Your code in B hides the navigation bar for the navigation controller. The navigation controller that holds view controller A is the same instance that holds view controller B. If you hide the navigation bar when B loads, then you go back to A (not sure how you're doing that without a back button or a edge pan gesture), it should still be hidden.
You probably want NOT disable the gesture (so the user can intuitively go back) and turn the navigation bar back on in view controller A's -viewWillAppear, to cover the case where you turned it off in B:
if (self.navigationBarHidden == NO)
{
self.navigationController.navigationBar.alpha = 1.0;
self.previewCollectionView.alpha = 1.0;
self.navigationBarHidden = NO;
}

Accessibility: How to always set the focus on the navigation item's title view

I'm using a UINavigationController in my app.
When using VoiceOver the backButton has the focus, when a new ViewController is pushed.
I'd rather have the accessibilityLabel of the titleView been focused if the view appears,
so that its accessibilityLabel is read first.
Using UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.navigationItem);the titleView seems to be focused, when I create and push the view controller for the first time.
But when I come back from another view controller (pushed onto the first one), the focus is on the back button again.
I should've set the the accessibilityLabel of the titleView, not the navigationItem.
The following works:
- (void) viewDidLoad
{
...
self.navigationItem.titleView.accessibilityLabel = #"[text-to-speak]";
}
- (void) viewDidAppear
{
[super viewDidAppear];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.navigationItem.titleView);
}

Use destinationViewController button in a custom segue

My goal is to make a custom segue with a custom animation as follows:
I want the segue to cover a button from the sourceViewController with a button from the destinationViewController with an effect similar to the navigation controller's push effect, i.e. the new button is supposed to push the old button away from right to left.
I have been able to make the old button (from the sourceViewController) move away as desired:
[UIView animateWithDuration:1.0 animations:^{
// set the target frame for animated view
sourceViewController.optionsButton.frame = leftButtonTargetFrame;
} completion:^(BOOL finished) {
[navigationController pushViewController:destinationViewController animated:NO];
// reset the button's frame back to its original frame
sourceViewController.optionsButton.frame = leftButtonInitFrame;
}];
But I am struggling to make the new button (from the destinationViewController) move in. The reason is that I cannot access the destinationViewController's view elements: While performing the segue they are not instantiated. And I cannot animate a button that is not instantiated.
So how can I replace a button in the sourceViewController with a button from the destinationViewController?
The view of the destination view controller hasn't been initialized/loaded at the time when you try to access the buttons. To load the view of the destination view controller, you can simply access the view property. Do this before using the buttons: [destinationViewController view];
destinationViewController.view; would also work, but it would generate a compiler warning.
Background Information:
If you access the view property and its value is currently nil, the view controller automatically calls the loadView method and returns the resulting view.
The method loadView loads the view that the controller manages. You should never call this method directly.
You are correct that you cannot animate an object that does not yet exist. However, you can fake it.
Create a place-holder button that will look identical to the button that will be in the new view controller.
Animate it to the correct place.
As the destination view controller comes in, its button should be invisible.
After the the view controller is in place (i.e. the segue has finished) the destination view controller can ensure the proper placement if its button and make its actual button visible.
Hope this helps.

Present a UIScrollView when opening an App for the first time

I have an iPad App that I want to be compatible from iOS 5.0 to 6.0. My main view contains a scroll view z-indexed on the front, which is initially set to hidden. I also have a toolbar containing a button that cycle the scroll view hidden or not.
I would like to add a feature to present the scroll view as initially visible when the user opens the App for the first time to make the help visible by default to new users.
My code to cycle between visible and hidden is the following:
- (void)showHelpView:(id)sender {
BOOL hidden = [blackTranslucent isHidden];
[self.view bringSubviewToFront:scrollViewOutlet];
if (hidden) {
[scrollViewOutlet setHidden:FALSE animationStyle:KGAnimationFade duration:0.7];
[blackTranslucent setHidden:FALSE animationStyle:KGAnimationFade duration:0.5];
}
else {
[scrollViewOutlet setHidden:TRUE animationStyle:KGAnimationFade duration:0.5];
[blackTranslucent setHidden:TRUE animationStyle:KGAnimationFade duration:0.7];
}
}
where the sender is my toolbar button, blackTranslucent is a view on top of the main view and scrollViewOutlet is my scroll view IBOutlet.
Add a property "isNewUser" on NSUserDefaults in the application:willFinishLaunchingWithOptions: method which will only be written once by checking if the key exists.
In your main view in the viewDidLoad check this property if true make the view visible and update the key to false. if not just continue regularly.
Further information on NSUserDefaults
Hope that helps

dismissModalViewControllerAnimated resets contentOffset

I have a problem with my table view. When dismissing a modal view controller presented on top of it, it always scrolling to the top . I have tried observing the changes to contentOffset using KVO, but the one that messes my view goes behind it.
From the UITableViewController, when user finishes his task in the modal dialog, self.tableView.contentOffset is , I call:
[self dismissModalViewControllerAnimated:YES]
Subsequently, when the viewWillAppear:(BOOL)animated is called, the self.tableView.contentOffset is already set to 0,0.
Is this supposed to be happening? I am able to work around the issue by remembering the scroll position before presenting the modal view and restore it back in viewWillAppear after dismissing the modal view. But it seems wrong. Am I missing something?
I have found similar problem described in Dismiss modal view changes underlying UIScrollView.
It looks like this is default behavior of UITableViewController. I tested it in very simple app and It worked exactly as you said. If you don't like it, use UIViewController instead.
Here is how I work around this problem, so that the table view maintains the original scroll position. In my subclass of UITableViewController I have added:
#property (assign) CGPoint lastScrollPosition;
Then in the implementation, I have overridden the following:
- (void)viewWillAppear:(BOOL)animated
{
self.tableView.contentOffset = self.lastScrollPosition;
}
- (void)dismissModalViewControllerAnimated:(BOOL)animated
{
self.lastScrollPosition = self.tableView.contentOffset;
[super dismissModalViewControllerAnimated:animated];
}
If you want your table to initially appear scrolled to non-zero position, as I did, don't forget to initialize the lastScrollPosition in your viewDidLoad.

Resources