Keyboard obscuring my table cell

110 views
Skip to first unread message

Todd Blanchard

unread,
Apr 12, 2010, 12:39:55 AM4/12/10
to thr...@googlegroups.com
I have a table acting as a form of type UITableViewStyleGrouped which is just about the size of the screen.

When filling in the lower fields, the keyboard opens up and obscures the field I'm editing.  How do I make the table scroll up and reveal the obscured field (and more interestingly, why doesn't this "just happen")?

Thanks for any tips,
-Todd Blanchard

Todd Blanchard

unread,
Apr 12, 2010, 1:46:22 AM4/12/10
to thr...@googlegroups.com
Nevermind - found autoresizesForKeyboard


--
You received this message because you are subscribed to the Google Groups "Three20" group.
To post to this group, send email to thr...@googlegroups.com.
To unsubscribe from this group, send email to three20+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/three20?hl=en.

David van Dugteren

unread,
Apr 12, 2010, 1:58:03 AM4/12/10
to thr...@googlegroups.com

static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;

On select throw this code in where relevant.

CGRect viewFrame = self.view.frame;
viewFrame.origin.y += PORTRAIT_KEYBOARD_HEIGHT;

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

[self.view setFrame:viewFrame];
[theTextField resignFirstResponder];

Hope that helps

David van Dugteren

Todd Blanchard wrote:
> Nevermind - found autoresizesForKeyboard
>
>
> On Apr 11, 2010, at 9:39 PM, Todd Blanchard wrote:
>
>> I have a table acting as a form of type UITableViewStyleGrouped which
>> is just about the size of the screen.
>>
>> When filling in the lower fields, the keyboard opens up and obscures
>> the field I'm editing. How do I make the table scroll up and reveal
>> the obscured field (and more interestingly, why doesn't this "just
>> happen")?
>>
>> Thanks for any tips,
>> -Todd Blanchard
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Three20" group.
>> To post to this group, send email to thr...@googlegroups.com

>> <mailto:thr...@googlegroups.com>.


>> To unsubscribe from this group, send email to
>> three20+u...@googlegroups.com

>> <mailto:three20+u...@googlegroups.com>.

jdandrea

unread,
Apr 26, 2010, 5:59:03 PM4/26/10
to Three20

On Apr 12, 12:39 am, Todd Blanchard <tblanch...@mac.com> wrote:

> I have a table acting as a form of type UITableViewStyleGrouped ... How do I make the table scroll up and reveal the obscured field …

On Apr 12, 1:46 am, Todd Blanchard <tblanch...@mac.com> wrote:

> Nevermind - found autoresizesForKeyboard

Same here. Also found autoresizesForKeyboard. Beautiful.

However, I ran into problems using it, and it seems I'm not the only
one. :-o

June 2009 thread:
http://groups.google.com/group/three20/browse_thread/thread/f85d2485a37e364c/

October 2009 thread:
http://groups.google.com/group/three20/browse_thread/thread/b4bbfe1b838ec1fb/

Some more context. Maybe this will help provide clues to sleuth things
out.

I've also got UITableViewStyleGrouped in the mix, using a white
background, as well as an overarching Tab Bar. This table view is
arrived at from a root view associated with one of those tabs.

The grouped table view has three sections of three TTTableControlItem
items, each with a UITextField inside.

With that, I have a few gotchas I'm trying my level best to hunt down
here:

1. If I pick one of the text fields in the _first_ section, the table
view appears to shrink nicely to accommodate the keyboard. However,
immediately after that happens, another view (?) with a telltale gray
striped table view background appears just above the keyboard, and the
table view height decreases even further. (The momentary scroll
indicator shows the height is indeed less.)

I'm not sure if that gray area (ha!) is the height of the tab bar or
the navigation bar, but I'm not yet sure where it's coming from, or
why it's happening. There's not much to the code right now. Making a
point to keep it very very simple at this stage.

2. If I pick a different text field in the first section, that gray
striped area disappears momentarily, then the field I picked neatly
scrolls into better view, but then the shrink/resize/gray-striped
scenario from #1 plays out again. <!>

3. If I scroll all the way down to the third section and pick a text
field there, a similar scenario to #1 happens, except the table view's
scroll position first jumps abruptly, as if there was no keyboard and
I had scrolled to the bottom of the view. THEN it scrolls into proper
view. So there's this jumping effect going on.

4. Finally, if I scroll to the middle/second section and pick a text
field there, we SOMETIMES a completely different scenario. (That's
right, I can only reproduce this if I pick a certain order of text
fields.) First, the keyboard is dismissed - even though I'm not at the
point of resigning first responder yet - and then a part of the table
view up top suddenly appears blanked out and not drawn. Nudging the
view's scroll position slightly redraws things.

I thought I was seeing things (well, of course I'm seeing SOMETHING!)
but then I noticed TTCatalog has similar behavior in the Table
Controls example. In fact, if you go add more fields/sections to it,
you can pretty much replicate what I'm describing above. You don't
actually need multiple sections to see some/all of this behavior, but
I'm just describing my own experience.

Whew - thanks for reading all that. Clues welcome/appreciated! I'm
currently trying to figure out what might be happening under the hood
in the keyboard resizing logic.

I'm starting to wonder if what I'm seeing is a collision between what
iPhone OS 3.0+ now provides with built-in keyboard/resizing support
(as it relates to text fields), and what might have been an absence of
it in iPhone OS 2.x. Maybe it's a simple matter of invoking this logic
only if we're running under iPhone OS 2.x? (n.b.: I only started using
iPhone OS starting with 3.0, so feel free to disabuse me of that
notion if I'm misrepresenting something here.)

Joe D'Andrea

unread,
Apr 26, 2010, 10:19:59 PM4/26/10
to Three20


On Apr 26, 5:59 pm, jdandrea <jdand...@gmail.com> wrote:

> I'm starting to wonder if what I'm seeing is a collision between what
> iPhone OS 3.0+ now provides with built-in keyboard/resizing support
> (as it relates to text fields), and what might have been an absence of
> it in iPhone OS 2.x.

Scratch that thought. UITableViewController doesn't get subclassed
anywhere within Three20. So any of the automagic resizing/scrolling
we'd get from the the iPhone OS 3.0 SDK doesn't apply here. I'd feel
comfy with that if I knew I could get the Three20 scrolling/resizing
behavior working sanely, but now I'm concerned about using
TTTableControlItem at all. I may just resort to either a) static text,
and have the cell tap lead to a multi-purpose editing view … or b) use
a regular UITableViewController … only then I think we lose a bit of
that handy view persistence. Arrrrgh. :\

Q: Has anyone else run into this issue? If so, what did you end up
with as a plan of action to mitigate things? (Inquiring minds want to
know!)

- Joe

Joe D'Andrea

unread,
Apr 27, 2010, 12:15:31 AM4/27/10
to Three20
Who-hoo! Matt Gallagher to the rescue:

http://cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html

So long as you assign each UITextField's delegate (in my case I am
using UITextField) to match textFieldDidBeginEditing: and
textFieldDidEndEditing: this works beautifully … WITH ONE POSSIBLE
GOTCHA, but now we should be on the fast track to solving it. Looks
like, when we're close to the bottom of the view and we pick a text
field, it scrolls up too much, taking the tab bar into account. So we
need to know if the tab bar is involved, and compensate, and then I
think this finally works!

Possible next step: Consider working Matt's technique into Three20.
Thoughts?

- Joe

Joe D'Andrea

unread,
Apr 27, 2010, 12:37:30 PM4/27/10
to Three20


On Apr 27, 12:15 am, "Joe D'Andrea" <jdand...@gmail.com> wrote:

> So we need to know if the tab bar is involved, and compensate, and then I
> think this finally works!

Best laid plans … Matt's technique doesn't resize the table view (or,
rather, its surrounding view).

Trying to wrangle this now, but it's spiraling out of hand, to the
point where I'm now looking to see when the keyboard is shown/hidden.

This excerpt from the "iPhone Application Programming Guide" is
interesting:

"For example, if the owner of the keyboard changes, the system sends a
UIKeyboardWillHideNotification message, but not a
UIKeyboardDidHideNotification message, to the current owner because
the change never causes the keyboard to be hidden. The delivery of the
UIKeyboardWillHideNotification is simply a way to alert the current
owner that it is about to lose the keyboard focus."

Is it me, or shouldn't "will hide" mean the keyboard really WILL hide
(vs. "might hide")? Losing keyboard focus would be a separate item,
no? :-o

Joe D'Andrea

unread,
Apr 27, 2010, 3:23:27 PM4/27/10
to Three20


On Apr 27, 12:37 pm, "Joe D'Andrea" <jdand...@gmail.com> wrote:

> Best laid plans … Matt's technique doesn't resize the table view (or,
> rather, its surrounding view).
>
> Trying to wrangle this now, but it's spiraling out of hand, to the
> point where I'm now looking to see when the keyboard is shown/hidden.

OK, it's gotcha compounding upon gotcha. Between seeing so many
threads online where folks are having differing POVs on how to solve
this, not all of them 100% spot-on (and even iPhone's
UITableViewController scroll/resize-on-keyboard implementation is a
bit herky-jerky in practice), I'm going to back off using
TTTableControlItem, or any of the text editors/views at all <sigh> and
create a set of edit mode views where the keyboard is always present.

I really hate to do this, but I'm very nervous proceeding with things
as-is. If anyone comes up with a reliable way to handle keyboard show/
hide across multiple text fields in a resizable table view, with or
without a toolbar/tab bar (takes breath), I'm all ears!

I know - that was a mouthful, wasn't it. :)

Skotch

unread,
Apr 27, 2010, 10:17:56 PM4/27/10
to Three20
Hey guys, I only skimmed this thread since it is quite long, so I
don't know if what I have to say is helpful or not.

I had a problem before with a TTTableViewController where Three20's
keyboard resizing code did not work right. The problem is that Three20
assumes that the table goes all of the way to the bottom of the
screen, which is often not the case, for example when you have a tab
bar. The keyboard does always start are the bottom of the screen, but
the tableview may not. So I wrote some new code in my inherited class
to do the calculation correctly, and now it seems to do the right
thing in all cases.

I have not tried to resubmit this back into the project because

1) I am still learning GIT and this branching thing seems like it is
taking me hours to get right. Plus submission might require example
code of the bug and a demo app, and I don't have the time for it right
now.

2) I have already submitted a NIB fork, and spent more than 1 day on
that, but it has not paid off yet and until I see the NIB's in the
head I don't feel comfortable spending more time on submitting forks.
This is not a jab or anything, I really just don't want to do work
unless I know that it is going to be of value to other people.
Hopefully NIB's will appear in the head soon and then I will start
submitting some more bug fixes, such as this one.

Anyway, in case this code is useful, I am providing it here. Hopefully
this will work for you as well and solve your problem. If it does,
maybe someone can submit the changes to three20.

The solution requires you to track the delta of the bottom of the
table and the bottom of the screen. I am storing that difference in a
member field called mDeltaBottom of my inherited class.

@interface SubClass : TTTableViewController
{
float mDeltaBottom;
}

Also, as already noted in this thread, you have to set

self.autoresizesForKeyboard = YES;


Otherwise, I override the following methods in my inherited class as
so:


#pragma mark keyboard resizing

static int keyboardAdjustCount = 0;

/*
If we were to shrink the table view by the whole size of the
keyboard,
that would be too much, since the keyboard extends down below the
bottom
of the table. So we adjust the bounds of the keyboard so that its
height only
covers the amount of they keyboard that covers the table.
*/
-(CGRect)adjustKeyboardBounds:(CGRect)bounds
{
//DMV: TODO: it would be good to contribute this back to three20

//the three20 code assumes that the table goes all the way to the
bottom
//of the screen when resizing it for the keyboard. This change allows
us
//to only resize the part of the screen that overlaps the keyboard.

if (bounds.size.height > mDeltaBottom)
bounds.size.height -= mDeltaBottom;
else
bounds.size.height = 0;
return bounds;
}

/**
* Sent to the controller before the keyboard slides in.
*/
- (void)keyboardWillAppear:(BOOL)animated withBounds:(CGRect)bounds
{
mDeltaBottom = TTScreenBounds().size.height - self.view.height -
self.view.ttScreenY;
[super keyboardWillAppear:animated withBounds:bounds];
}

/**
* Sent to the controller before the keyboard slides out.
*/
- (void)keyboardWillDisappear:(BOOL)animated withBounds:(CGRect)bounds
{
keyboardAdjustCount--;
if (keyboardAdjustCount != 0)
{
TTDASSERT(NO);
return; //for some reason, we are being called too much
}
bounds = [self adjustKeyboardBounds:bounds];
[super keyboardWillDisappear:animated withBounds:bounds];
}

/**
* Sent to the controller after the keyboard has slid in.
*/
- (void)keyboardDidAppear:(BOOL)animated withBounds:(CGRect)bounds
{
if (keyboardAdjustCount != 0)
{
TTDASSERT(NO);
return; //for some reason, we are being called too much
}
keyboardAdjustCount++;
bounds = [self adjustKeyboardBounds:bounds];
[super keyboardDidAppear:animated withBounds:bounds];

//scroll to the new folder row
[self.tableView scrollToRowAtIndexPath:[self newShelfIndexPath]
atScrollPosition:UITableViewScrollPositionMiddle
animated:YES];

}

/**
* Sent to the controller after the keyboard has slid out.
*/
- (void)keyboardDidDisappear:(BOOL)animated withBounds:(CGRect)bounds
{
[super keyboardDidDisappear:animated withBounds:bounds];
}


I hope that I didn't leave any thing out. Let me know if this works
for you.

Joe D'Andrea

unread,
Apr 28, 2010, 8:48:03 AM4/28/10
to Three20


On Apr 27, 10:17 pm, Skotch <skotchv...@gmail.com> wrote:

> Three20 assumes that the table goes all of the way to the bottom of the
> screen, which is often not the case, for example when you have a tab
> bar.

Exactly! As you've rightly pointed out, a delta will do wonders. Thank
you for sharing this! Alas, it looks like we have to subclass vs. use
a category (for mDeltaBottom) … unless perhaps we could leverage a
protocol? … or calculate mDeltaBottom in adjustKeyboardBounds:? I
suspect you have a good reason for putting it in
keyboardWillAppear:withBounds: though. (Frames are changing, etc.)

I tried applying a similar delta in Matt Gallagher's sample code[1]
(separate from Three20, granted), but his example has another gotcha
in that it doesn't resize the view being obscured by the keyboard.

That's what led me down the path of UIKeyboardWillHideNotification and
its bretheren. Upon reading Apple's docs though, I almost feel as if
it should be called UIKeyboardMightHideNotification or MayHide.

I'll be sure to try this out. I'm most interested in seeing if that
bounce-around effect goes away. I'm hopeful that, with a delta in
play, it does.

- Joe

[1] http://cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html

Joe D'Andrea

unread,
Apr 28, 2010, 12:41:13 PM4/28/10
to Three20
Skotch,

I'm trying this out with the TTCatalog app, just to see how it would
fly. There's one bit that doesn't exist though: newShelfIndexPath ...

On Apr 27, 10:17 pm, Skotch <skotchv...@gmail.com> wrote:

>         //scroll to the new folder row
>         [self.tableView scrollToRowAtIndexPath:[self newShelfIndexPath]
>                                                   atScrollPosition:UITableViewScrollPositionMiddle
>                                                                   animated:YES];

At what point are you first setting that? (I suspect it's in another
protocol method, but here it's more streamlined vs. knowing someone
tapped a text view control vs. a cell overall.) Then I could likely do
something similar in TTCatalog.

- Joe

Skotch

unread,
Apr 28, 2010, 10:17:27 PM4/28/10
to Three20
I responded to you but it never showed up, so I am going to try again
(in a more pithy version).

> There's one bit that doesn't exist though: newShelfIndexPath ...

My mistake in cutting and pasting code - I should not have included
newShelfIndexPath. Please replace that with the row that you want to
move on screen, or comment the line out entirely if the row in
question is on screen already.

There are two problems here:

1) Resizing the table
2) Scrolling the row on screen once the table has its new size.

The line in question is about item 2, the rest of the code handles
item 1. In some cases, the row will end up off screen after the
resize, so you might need to scroll it on screen.

Extra Information:
In my application, the user presses a button to scroll a certain row
with a textfield on screen. Since it is usually off screen, the edit
control probably doesn't even exist yet. So I call this method to
create the row and bring up the keyboard:

/*
Select the edit field, so that the keyboard will come up.
Note that TableTextFieldCell is my own custom class, and
newShelfIndexPath is my own custom method, but as an example this
should be clear enough.
*/
-(void)selectKeyboard
{
TableTextFieldCell * c = (TableTextFieldCell *)[self.tableView
cellForRowAtIndexPath:[self newShelfIndexPath]];
TTDASSERT(c);
[c.textField becomeFirstResponder];
}

After the keyboard comes up, I finish scrolling the row onto the
screen in the code that you mention above. I think all of that is
probably beyond the scope of the problem that you were seeing, but I
am not sure.

Skotch

unread,
Apr 28, 2010, 10:25:29 PM4/28/10
to Three20
> Thank you for sharing this! Alas, it looks like we have to subclass vs. use
> a category (for mDeltaBottom) … unless perhaps we could leverage a
> protocol? … or calculate mDeltaBottom in adjustKeyboardBounds:?

I think that any solution is going to require a new variable, which
really should be an iVar. So any solution is going to require either
subclassing or (preferred) modifying the three20 source code to fix
the problem at its source.

For now, it would be good to get a confirmation that this code helps
outside of just my own application. Later someone can submit a three20
patch to be integrated into the main trunk.

> That's what led me down the path of UIKeyboardWillHideNotification and
> its bretheren. Upon reading Apple's docs though, I almost feel as if
> it should be called UIKeyboardMightHideNotification or MayHide.

Three20 is already using UIKeyboardWillHideNotification, which is how
it ends up calling keyboardWillDisappear:withBounds:

Also notice in my code that I was sometimes getting double events
(tracked by keyboardAdjustCount). I never got a missed event like you
mention, although it may happen. I suspect three20 handles it
correctly.

I don't know if my double check for events is necessary anymore, but
it should be benign so I would recommend leaving it in for now.

Joe D'Andrea

unread,
Apr 28, 2010, 10:32:09 PM4/28/10
to Three20
Whoops - the thread detoured in to private email. No problem - back we
go. Re-posting my last email to get back into the slipstream ...

OK! I tried it out. What I ended up doing was adding another private
variable:

UIView *_activeView;

Then we set/clear it like so:

- (void)textViewDidBeginEditing:(UITextView *)textView {
_activeView = textView;
}

- (void)textViewDidEndEditing:(UITextView *)textView {
_activeView = nil;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
_activeView = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
_activeView = nil;
}

[n.b.: This doesn't cover all possibilities.]

Then, in keyboardDidAppear:withBounds: we scroll like so:

UITableViewCell *cell = (UITableViewCell *)[[_activeView superview]
superview];
[self.tableView scrollToRowAtIndexPath:[self.tableView
indexPathForCell:cell]
atScrollPosition:UITableViewScrollPositionMiddle animated:YES];

Now, I suspect this is not the best way to go about figuring out which
indexPath to scroll to (this looks like a job for a delegate method!),
but I'm just trying to tire kick the basic idea for now.

Alas, so far, I've seen your keyboardAdjustCount counter reach -5.
Drat. :\

I think this goes back to what I was seeing in the Apple docs. Have a
look at "Managing the Keyboard" here:

http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TextandWeb/TextandWeb.html

"For example, if the owner of the keyboard changes, the system sends a
UIKeyboardWillHideNotification message, but not a
UIKeyboardDidHideNotification message, to the current owner because
the change never causes the keyboard to be hidden. The delivery of the
UIKeyboardWillHideNotification is simply a way to alert the current
owner that it is about to lose the keyboard focus."

Of course we have no control over this, but I swear [it seems]
tantamount to saying "This notification is really not what it appears
to be. We're really saying to the current owner - you're losing
keyboard focus."

Well, OK, but _that_ sounds like a
UIKeyboardWillLoseFocusNotification. As it stands now, it's not
"WillHide" at all. It's "MightHide".

- Joe

Joe D'Andrea

unread,
Apr 28, 2010, 10:35:52 PM4/28/10
to Three20


On Apr 28, 10:32 pm, "Joe D'Andrea" <jdand...@gmail.com> wrote:

> Well, OK, but _that_ sounds like a
> UIKeyboardWillLoseFocusNotification.

… or perhaps UIKeyboardOwnerWillLoseFocusNotification!

I realize this is all academic, but I think it helps me to better
understand the situation and _why_ keyboardAdjustCount can reach
negative values.

Skotch

unread,
Apr 28, 2010, 10:42:06 PM4/28/10
to Three20
It looks like three20 has a method called
scrollFirstResponderIntoView, I wonder if that will avoid the need to
track the row. Let me know what happens if you give it a try. I no
nothing about it other than the name.

If that fails, then I was trying to think if there was some way to
work back from the first responder to the the row index, and I suspect
that there is, and that might be a more elegant solution.

Three20 has a method (findFirstResponder) to find the first responder.
From there you could traverse its parents until you got a
UITableViewCell, and then scroll to that.

But frankly I am not going to have time in the immediate future to try
that one out.
> http://developer.apple.com/iphone/library/documentation/iPhone/Concep...

Skotch

unread,
Apr 28, 2010, 10:48:53 PM4/28/10
to Three20
I am a liar, I did take the time. I tried replacing that line in my
own code with this one:

[self.tableView scrollFirstResponderIntoView];

and it works fine. I think that is much simpler solution than tracking
the current edit view. Give it a try and see if it works for you.

Joe D'Andrea

unread,
Apr 28, 2010, 10:50:29 PM4/28/10
to Three20


On Apr 28, 10:42 pm, Skotch <skotchv...@gmail.com> wrote:
> It looks like three20 has a method called
> scrollFirstResponderIntoView …

I think I can keep reading the source over and over again, yet I will
_still_ keep noticing things I missed the previous go-rounds.

That's brilliant. I looked at the method and it does exactly what you
think it does. Good! I get to toss all that other code.

So, in short, it works, but:

* keyboardAdjustCount still goes negative
* The scroll doesn't go from the last position. It jumps to the top,
then scrolls down.

Still, it's a start! (I wonder if preventing the call in to super in
some cases is causing unexpected grief here?)

d.heark

unread,
Sep 22, 2010, 5:47:17 PM9/22/10
to thr...@googlegroups.com
Hi all,

any news about this problem? There is a release of three20 that address this problem?

Regards, David

Skotch

unread,
Oct 3, 2010, 7:21:41 PM10/3/10
to Three20
As far as I know this has never been added to a three20 release, but
its a big deal so I think it should.

I also figured out why keyboardAdjustCount can go negative. Basically,
if you set autoresizesForKeyboard = YES, then you need to set it = NO
before you exit your window, or the notifications will just build up.
This is a bug in TTBaseViewController because they only release the
UIKeyboardWillShowNotification's if it gets set back to NO. It might
be better to modify this base class to reset it automatically, but I
am not sure what the best place to do that is.
Reply all
Reply to author
Forward
0 new messages