Can I animate the UIScrollView contentOffset property via its layer?

You have to animate the bounds property. In fact, that's what the contentOffset property uses behind the scenes.

Example:

CGRect bounds = scrollView.bounds;

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
animation.duration = 1.0;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

animation.fromValue = [NSValue valueWithCGRect:bounds];

bounds.origin.x += 200;

animation.toValue = [NSValue valueWithCGRect:bounds];

[scrollView.layer addAnimation:animation forKey:@"bounds"];

scrollView.bounds = bounds;

If you're curious, the way I used to get this information is the following:

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];

[scrollView setContentOffset:CGPointMake(200, 0) animated:NO];

[UIView commitAnimations];

NSLog(@"%@",scrollView);

The NSLog call will output:

<UIScrollView: 0x860ba20; frame = (-65.5 0; 451 367); clipsToBounds = YES; autoresize = W+RM+TM+H; animations = { bounds=<CABasicAnimation: 0xec1e7c0>; }; layer = <CALayer: 0x860bbc0>; contentOffset: {246, 0}>

The animations snippet will list all the active animations, in this case { bounds=<CABasicAnimation: 0xec1e7c0>; }.

Hope this helps.