Thanks for the lengthy explanation, Luke. I was aware of most of this. It seems like the result I'm seeing is a consequence of a number of things. Since the end result is correct, it seems like it should be possible to do things the way I was attempting to do them, but that subtleties in the implementation prevent it from behaving correctly.
I tried adjusting the content inset bottom instead, as you suggested, but unfortunately this required me to also move the text entry UI separately. Then I tried just moving the entire container (table view plus message composition area) up, and adjusting the contentInset.top appropriately. This works correctly. While it's a pity I can't just do the natural resize-frame-and-adjust-offset, I appreciate you giving me a workaround that gives me the results I need. -- Rick On Apr 17, 2012, at 10:48 , Luke Hiesterman wrote: > 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