【问题标题】:How to apply a view transformation that works for a UIView to a NSView?如何将适用于 UIView 的视图转换应用于 NSView?
【发布时间】:2013-04-14 20:09:17
【问题描述】:

我有一个视图转换,可以让任何 UIView 对象跟随 cocos2d 节点。在 iOS 上运行良好,在此示例中 UIButton 遵循其 Box2D 主体:

现在对于 Mac,我首先验证了我是否正确设置了覆盖 NSWindow,以便在 cocos2d OpenGL 视图之上绘制 NSView 对象。这很有效,就像在这种情况下使用 NSButton:

但后来我了解到 NSViews 没有 [NSView setTransform:..] 方法。我不确定这是否是它在 Mac 上的工作方式,但这是我所做的:

// sometime after initializing the view
[nsView setWantsLayer:YES];

// every time I update transform:
nsView.layer.affineTransform = transform;

我验证了该层是非零的。我还重新验证了在启用 setWantsLayer 后绘制了 NSView。结果令人失望,按钮在整个窗口中无处可见,甚至似乎没有轻微偏移或镜像,它不再存在了:

这让我想到了转换代码。正如我所说,这与 iOS 的代码相同(除了在最后分配转换)。它在 iOS 上完美运行(也可以在任何方向上),但在带有 NSView 对象的 Mac OS X 上却不行,我根本看不到 NSView 对象。

我不确定这里可能出了什么问题,也许 CALayer 的工作方式不同,也许我只是犯了一个非常愚蠢和明显的错误。我就是找不到任何东西。

KKAppDelegate* ad = (KKAppDelegate*)[KTApplication sharedApplication].delegate;
float windowHeight = ad.window.frame.size.height;

float x = _position.x - _contentSize.width * _anchorPoint.x;
float y = windowHeight - (_position.y + _contentSize.height * _anchorPoint.y);

if (_ignoreAnchorPointForPosition)
{
    x += _anchorPointInPoints.x;
    y += _anchorPointInPoints.y;
}

float cx = 1, sx = 0, cy = 1, sy = 0;
if (_rotationX || _rotationY)
{
    float radiansX = CC_DEGREES_TO_RADIANS(_rotationX);
    float radiansY = CC_DEGREES_TO_RADIANS(_rotationY);
    cx = cosf(radiansX);
    sx = sinf(radiansX);
    cy = cosf(radiansY);
    sy = sinf(radiansY);
}

CGAffineTransform transform = 
    CGAffineTransformMake(cy * _scaleX, sy * _scaleX,
                          -sx * _scaleY, cx * _scaleY, x, y);

#if KK_PLATFORM_IOS
    _cocoaView.transform = transform;
#elif KK_PLATFORM_MAC
    _cocoaView.layer.affineTransform = transform;
#endif

我验证了代码运行并且 x/y 值是可以预期的(即没有负位置或疯狂值)。甚至在第一步都没有执行旋转,但是在第一帧的变换和绘制之后我仍然看不到 NSView。

我对 CALayer 和对 NSView 应用转换完全是 n00b。如果不是解决方案,我将不胜感激,然后提供一些有关如何调试的提示。谢谢!

更新:

我开始尝试通过小值更改图层的变换,看看会发生什么。

CGAffineTransform transform = _cocoaView.layer.affineTransform;
transform = CGAffineTransformTranslate(transform, 0.1, 0.1);
_cocoaView.layer.affineTransform = transform;

这样做的效果是一个缓慢移动的 NSButton。它一直向上和向右移动,但在视图框架的边界矩形处消失:

所以我认为我的问题是视图没有被转换,只是图层 - 当我转换图层时,它会快速将视图的内容绘制到图层边界之外,因此不再显示任何内容。

我是否正确地假设我必须直接更改视图的属性?文档也强调了这一点。在这一点上我只是不知道如何将转换应用到视图(即我回到第一方)。我尝试手动设置旋转和框架原点,但这样我无法将旋转中心与 cocos2d 节点的中心(anchorPoint)对齐。

【问题讨论】:

    标签: objective-c cocoa nsview transformation cgaffinetransform


    【解决方案1】:

    UIButtonNSButton 之间有一个重要区别。即使 NSButton 最终是 NSView 的子类,NSButton 的呈现也是由其单元格 NSButtonCell 完成的。单元被创建为 NSView 的“更轻”版本。正如 Apple 的文档所述:

    NSCell 类提供了一种在 一个没有完整 NSView 子类开销的 NSView 对象。它的 大多数 NSControl 类大量使用来实现它们的 内部运作。

    虽然这在早期的 Mac OS X 时代很有用,但现在已不再如此,希望 Apple 会在某个阶段在 AppKit 中改变这一点。

    发生在你身上的是单元格被旋转了,但随后它被视图裁剪,在你的情况下是按钮本身。

    为了解决这个问题,也让NSButton的superview layer-backed,我相信剪裁会消失:

    [nsView.superview setWantsLayer:YES];
    

    【讨论】:

    • 谢谢,我试试看。
    • 这种方法可行,但有一个很大的缺点:因为 superview 是一个与主窗口大小相同的覆盖窗口,由于某种原因,在其 contentView 上启用图层支持会禁用所有用户输入。不只是在窗口内部,甚至是窗口的 x + - 图标(这可能是因为窗口实际上太大了)。同样有趣的是:如果覆盖窗口的 contentView 是 layer-backed 但没有子视图,它会将帧速率减慢到 30 fps,直到添加视图(按钮)。不过,你应该得到 500 分。 ;)
    • 一个替代层支持窗口的 contentView,如果你只需要旋转,是使用传统的方法来旋转视图,使用 NSView 的 - (void)setFrameRotation:(CGFloat)angle 或 - (void )setFrameCenterRotation:(CGFloat)角度。如果它是 NSControl,您可以检查对象的类并以这种方式旋转它。
    猜你喜欢
    • 2010-09-25
    • 2012-08-17
    • 2010-11-09
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    • 2018-02-17
    相关资源
    最近更新 更多