So, attempting to modify both the frame and the contentOffset in the same 
animation is a problem. This has to do with how UIView animations work coupled 
with how UIScrollView works. I'm going to give a lengthy explanation of why 
this doesn't work, but you can skip to the bottom for what should be the 
solution.

First a quick note on how UIView animations work (to make sure we're on the 
same page):

1. When an animatable property is modified within an animation block, UIKit 
sets up an animation on the given view's underlying CALayer object. That 
animation has a fromValue and a toValue which define what we're animating from 
and to. When you set a property, the value you set gets taken as the 
animation's toValue, and whatever was already there gets set as the fromValue. 
Thus, if you have a view whose alpha is 0.0, and you set its alpha to 1.0 in an 
animation block, UIKit sets an alpha animation on the CALayer whose fromValue 
is 0.0 and whose toValue is 1.0. An interesting caveat here is that if you set 
the same property twice in the same turn of the runloop, the animation results 
might not be as you expect, because the fromValue used by UIKit is always the 
model value just before you make the change. Thus if we start with a view whose 
alpha is 0.0 and run this code

[UIView animateWithDuration:0.3 animations:^(void) {
view.alpha = 1.0;
....
view.alpha = 0.9;
}];

The result will be that the view jumps immediately to alpha 1.0, and then 
animates to 0.9, even though the 1.0 was in the animation block. The second 
animation clobbers the first one and uses the model value set by the first 
animation as its fromValue.

Moving on....

2. Frame changes are interesting because a frame is not directly a property of 
a view - it is a derived property of its center, bounds, and transform. When 
you modify a view's frame, you are actually modifying its center and bounds, 
which are each distinctly animatable properties, and UIKit sets up animations 
on the underlying CALayer for each of them.

And we also need to make sure we're on the same page about how scrolling works 
in UIScrollView:

3. The portion of any view that is drawn on screen is defined by its bounds - 
the coordinate space of that view. Normally, a view has a bounds.origin of 0,0 
and a bounds.size equal to its frame.size. A UIScrollView brings new content 
onto the screen, getting the effect of scrolling, but modifying its 
bounds.origin. In fact, contentOffset is really just bounds.origin.

Ok, so bringing this all together....

When you change a table view's contentOffset and its frame.size in the same 
animation, you've actually clobbered one of your animations, because both of 
those properties ultimately result in a bounds animation on the underlying 
layer. One is modifying the bounds origin, and the other bounds size, but 
they're both just bounds animations, and just as we saw in the alpha case 
above, the second one will stomp on the first one and use the first one as its 
fromValue. Thus you will see things "jump" to the first bounds value you set 
and then animate to the second.

And now what should be a solution to the long-winded explanation of the problem:

Instead of changing the frame of a table view to accommodate the keyboard 
coming up, we recommend changing the contentInset. By adding the height of the 
keyboard to the table's contentInset.bottom, you get additional scrolling area 
so things don't get stuck behind the keyboard, but you won't be creating a 
bounds animation in the process. In fact, UITableViewController does this 
automatically for table views that it manages.

Hope that helps.

Luke

On Apr 16, 2012, at 6:27 PM, Rick Mann wrote:

Er, for reference, the view hierarchy is this:

http://latencyzero.com/stuff/ViewHierarchy.png


On Apr 16, 2012, at 18:16 , Rick Mann wrote:


On Apr 16, 2012, at 16:32 , Luke Hiesterman wrote:

You can do this by wrapping the operation in your own animation block. This 
simple code demonstrates doing it on 44 point high rows:

  [UIView animateWithDuration:0.3 animations:^(void) {
      [tableView beginUpdates];
      CGPoint contentOffset = tableView.contentOffset;
      if (contentOffset.y > 0) {
          contentOffset.y += 44;
          tableView.contentOffset = contentOffset;
      }
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath 
indexPathForRow:__numRows inSection:0]] 
withRowAnimation:UITableViewRowAnimationAutomatic];
      __numRows++;
      [tableView endUpdates];
  }];

Yeah, this is essentially what I do, but while I can correctly animate the 
frame change alone, if I try to do that AND change contentOffset, it doesn't 
work.

Please see the following videos. For reference, the view hierarchy is this:

http://latencyzero.com/stuff/AdjustingOffset.mov

The parent View is a blue color. The Container view is green. The UITableView 
is pink.

If I do not adjust the content offset (that is, if it gets set to 0.0), you can 
see the views move and resize correctly:

http://latencyzero.com/stuff/AdjustingOffset.mov

If I DO adjust the content offset (even if I hard-code it to 10 pixels), 
everything ends up in the right place, but the table view immediately resizes 
to the proper height, but the frame.origin.y is adjusted about 81 pixels down 
in the view. It snaps to this position, THEN animates to the correct position.

http://latencyzero.com/stuff/NoOffsetAdjustment.mov

The code that does this (for the keyboard appearing) is here:

http://pastebin.com/zRSR78fZ


2) When animating a frame change, are subframe re-sizes also animated? It looks 
like they're partly immediately update, then animating.

Any subviews which are resized in the scope of the superview's frame change 
will share the animation, which includes anything that has autoresizing masks. 
You may need to invoke -layoutIfNeeded within your animation block on views who 
defer resizing of their subviews until layout time to capture some things in an 
animation. But that discussion is orthogonal to your stated goal, which can be 
achieved by following the sample I've provided above.

I tried throwing in a -layoutIfNeeded, but it had no effect.

--
Rick




_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/rmann%40latencyzero.com

This email sent to rm...@latencyzero.com


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to