On May 21, 2010, at 10:52 AM, Kyle Sluder wrote:
> On Fri, May 21, 2010 at 10:37 AM, Troy Stephens <tsteph...@apple.com> wrote:
>> CALayers don't support the same notion of "flippedness" that NSView's 
>> geometry model uses.  (CALayer's "geometryFlipped" property is recursive in 
>> its effect, so isn't semantically identical.)
> 
> Hmm. Perhaps instead of using geometryFlipped on our layer, we should
> manually calculate the bounds rectangle as appropriate? Or would
> setting the anchor point to (0,1) suffice? Basically, we want to lay
> out our contents like a text view would, which means that we want our
> first row of stuff (which is contained in a child layer) to appear at
> the upper left of the view, which should be at (0,0) in the layer's
> bounds coordinate space.

You can use geometryFlipped on your documentView's layer for this purpose, if 
and only if your documentView isn't going to have any subviews.  If you control 
all the content (build it out of your own layers) from there on down, you're 
OK.  If AppKit has to position subview backing layers within the documentView's 
layer, it won't take the geometryFlipped setting into account and the 
positioning won't turn out right.

You should never modify the anchorPoint of a view backing layer.  If you modify 
your code to override -makeBackingLayer, AppKit will set the returned layer's 
anchorPoint automatically the way it wants it (to (0,1) if the superview is 
flipped, or (0,0) if the superview is unflipped).

>> Therefore, whenever AppKit resizes the backing layer of a flipped NSView, we 
>> have to compute and assign new "position" values for its sublayers, to keep 
>> them in the same place relative to the top left.  (Don't count on this not 
>> changing in a future release, but for debugging purposes you can look for 
>> -_updateSublayerPositionsForFlippedSuperview, which gets invoked from 
>> -setFrameSize:)
>> 
>> We do this for sublayers that we created and therefore consider ourselves to 
>> "own", but in your test app you're instantiating and assigning a layer of 
>> your own to the documentView.  Therefore, when we resize the ClipView's 
>> backing layer (and the ClipView is flipped, because it always matches the 
>> flippedness of the ScrollView's documentView), we don't touch the position 
>> of your documentView's layer.  (If you modify your example to omit the 
>> custom layer creation and -setLayer:, and instead override -drawRect: to 
>> draw your content into the view's AppKit-provided backing layer, you'll see 
>> the problem goes away.)
> 
> Indeed it does. :) I had tested that, and was actually contemplating
> adding a button to toggle that behavior, but I wound up heading down
> the road of "rewrite NSScrollView using CAScrollLayer" instead.

There should be no need for that.  Just change your backing layer instantiation 
to user -makeBackingLayer.

>> Arguably it would actually be OK for us to modify the layer's position in 
>> this case (and clearly our "hands off" policy isn't quite consistent about 
>> this, since, as you noted, scrolling will "fix" the incorrect document layer 
>> position).
> 
> The inconsistency is what's so maddening. I thought I had just failed
> to do something on initialization.

We'll look at improving the consistency of this behavior.

>> Meanwhile, the simplest solution, if you require a custom backing layer, is 
>> to override NSView's -makeBackingLayer method (added in 10.6) to instantiate 
>> and return your (autoreleased) layer.  When layer instantiation goes through 
>> this path, AppKit considers the layer AppKit-owned, so you won't run into 
>> the positioning problem.
> 
> I can't believe we've overlooked this method. We do, however, need to
> resize the layer vertically as our document grows/shrinks, and we need
> it to always be at least as high as the visible area of the scroll
> view. Does this have the same potential for conflict with AppKit's
> layer resizing? (Or perhaps if we just resize the view to the
> appropriate size, this entire question just goes away. But that can't
> be right, it doesn't involve impossible contortions and overriding
> private methods! <grin>)

Once you're using -makeBackingLayer, just size the documentView the way you 
want it, and let AppKit automatically resize the layer to match.

For "document view should always be at least as big as the clip area" behavior, 
you'll want to monitor the ClipView for size changes, and resize the 
documentView as desired in response.

>> By the way: I don't know whether CAGradientLayer disregards -setNeedsDisplay 
>> (since the layer renders its content programmatically), possibly making this 
>> irrelevant in practice, but in cases like this, where you provide a layer of 
>> your own that already has content, and you don't want AppKit to ever invoke 
>> the view's -drawRect: to draw view content into the layer, it's a good idea 
>> to -setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawNever on the view.
> 
> The CAGradientLayer is a red herring that I was using to visually
> establish which end of the layer was "up."
> 
> You and David have been thoroughly amazing with your help. Thanks so much!

Sure.  Let us know if you run into further difficulty with this.

Troy

_______________________________________________

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

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

Reply via email to