我应该如何将自定义 NSView 包装在 NSScrollView 中?
Cocoa 的 NSScrollView 的解释严重不足。我希望这里有人知道这是什么意思并且可以给我几秒钟的时间。
所以我有一个自定义的 NSView。我实现了 -drawRect:让它绘制一些东西,用颜色填充自己,等等。然后我有一个 NSScrollView 包装它(通过界面生成器设置)。
现在,内部自定义视图的尺寸必须大于适合外部滚动视图的尺寸,以便其滚动。我就意识到这么多了。我顺便配置了它,以便滚动视图调整到周围窗口的大小,但这应该不重要。
我重写内部视图的 -frame 方法以返回大小至少为 1000x1000 的帧。
- (NSRect)frame {
CGFloat w = 1000;
CGFloat h = 1000;
if (self.superview.bounds.size.width > w)
w = self.superview.bounds.size.width;
if (self.superview.bounds.size.height > h)
h = self.superview.bounds.size.height;
return NSMakeRect(0, 0, w, h);
}
这是结果,我很难解释:
- 当滚动视图包围的区域小于 1000x1000 时,我可以滚动,
但是
唯一填充颜色的区域(即我的 -drawRect: 方法有任何效果)是
- 与滚动视图的边界一样大
- 位于(0,0。我使用翻转,所以它在左上角,滚动后它最终位于可见区域之外。
- 位于这个不相关矩形之外的可见区域根本没有被绘制。
除了这一点之外,我不知道任何东西。似乎用于绘制的矩形被剪裁了。滚动视图在窗口中的位置、大小或其他内容,但它没有考虑滚动的“位置”。
应该注意的是,我真的不希望发生任何其他事情,我觉得我错过了。抱歉,我无法更好地解释,但我希望回答比提问更容易
,
不是里克·阿斯特利。
Cocoa's NSScrollView is horribly under-explained. I hope someone here knows what it's all about and can spare me a few seconds.
So I have a custom NSView. I implement -drawRect: for it to draw something, fill itself with colour, whatever. Then I have an NSScrollView wrapping it (set up through the interface Builder).
Now the inner, custom, view must have a size larger than that which fits in the outer scroll view—for it to scroll. That much I realise. I have incidentally configured it so that the scroll view adjusts to the surrounding window’s size, but that shouldn’t matter.
I override my inner view’s -frame method to return a frame sized at least 1000x1000.
- (NSRect)frame {
CGFloat w = 1000;
CGFloat h = 1000;
if (self.superview.bounds.size.width > w)
w = self.superview.bounds.size.width;
if (self.superview.bounds.size.height > h)
h = self.superview.bounds.size.height;
return NSMakeRect(0, 0, w, h);
}
Here’s the outcome, which I have trouble interpreting:
- I can scroll when the scroll view encloses an area smaller than 1000x1000
BUT
The only area filled with colour (i.e. that my -drawRect: method has any effect on) is
- as large as the scroll view’s bounds
- located at (0,0. I use flipped, so that’s top left, and it ends up being outside the visible area after scrolling.
- The visible area that lies outside this irrelevant rectangle is not painted at all.
I don’t know anything beyond this point. It seems like the rect for drawing is clipped to the scroll view’s position in the window, and size, or something—but it does not take the scrolled "location" into account.
It should be noted that I don't really expect anything else to happen. I feel I am missing a piece, but can't find which. Sorry for the wall of text, but I can’t explain better right now. I hope it is easier to answer than it is to ask.
Regards and hope,
Not Rick Astley
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
覆盖
-frame
是一个非常非常坏主意。有很多事情取决于实际实例变量是否具有正确的值。相反,尝试使用setFrame:
将框架设置为您想要的框架,如果幸运的话,这可能会解决您所有的问题......It's a very very very bad idea to overwrite
-frame
. There is so much that depends on the actual instance variable having a correct value. Instead try to set the frame to the one you want usingsetFrame:
, that might fix all your problems if you're lucky...我同意 Max 的警告,即你不应该覆盖 -frame。如果要约束设置的框架,请覆盖其设置器 ( -setFrame: ) 和指定的初始值设定项 ( -initWithFrame: ) 并根据需要调整建议的框架。
关于您的总体问题,我想知道您的问题是否是概念性的。 -drawRect:(要求重绘的脏矩形)的参数非常有用,如果您正在绘制可以分部分增量重绘的内容(例如网格 - 任何与 dirtyRect 相交的网格块都可以重绘,其余部分可以重绘)忽略)。如果你正在做一些必须完全重绘的事情,你应该使用[selfbounds]而不是在drawRect中传递的脏矩形。
例如,如果您只有一个标准渐变背景,则很难从 dirtyRect 判断要重绘渐变的哪一部分,并且只需使用渐变重绘整个视图即可轻松得多,完全忽略 dirtyRect。
您的假设是正确的,在滚动时通常只会要求重绘滚动视图的剪辑矩形所暴露的视图区域。还需要考虑与滚动视图的 -copiesOnScroll 的交互。
我希望这有帮助。
I agree with Max's warning that you shouldn't override -frame. If you want to constrain the set frame, override its setter ( -setFrame: ) and the designated initializer ( -initWithFrame: ) and adjust the proposed frame as desired.
Regarding your overall problem, I wonder if your problem is conceptual. The argument for -drawRect: (the dirty rectangle you're asked to redraw) is useful if you're drawing something that you can redraw incrementally in parts (like a grid - any grid blocks intersecting dirtyRect can be redrawn and the rest can be ignored). If you're doing something that has to be completely redrawn, you should use [self bounds] and not the dirty rect passed at drawRect.
For example, if you have just a standard gradient background, it's difficult to tell from dirtyRect which part of the gradient to redraw and infinitely easier just to redraw the whole view with the gradient, ignoring dirtyRect altogether.
You're right in assuming that only the area of your view exposed by the scroll view's clip rect will normally be asked to redraw when scrolling. There're also interactions with the scroll view's -copiesOnScroll to consider.
I hope this helps.
NSScroller
的使用实际上依赖于对 MVC 范例的深入理解。苹果的文档实际上专注于显示一张照片和一组文本,但没有太多其他内容。 使用NSScrollView
是我的事情过去我们一直在努力解决这个问题。首先,不要覆盖
框架
。使用setFrame
告诉scrollView
工作区域有多大,然后只需在框架包含的区域中绘制即可。据我了解,自定义的 NSView 和包含的 NSScrollView 负责其余的工作,例如何时在何处绘制什么。换句话说,忽略传递给drawRect
的rect
的边界,而是在发送给scrollView
的帧的边界内进行绘制;不要担心什么是可见的,什么是不可见的,因为这是框架的工作。这就是 MVC 范例的用武之地:更新模型时应使用
setFrame
。因此,如果对象超出了框架的当前边界,则使用 setFrame 设置新扩展的边界,然后在该区域内进行绘制。Use of the
NSScroller
really relies on a solid understanding of the MVC paradigm. Apple's docs really focus on showing a photo and a set of text, but not much else. The use ofNSScrollView
is something that I've struggled with in the past.First off, do not override
frame
. UsesetFrame
to tell thescrollView
how large the working area is, and then just simply draw in the area the frame encompasses. As I understand it, a customNSView
and the encompassingNSScrollView
takes care of the rest, such as what to draw where when. In other words, ignore the bounds of therect
passed intodrawRect
and instead draw within the bounds of the frame you sent toscrollView
; don't worry about what is visible and what isn't because that is the job of the framework.Here is where the MVC paradigm comes in:
setFrame
should be used when your Model is updated. So, if an object falls outside of the current bounds of the frame, then usesetFrame
to set the newly expanded bounds, and then draw within that area.