【问题标题】:Rounded corner gradient background of window in CocoaCocoa中窗口的圆角渐变背景
【发布时间】:2012-08-15 15:05:22
【问题描述】:

我有一个带有文本字段和边框按钮的窗口。它是无边界且透明的,但问题会在任何窗口上重现。

该窗口的内容视图在 IB 中设置为绘制窗口背景的自定义类。

代码如下:

- (void)drawRect:(NSRect)dirtyRect
{
    [NSGraphicsContext saveGraphicsState];

    float cornerRadius = 10;
    NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:self.bounds xRadius:cornerRadius yRadius:cornerRadius];

    [path setClip];

    NSGradient *gradient = [[NSGradient alloc] initWithColorsAndLocations:
                            [NSColor colorWithCalibratedRed:0.96f green:0.96f blue:0.96f alpha:1.00f], 0.0f,
                            [NSColor colorWithCalibratedRed:0.84f green:0.84f blue:0.84f alpha:1.00f], 1.0f,
                            nil];

    [gradient drawInRect:self.bounds angle:270];

    [NSGraphicsContext restoreGraphicsState];
}

它会导致一些非常奇怪的伪影,例如消失的对象或文本字段的背景更改为窗口的:

发生了什么事?我试图隔离它,我一直在玩这个“图形上下文状态保存”的东西(我不确定我是否理解正确),但问题仍然存在。

我有 XCode 4.4,SDK 是 10.7(我的操作系统也是),部署目标是 10.6。可能没关系,但我过去一直在做类似的事情,我从来没有遇到过这么奇怪的问题。

【问题讨论】:

  • 这个人看起来很棘手。

标签: objective-c macos cocoa


【解决方案1】:

问题似乎出在 [path setClip] 方法上。我对此进行了注释,文本字段和按钮绘制正确。

所以,我然后替换了这一行:

[gradient drawInRect:self.bounds angle:270];

[gradient drawInBezierPath:path angle:270];

一切都很完美。按钮和文本字段按预期显示。

NSBezierPath 的类参考声明:

你应该避免使用这种方法来调整剪切路径,因为它可能会扩展剪切路径超出封闭视图设置的范围。如果您确实使用此方法,请务必在修改剪切路径之前保存图形状态,并在完成后恢复图形状态。

此方法使用当前的绕线规则来确定接收器的剪裁形状。此方法不影响接收者的路径。

并没有真正解释你看到的问题,但引导我看看我还能如何绘制渐变。

【讨论】:

  • 感谢您的回答,我明天再看看!
  • 嘿,它似乎工作! :) 但是如果我需要将我的“圆角”贝塞尔路径剪裁到脏矩形怎么办?我用什么? +clipRect: 的 NSBezierPath?它似乎有效,但我不知道边缘情况......
  • 查看视图的drawRect,它被传递给整个视图的dirtyRect,然后是文本字段的dirtyRect,基本上每次输入光标闪烁时。我认为这就是剪辑影响文本字段和按钮的原因。所以问题是,你什么时候想将“圆角”应用于dirtyRect。由于 dortyRect 将在不同时间表示视图的不同部分,因此如果您使用dirtyRect,您将影响这些部分。
  • 现在对我来说一切都很有意义。当输入光标闪烁时,为窗口的内容视图调用 -drawRect ,然后为文本字段调用,但由于按钮没有改变,我已经绘制了按钮的图像。那是对的吗?我的经验是在 webdev 中,每个层都是独立的(据我所知,就像在 Core Animation 层中一样),所以它对我来说非常深奥。
  • 但我不明白一件事:如果是这样,为什么 [gradient drawInBezierPath:path angle:270];工作,但是 [path setClip];[gradient drawInRect:self.bounds angle:270];不是吗?前者中的路径是否自动剪辑到脏矩形?这很奇怪。
【解决方案2】:

使其工作的一种解决方法是(在窗口的 -awakeFromNib 或 -init 处)制作与 self.bounds 大小相同的 NSImage,然后将此渐变绘制到图像中(使用图像的 -lockFocus、-unlockFocus)。然后,您可以使用 window.backgroundColor = [NSColor colorWithPatternImage:image];

将图像设置为背景

它有效,但我对解决方案不满意。

我看不出有任何理由说明上述方法不起作用。我在绘制视图时也遇到过类似的奇怪问题,所以我想知道它不起作用的真正原因。

【讨论】:

    【解决方案3】:

    我同意这很奇怪/烦人。有人会认为这只是层之间可能相互干扰的问题..但如果不执行以下操作似乎很难解决..

    这是您描述的视图,搞砸了。 和之后 - 通过界面生成器更改了一个简单的复选框..

    我发现通过将有问题的控件封装在一个框或视图或诸如此类的东西中,然后单击界面构建器中的“核心动画”“setWantsLayer”按钮,将允许这些界面元素在没有所有杂乱无章的情况下发光。

    有点愚蠢的解决方法……但实际上它很有效——而且很简单。

    PS - 我发现在排除此类问题时,让参数(颜色等)更加生动会有所帮助 - 特别是当您试图向人们描述问题所在时..

    【讨论】:

    • 嘿,谢谢你的提示。这似乎很有用,尽管对于我在使用 CA 层时遇到这些问题的特定项目不是一种选择(因为该应用程序基于 WebKit,由于某种原因,当您使用层时,它会出现混乱)
    • 有趣!似乎有效,但我收到此通知:“当 [NSGraphicsContext currentContext] 为 nil 时绘制图像没有意义。这是一个编程错误。在 void _NSWarnForDrawingImageWithNoCurrentContext() 上中断以进行调试。这只会记录一次。这可能会在未来打破。”。这是什么意思?
    • 您是否“链接”到QuartzCore.framework?它也适用于我没有[NSGraphicsContext saveGraphicsState];[NSGraphicsContext restoreGraphicsState];。把他们赶出去!当您混合可可和石英绘图时,您通常只需要担心您的上下文,或者将焦点锁定在绘图例程中的特定“子矩形”上。
    • 我总是忘记链接 QuartzCore ;) (但它仍然有效,ML 中是否发生了一些变化?)我有 [path setClip];在代码中,因此 AFAIK 保存/恢复图形上下文是必要的
    猜你喜欢
    • 2011-08-23
    • 2019-02-22
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    • 2016-10-05
    • 2010-12-03
    • 1970-01-01
    相关资源
    最近更新 更多