Search code examples
iosobjective-cuiscrollviewinterface-builderuistatusbar

Does UIScrollview works correct with UIStatusbar?


my problem is related with UIScrollview. lets describe it,

I have signup screen which has a scrollview, initially scrolling is not enabled. when keyboard appears I will enable scrollview and when keyboard hides again I am disabling scrolling. my scrollview’s width and height is same as its default view, I have applied horizontal, and vertical centre in container as well as top, bottom, leading and trailing edges are zero (i.e. it is equal to default view). I have a signup button which navigates to signup screen, and applied bottom constraints (bottom space constraints = 0), also I m using keyboard notification for appear and hide.

Actual Problem: when tap textfield keyboard appears, scrollview scrolls, and when I dismiss the keyboard the scrollview came down, but this time the signup button will move little bit up (like bottom space has 20 points constraints).

First time its like scrollview starts after status bar, but when keyboard appears and hides its like scrollview is renders over view including status bar.

Do I need to add any constraints related to Top/Bottom Layout Guide in IB? or do I need to add any constraints related to in viewDidLoad

Code for Keyboard notification.

-(void)keyboardWillShow:(NSNotification *)notification {
    [self.navigationController.navigationBar setBackgroundImage:nil
                                                  forBarMetrics:UIBarMetricsDefault];
    self.navigationController.navigationBar.shadowImage = nil;
    self.ContentScrollView.scrollEnabled=YES;
    NSDictionary *userInfo = [notification userInfo];

    CGRect keyboardFrameInWindow;
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];

    // the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
    CGRect keyboardFrameInView = [self.ContentScrollView convertRect:keyboardFrameInWindow fromView:nil];

    CGRect scrollViewKeyboardIntersection = CGRectIntersection(self.ContentScrollView.frame, keyboardFrameInView);
    UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);

    // this is an old animation method, but the only one that retains compatibility between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
    [UIView animateWithDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0.0 options:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue] animations:^{
        self.ContentScrollView.contentInset = newContentInsets;
        self.ContentScrollView.scrollIndicatorInsets = newContentInsets;

        /*
         * Depending on visual layout, _activeField should either be the input field (UITextField,..) or another element
         * that should be visible, e.g. a purchase button below an amount text field
         * it makes sense to set _activeField in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
         */
        if (_activeField) {
            CGRect controlFrameInScrollView = [self.ContentScrollView convertRect:_activeField.bounds fromView:_activeField]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
            controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, 0); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.

            CGFloat controlVisualOffsetToTopOfScrollview = (controlFrameInScrollView.origin.y - self.ContentScrollView.contentOffset.y)+10;
            CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;

            // this is the visible part of the scroll view that is not hidden by the keyboard
            CGFloat scrollViewVisibleHeight = self.ContentScrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;

            if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
                // scroll up until the control is in place
                CGPoint newContentOffset = self.ContentScrollView.contentOffset;
                newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);

                // make sure we don't set an impossible offset caused by the "nice visual offset"
                // if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
                CGFloat maxScrollViewHeight = MAX(self.ContentScrollView.frame.size.height, self.ContentScrollView.contentSize.height);
                newContentOffset.y = MIN(newContentOffset.y, maxScrollViewHeight - scrollViewVisibleHeight);
                [self.ContentScrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
            } else if (controlFrameInScrollView.origin.y < self.ContentScrollView.contentOffset.y) {
                // if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
                CGPoint newContentOffset = self.ContentScrollView.contentOffset;
                newContentOffset.y = controlFrameInScrollView.origin.y;

                [self.ContentScrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
            }
        }

    } completion:NULL];
}


- (void)keyboardWillHide:(NSNotification *)notification {

    NSDictionary *userInfo = [notification userInfo];
    [UIView animateWithDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]doubleValue ] delay:0.01 options:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]intValue] animations:^{
        UIEdgeInsets contentInsets = UIEdgeInsetsZero;
        self.ContentScrollView.contentInset = contentInsets;
        self.ContentScrollView.scrollIndicatorInsets = contentInsets;

        CGPoint scrollPoint;
            self.ContentScrollView.scrollEnabled=NO;
            scrollPoint = CGPointMake(0.0, 0.0);

        [self.ContentScrollView setContentOffset:scrollPoint animated:YES];

    } completion:^(BOOL finished){
        __weak typeof(self) weakSelf=self;
        [weakSelf.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
        weakSelf.navigationController.navigationBar.shadowImage = [UIImage new];
    }];

}

Image IB Screen shot

If further required I will send the screen shots of before and after keyboard notification.

Thank You.


Solution

  • From Documentation

    A Boolean value that indicates whether the view controller should automatically adjust its scroll view insets.

    Declaration

    @property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets
    

    Discussion

    Default value is YES, which allows the view controller to adjust its scroll view insets in response to the screen areas consumed by the status bar, navigation bar, and toolbar or tab bar. Set to NO if you want to manage scroll view inset adjustments yourself, such as when there is more than one scroll view in the view hierarchy.

    Write self. automaticallyAdjustsScrollViewInsets=NO; in viewDidLoad and try