TPKeyboardAvoiding icon indicating copy to clipboard operation
TPKeyboardAvoiding copied to clipboard

Scrollview's content too tall after keyboard disappears

Open danray0424 opened this issue 12 years ago • 20 comments

I added a UIScrollView to my view, and put all my content inside it. This is on the DetailController of a UISplitView, as generated from the Xcode template. We're inside a UINavigationController in the detail pane.

TPKeyboardAvoiding scrolls things up out of the way when the keyboard appears. Brilliant. When the keyboard disappears, the content comes down, but after returning to position the content in the scrollview is offset northward by the height of the navigationBar, and is touch-enabled, so it can be manually scrolled up and down by that amount.

danray0424 avatar Dec 13 '13 14:12 danray0424

I can confirm this issue exists.

arietis avatar Dec 18 '13 11:12 arietis

I'm getting this too...

nathankot avatar Dec 19 '13 22:12 nathankot

I got this too, it appears the trouble is with this method for calculating the underlying content size inside the scrollview:

-(CGSize)TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames {
    CGRect rect = CGRectZero;
    for ( UIView *view in self.subviews ) {
        rect = CGRectUnion(rect, view.frame);
    }
    rect.size.height += kCalculatedContentPadding;
    return rect.size;
}

The scrollview inserts two subviews for the scroll indicators that throw off the calculation. I couldn't figure out a way to exclude the scroll indicator views from that for loop. I did find that if I turned off the scroll indicators completely, the issue goes away.

intrepidmatt avatar Dec 31 '13 20:12 intrepidmatt

Beautiful, that fixes it.

For others' reference, if you're using IB to make the connection between your viewController's ".view" property and your TPKeyboardAvoidingScrollView, you have to explicitly create a property called "view" of type TPKeyboardAvoidingScrollView, or else you don't have the method showsVerticalScrollIndicator on that property. TPKASV gets that method by virtue of subclassing UIScrollView.

danray0424 avatar Jan 02 '14 14:01 danray0424

I can't reproduce this problem myself, but if the solution @intrepidmatt describes addresses the problem, I'd like to find a better way to avoid including the scroll indicator views in the calculation. @intrepidmatt, have you tried identifying those by class name, or perhaps tag? (if you put an NSLog on the view within that loop, it might help to show their properties, to give us something to use to identify them)

michaeltyson avatar Jan 03 '14 01:01 michaeltyson

Results of the log:

view: <UIImageView: 0x99939c0; frame = (316 561; 3 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x9993590>> 
tag: 0

intrepidmatt avatar Jan 03 '14 20:01 intrepidmatt

I am having this issue as well. Is there a fix for it?

mbcoder17 avatar Jan 08 '14 01:01 mbcoder17

Hmm, that's not particularly helpful, is it? Is there a way to reproduce this problem reliably, ideally using the provided sample app?

michaeltyson avatar Jan 08 '14 01:01 michaeltyson

Sorry, allow me to explain what is causing the problem for me: Originally I had a UIView with all of my elements in it, then I found this amazing class that would fix my textfield problems, so in my storyboard I changed the class of my View to TPKeyboardAvoidingScrollView. The textfields move into position correctly, but when I dismiss the keyboard, the scroll view is offset and there is extra space on the top/bottom to scroll...

mbcoder17 avatar Jan 08 '14 01:01 mbcoder17

Oh, apologies @mbcoder17 - by 'not particularly helpful' I was responding to @intrepidmatt's finding that the UIScrollView's scroll indicators apparently can't be uniquely identified =) Your message was fine! Alas, until we can either figure out how to exclude those indicators, I don't know how we can address the issue, but if I can reproduce it here somehow, that'd be helpful.

Cheers for the extra info all the same though!

michaeltyson avatar Jan 08 '14 01:01 michaeltyson

In the sample app, change the deployment target to 7.0 and run in the iOS 7 3.5 inch simulator. Delete all the fields in FirstView.xib except for "Iggle" and "Splat". You'll see the scroll indicator UIImageViews if you break on line 208 of UIScrollView+TPKeyboardAvoidingAdditions.m.

Repro steps:

  1. Run in iOS 7 3.5 inch simulator
  2. Click on "Splat"
  3. Click on empty space to dismiss the keyboard.
  4. "Iggle" is now hidden

If you disable the horizontal and vertical scroll indicators on the scroll view in FirstView.xib and try the steps again, it works properly (iggle correctly scrolls back into view when the keyboard is dismissed).

intrepidmatt avatar Jan 08 '14 01:01 intrepidmatt

How can I implement the fix mentioned a few posts up? I don't have any scroll indicator settings in IB as I started with a UIView not a scroll view.....

On Jan 7, 2014, at 8:45 PM, Michael Tyson [email protected] wrote:

Oh, apologies @mbcoder17 - by 'not particularly helpful' I was responding to @intrepidmatt's finding that the UIScrollView's scroll indicators apparently can't be uniquely identified =) Your message was fine! Alas, until we can either figure out how to exclude those indicators, I don't know how we can address the issue, but if I can reproduce it here somehow, that'd be helpful.

Cheers for the extra info all the same though!

— Reply to this email directly or view it on GitHub.

mbcoder17 avatar Jan 08 '14 02:01 mbcoder17

I was able to do so in interface builder with your sample project and no modifications:

screen shot 2014-01-07 at 9 32 07 pm

intrepidmatt avatar Jan 08 '14 02:01 intrepidmatt

Ah lovely, thank you @intrepidmatt ! I'll take a look.

michaeltyson avatar Jan 08 '14 06:01 michaeltyson

I solved this by putting the .view @property into my .h (you already have one by virtue of subclassing UIViewController, but you can override it in the header file), and explicitly making it a TPKeyboardAvoidingScrollView. Then inside -viewDidLoad I could turn off the .showsHorizontalScrollIndicator and .showsVerticalScrollIndicator.

"Solved" is a strong word--the problem is gone in my implementation, but obviously a way for TPKA to notice scroll indicators and ignore them is the real solution.

danray0424 avatar Jan 08 '14 11:01 danray0424

@danray0424 that didn't fix it for me. All it did was hide the scroll bars, but there is still a taller content to scroll through...

mbcoder17 avatar Jan 08 '14 22:01 mbcoder17

:+1:

jonathandemoor avatar Jan 09 '14 08:01 jonathandemoor

Any fix yet?

mbcoder17 avatar Jan 18 '14 15:01 mbcoder17

If I understand this issue correct then I get this problem when I'm toggling between regular textfields and textfields with input view's such as a picker or a custom accessory view. Should it be any difference when I user pickers instead of textfields when I use TPKeyboardAvoiding?

osklar0328 avatar Jan 21 '14 19:01 osklar0328

I think I worked out this issue.

The problem, as @intrepidmatt stated, is that TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames is including the scroll indicators in the calculation. The scroll indicators are UIImageViews, added by the UIScrollView as subviews.

While there isn't a way to determine if the UIImageView you're looking at is a scroll indicator, they are removed when you turn off the scroll indicators.

So the fix is to simply remember if the scroll indicators are turned on before calculating the content size, then turning them off, performing the calculation, and restoring the indicators' visibilities. I'll send a push request to @michaeltyson in a moment, but here's the code in the meantime:

-(CGSize)TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames {

    BOOL wasShowingVerticalScrollIndicator = self.showsVerticalScrollIndicator;
    BOOL wasShowingHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;

    self.showsVerticalScrollIndicator = NO;
    self.showsHorizontalScrollIndicator = NO;

    CGRect rect = CGRectZero;
    for ( UIView *view in self.subviews ) {
        rect = CGRectUnion(rect, view.frame);
    }
    rect.size.height += kCalculatedContentPadding;

    self.showsVerticalScrollIndicator = wasShowingVerticalScrollIndicator;
    self.showsHorizontalScrollIndicator = wasShowingHorizontalScrollIndicator;

    return rect.size;
}

brianpseudo avatar Jan 29 '14 15:01 brianpseudo