CALayer zPosition排序具有极大的值

sud*_*-rf 10 macos core-animation ios

我遇到了一个问题,Core Animation zPosition在价值变大时似乎忽略了我的价值观.

这可以很容易地复制.

CGFloat largeZPosition = 1000000000;

CALayer *topLayer = ...
CALayer *bottomLayer = ...
bottomLayer.frame = CGRectOffset(topLayer.frame, 50, 50);

topLayer.zPosition = largeZPosition + 1;
bottomLayer.zPosition = largeZPosition;

// Intentionally sort the sublayers array in the wrong order.
rootLayer.sublayers = @[ topLayer, bottomLayer ];
Run Code Online (Sandbox Code Playgroud)

对于z位置的小值,这可以按预期运行.即使子层数组未正确排序,顶层也会显示在底层之上,如下所示:

正确

但是,通过上面显示的示例,结果如下:

在此输入图像描述

显然这是不正确的.

问题

根据我的需要,我无法对子层数组进行手动排序,因此我依赖于zPosition按预期执行.所以我的问题是:我该如何解决这个问题?谢谢.

小智 13

这是因为QuartzCore似乎转换zPositionfloat,所以当它失去精度CGFloatdouble.IEEE单精度浮点数使用24位表示有效位和精度,因此可能无法精确表示大于2 ^ 24的整数.例如,

float largeZPosition = 1000000000;
float largeZPositionPlus1 = 1000000001;
NSLog(@"%f %f %d", largeZPosition, largeZPositionPlus1, largeZPosition == largeZPositionPlus1);
Run Code Online (Sandbox Code Playgroud)

输出

1000000000.000000 1000000000.000000 1
Run Code Online (Sandbox Code Playgroud)

下一个可精确表示的整数是1000000064.

注意,它CALayer.zPosition被定义为CGFloat并且能够保持大于2 ^ 24的积分值,只要底层CGFloat能够做到这一点.检查

layer.zPosition = 1000000001;
NSLog(@"%f", layer.zPosition);
Run Code Online (Sandbox Code Playgroud)

在64位OS X,其中CGFloatdouble,输出

1000000001.000000
Run Code Online (Sandbox Code Playgroud)

所以,在CALayer公共Objective-C类级别,精度并没有丢失.QuartzCore还有其他地方可以转换为单精度float.

我建议使用小于2 ^ 24的整数(包括加法结果).鉴于它zPosition具有浮点类型,您可以使用较小的小数值而不是大的整数值.