
秦人不暇自哀,而后人哀之;后人哀之而不鉴之,亦使后人而复哀后人也
在便捷的网络时代学习,更注重对基础知识的借与鉴。在macOS 开发基础教程视频课程的NSView章节中,解释了关于视图的frame和bounds的坐标参照系统,限于授课经验与课程时间,感觉对NSView的bounds属性,表述的不够深入,希望通过本文帮助观看课程的同学加深对bounds的理解,并通过实例运用,体会在NSView中bounds的真正价值。
关于视图NSView的frame和bounds的概念,我们就不再介绍了,(课程的视频中有图例讲解,网上也有相关资料),这里只重点突出视频教程中的阐述的两个点:
- frame : 相对父控件的坐标系统的描述
- bounds:相对NSView自身坐标系统的描述
上面这两点如果从字面的含义理解起来可能会觉得有些抽象,为了便于具体说明,我们打个比方,将frame想象成为一个相框,它的作用仅仅是告诉父控件自己需要占据的位置和尺寸(嘿!父控件,我需要在你的坐标系统中的占据这个frame.origin位置,尺寸是frame.size的区域),这样以来,父控件在布局的时候,就会知道如何摆放它内部的所有控件了。
视图NSView里的各种内容(subViews),我们可以想象成为各种相片,它们既可以摆放在相框的(frame)内部,也可以摆放在相框的(frame)外部。这正如你在房间的墙上(父控件)里放置了一个有相框壁画(NSView)。
为了防止壁画(NSView)蒙尘,你将整个壁画(NSView)都遮盖保护起来。可是一旦遮盖起来,你发现自己都无法观看了,这时候你想到了一个聪明的办法:在遮盖上开启一个矩形的窗口,透过这个窗口,就可以看到遮盖下面的壁画(NSView)了,如你所料:这个矩形的窗口,就是bounds
通过bounds,我们就可以看到NSView内部所展示的内容。如果bounds比较小(就像你在遮盖上开了一个小小的窗口),可以通过移动bounds位置,来展示NSView的各个区域内容。这样bounds就成为了我们对NSView的观景窗~
如果现在你已经理解了bounds,那么对于ScrollView的是如何实现滑动展示其内部视图内容,就不会觉得奇怪了。
下面我们通过一个示例来加深对bounds的理解和使用
-
创建一个Mac application 项目工程,从控件库中拖动一个customView到ViewController中,并搭建UI界面大致如下:
UI界面 在customView中添加随意几个box视图,并设置颜色(为了观看效果)。
添加自定义类CustomScrollView.swift文件(继承自NSView)来管理customView控件
在Storyboard中设置customView的类属性为:CustomScrollView

- 实现CustomScrollView.swift的代码:
import Cocoa
class CustomScrollView: NSView {
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
NSColor.lightGray.set()
NSRectFill(dirtyRect)
// Drawing code here.
}
override func awakeFromNib() {
super.awakeFromNib()
let pan = NSPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
addGestureRecognizer(pan)
}
// 移动鼠标时,修改视图的bounds属性,即可实现scroll效果
func handlePanGesture(_ panGesture : NSPanGestureRecognizer){
let transPoint = panGesture.translation(in: self)
bounds.origin.x -= transPoint.x
bounds.origin.y -= transPoint.y
panGesture .setTranslation(NSZeroPoint, in: self)
}
}
-
最终运行效果:
运行效果
结束语
我们通过修改一个NSView的bounds,自己实现了一个类似的ScrollView,希望通过本文对视频课程的补充,对你理解bounds属性有所助益,并同时希望对ScrollView的实现机制,你也能有比从前更多一点的掌握了。
谢谢观看,祝课程学习愉快~


