如何在 Mac 上与图层支持的视图交互

发布于 2024-11-05 12:39:19 字数 2537 浏览 0 评论 0原文

我正在设计一个包含多个标签和文本字段的用户界面。我想像这样设置 UI 样式:

  1. 为我的 NSWindow 的内容视图设置背景图案,
  2. 在左上角的背景中添加自定义图标

我通过制作内容视图解决了第一个问题层支持的视图,如 Apple 的 NSView 文档:

层支持的视图是由核心动画层支持的视图。视图完成的任何绘制都会缓存在支持层中。您只需调用值为 YESsetWantsLayer: 即可配置图层支持的视图。视图类将自动为您创建一个支持层,并且您可以使用视图类的绘图机制。 当使用图层支持的视图时,您永远不应该直接与图层交互。

层托管视图是包含您打算直接操作的核心动画层的视图。您可以通过实例化 Core Animation 图层类的实例并使用视图的 setLayer: 方法设置该图层来创建图层托管视图。执行此操作后,您可以使用值 YES 调用 setWantsLayer:使用图层托管视图时,不应依赖该视图进行绘图,也不应向图层托管视图添加子视图。

然后生成 CGColorRef绘制我的 CGImage 的 CGPattern :

NSView *mainView = [[self window]contentView];
[mainView setWantsLayer:YES];

为了将背景图像设置为图案,我使用了来自 如何在此处平铺 CALayer 的内容 以完成第一个任务。

然而,对于第二个任务,添加图标我使用了下面的代码:

CGImageRef iconImage = NULL;
NSString *path = [[NSBundle mainBundle] pathForResource:@"icon_128" ofType:@"png"];
if(path != nil) {
    NSURL *imageURL = [NSURL fileURLWithPath:path];
    provider = CGDataProviderCreateWithURL((CFURLRef)imageURL);
    iconImage = CGImageCreateWithPNGDataProvider(provider,NULL,FALSE,kCGRenderingIntentDefault); 
    CFRelease(provider);
}
CALayer *iconLayer = [[CALayer alloc] init];
// layer is the mainView's layer
CGRect layerFrame = layer.frame;
CGFloat iconWidth = 128.f;
iconLayer.frame = CGRectMake(0.f, CGRectGetHeight(layerFrame)-iconWidth, 128.f, 128.f);
iconLayer.contents = (id)iconImage;
CGImageRelease(iconImage);
[layer insertSublayer:iconLayer  atIndex:0];
[iconLayer release];

问题

  1. 我不确定我是否违反了Apple关于层支持视图的限制,即您永远不应该直接与层交互。设置图层的背景颜色时直接与图层交互还是我在这里弄错了?
  2. 我对直接与图层支持视图的图层层次结构进行交互并插入新图层(就像我在第二个任务中所做的那样)有一种不好的感觉。这是可能的还是也违反了苹果的指导方针?我想指出的是,这个内容视图当然有几个子视图,例如标签、文本视图和按钮。
  3. 在我看来,仅使用一个层托管 NSView 似乎是最干净的解决方案。然后,所有文本标签都可以添加为 CATextLayers 等。但是,如果我正确理解 Apple 的文档,我就无法再向视图添加任何控件。我是否必须自己在自定义 CALayers 中编写所有控件才能使其正常工作?听起来像是重新发明了豪华轮子。我也不知道如何仅在 CoreAnimation 中编写 NSTextField

任何有关如何使用 CoreAnimation 和标准控件拆分设计用户界面的建议都值得赞赏。

请注意,我在这里谈论的是 Mac。

I am designing a user interface containing several labels and text fields. I would like to style the UI like this:

  1. setting a background pattern for the content view of my NSWindow
  2. adding a custom icon to the background in the upper left corner

I solved the first problem by making the content view a layer-backed view as described in Apple's documentation of NSView:

A layer-backed view is a view that is backed by a Core Animation layer. Any drawing done by the view is the cached in the backing layer. You configured a layer-backed view by simply invoking setWantsLayer: with a value of YES. The view class will automatically create the a backing layer for you, and you use the view class’s drawing mechanisms. When using layer-backed views you should never interact directly with the layer.

A layer-hosting view is a view that contains a Core Animation layer that you intend to manipulate directly. You create a layer-hosting view by instantiating an instance of a Core Animation layer class and setting that layer using the view’s setLayer: method. After doing so, you then invoke setWantsLayer: with a value of YES. When using a layer-hosting view you should not rely on the view for drawing, nor should you add subviews to the layer-hosting view.

and then generating a CGColorRef out of a CGPattern which draws my CGImage:

NSView *mainView = [[self window]contentView];
[mainView setWantsLayer:YES];

To set the background image as a pattern I used the answer from How to tile the contents of a CALayer here on SO to get the first task done.

However for the second task, adding the icon I used the code below:

CGImageRef iconImage = NULL;
NSString *path = [[NSBundle mainBundle] pathForResource:@"icon_128" ofType:@"png"];
if(path != nil) {
    NSURL *imageURL = [NSURL fileURLWithPath:path];
    provider = CGDataProviderCreateWithURL((CFURLRef)imageURL);
    iconImage = CGImageCreateWithPNGDataProvider(provider,NULL,FALSE,kCGRenderingIntentDefault); 
    CFRelease(provider);
}
CALayer *iconLayer = [[CALayer alloc] init];
// layer is the mainView's layer
CGRect layerFrame = layer.frame;
CGFloat iconWidth = 128.f;
iconLayer.frame = CGRectMake(0.f, CGRectGetHeight(layerFrame)-iconWidth, 128.f, 128.f);
iconLayer.contents = (id)iconImage;
CGImageRelease(iconImage);
[layer insertSublayer:iconLayer  atIndex:0];
[iconLayer release];

The Questions

  1. I am not sure if I am violating Apple's restrictions concerning layer-backed views that you should never interact directly with the layer. When setting the layer's background color I am interacting directly with the layer or am I mistaken here?
  2. I have a bad feeling about interacting with the layer hierarchy of a layer-backed view directly and inserting a new layer like I did for my second task. Is this possible or also violating Apple's guidelines? I want to point out that this content view of course has several subviews such as labels, a text view and buttons.
  3. It seems to me that just using one single layer-hosting NSView seems to be the cleanest solution. All the text labels could then be added as CATextLayers etc. However if I understand Apple's documentation correctly I cannot add any controls to the view anymore. Would I have to code all the controls myself in custom CALayers to get it working? Sounds like reinventing the wheel de luxe. I also have no idea how one would code a NSTextField solely in CoreAnimation.

Any advice on how split designing user interfaces with CoreAnimation and standard controls is appreciated.

Please note that I am talking about the Mac here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

離人涙 2024-11-12 12:39:19

不需要图层支持恕我直言:

对于 1. 我

NSImage *patternImage = [NSImage imageNamed:@"pattern"];
[window setBackgroungdColor:[NSColor colorWithPatternImage:patternImage]];

为 2. 添加一个 NSImageView 作为内容视图的子视图

NSImageView *v = ...
[[window contentView] addSubview:v]; 

在 mac 上,如果有图层支持,某些视图不会很好地响应
:: 例如 pdfview

no layer backing needed IMHO:

for 1. I do a pattern image

NSImage *patternImage = [NSImage imageNamed:@"pattern"];
[window setBackgroungdColor:[NSColor colorWithPatternImage:patternImage]];

for 2. add an NSImageView as a subview of the contentview

NSImageView *v = ...
[[window contentView] addSubview:v]; 

on mac some views dont respond nicely IF layer backed
:: e.g. pdfview

回首观望 2024-11-12 12:39:19

创建一个超级视图容器 A。将子视图 B 添加到 A 以满足您的所有 NSView 需求(按钮等)。将子视图 C 添加到 A 以满足您的所有核心动画需求。

编辑:
更好的是:使用超级视图 A 来满足您所有的 NSView 需求,使用一个子视图 C 来满足您的核心动画需求,完全忽略视图 B。

Make a superview container A. Add a subview B to A for all your NSView needs (buttons, etc.). Add a subview C to A for all your Core Animation needs.

Edit:
Even better: use superview A for all your NSView needs and one subview C for your Core Animation needs, ignoring view B altogether.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文