Question

So, I seem to ask hard questions but here I go again.

I have what seems like a weird problem. In some of my views, I hide toolbars at the top by rotating them back on the x-axis by 90 degrees. I then allow them to be 'pulled down' by the user which will rotate the view to 0 degrees, thus displaying the toolbar. It all works great except on one view where I have two toolbars to pull down. This works by rotating the first toolbar down and then the second, with the first toolbar displaced down by the height of the second toolbar. All this works fine on the non-retina displays. However, on a retina display the displacement of the first toolbar is only half what it should be. Furthermore, the frame of the view is exactly what it should be. In other words, when I check (NSLog) I get a frame of {0, 30, 320, 30} but the actual image is showing at frame: {0, 15, 320, 30} . It's only the background that's shifted. If I click on the space the view should be, the touch events go through.

This is what's happening on retina screens:

enter image description here

This is what happens on non-Retina screens (exact same code):

enter image description here

This is the code I use to rotate the view (very simple):

- (void) rotateView:(UIView *)view downBy:(CGFloat)rad{
    CALayer *rLayer = view.layer;
    CGFloat zDist = self.view.window.bounds.size.height * 1.5f;
    CATransform3D rT = CATransform3DIdentity;
    rT.m34 = 1.0f /  -zDist;
    rT = CATransform3DRotate(rT, rad, 1.0f, 0.0f, 0.0f);
    rLayer.transform = rT;
}

Again, this only occurs on retina displays.

Now, the toolbar is being rendered in Core Graphics. So I eliminated my CG code as the source of the problem by removing it completely from drawRect so that there's no code in draw rect at all; the problem still occurs. I also noted that if I don't use drawRect (comment out the the entire method) the rotation occurs correctly but all of the subviews (which also use core graphics) are rendered at 1/2 the resolution so that everything looks blurry:

enter image description here

I think it has something to do with the transform but I'm not sure how or why. If I set the layer transform to identity after the rotation is set back to 0 radians(so it's fully in view) the view will snap to its correct position. I also noted that at 0 radians the transform is not quite at identity: m34 (perspective) is still set. Setting it back to zero does fix the problem. But setting it to zero during doesn't fix the problem while the view is in any other rotation other than 0 rad. And views that are not rotating down from origin {0,0} are still shifted. It seems like the problem occurs during ANY 3d transform, although I have check all the transforms to confirm that.

UPDATE

Due to the answer by @Joshua Weinberg I started messing around with the rasterizationScale of the layer. What I discovered was the offset of the underlying image was off by 1/rasterizationScale. So if I set the rasterizationScale to 6 and move my view down by 30, the background image only moves down by 30/6 (5.0f).

UPDATE 2

I tried a hack whereby I translated the image down. It works in that the image moves down the appropriate amount but it also makes the image disappear. So this code in my rotation method:

rT = CATransform3DTranslate(rT, view.frame.origin.x - (view.frame.origin.x / rLayer.rasterizationScale), view.frame.origin.y - (view.frame.origin.y / rLayer.rasterizationScale), 0);

Yields this: enter image description here

Was it helpful?

Solution

I figured it out. The view controller I've been struggling with was in a Custom Container Controller I had built as a custom split view controller. That controller also utilized 3D transforms when switching between view panes. At the end of a transition I left the .m34 (perspective transform) alone. Apparently this was causing all the problems I've been having. I made sure to set the transform of the layer to identity when switching views in the container controller and now it all works fine.

So I guess the moral of the story is, always make sure your super layers are at identity transform before you transform any sub layers or you may just have unexpected results.

OTHER TIPS

Set the rasterizationScale of the layer to [[UIScreen mainScreen] scale] and it should work. When you apply a 3d transform the layer gets rasterized, and the default rasterization is 1.0f;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top