本文主要讲述如何实现可以控制NSScrollView滚动的Slider,借此来探究、深入理解NSScrollView滚动的原理,最终实现的Demo如下:
接下来,我将通过以下四部分来由浅入深的探究NSScrollView。
一、NSScrollView的结构。
当我们通过Interface Builder将一个NSScrollView拖拽至某个ViewController时,整个NSScrollView的结构如下:
- Bordered Scroll View:NSScrollView的整体结构,由一个Clip View和两个Scroller构成。
- Clip View:非常重要的一部分,通过改变自身的bounds属性,可以使subview滚动。
- Child View:整个NSScrollView中最核心的部分,也是整个NSScrollView中展示的部分。
- Scroller:如图所示,在NSScrollView中有两个Scroller,一个是垂直滚动的滚动条,一个是水平滚动的滚动条。
二、frame与bounds的区别
在每个View中,都有frame与bounds属性,frame与bounds都是用来描述View的位置、大小信息的,但是存在些许差别,在此我只简单的总结一下。
frame:表示在superview坐标系中的位置与大小。
bounds:表示本身坐标系中的位置和大小。
看下图就明白了(还不明白的,仔细看下图,好好琢磨琢磨):
三、NSScrollView的滚动原理
通过上节,我知道了frame与bounds的区别之后,我们来思考一个问题:如果保持自身frame不变,改变了superview的bounds之后,会发生什么?
frame代表superview坐标系中的位置,若superview的bounds改变,意味着superview的坐标系发生了改变,如果此时frame没有改变的话,那么就意味着,本地坐标系的原点随着superview坐标系的偏移发生了变化。
简而言之:改变superview的bounds就可以使当前view的显示位置发生变化。
我们结合第一部分的图来看,如果我们需要让Child View向右滚动10像素,那么我们需要将其superview也就是Clip View的bounds的x坐标的基础上加10即可,这样就实现了Child View的水平滚动。(啥?你问我向左滚动怎么办?要不你猜猜看???)
可如果我们需要让Child View向上滚动10像素呢?很简单,使Clip View的bounds的y坐标减10即可。
四、通过slider实现滚动NSScrollView
slider设置Contiuous.
核心代码如下:
__weak IBOutlet NSSlider *slider;
slider.minValue = 0;
slider.maxValue = NSWidth(childView.frame);
- (IBAction)changed:(NSSlider *)sender {
NSRect bounds = NSMakeRect(sender.doubleValue,
NSMinY(clipView.bounds),
NSWidth(clipView.bounds),
NSHeight(clipView.bounds));
[clipView setValue:@(bounds) forKey:@"bounds"];
}
五、完整Demo源代码
https://github.com/gaoxiaodiao/mac_sample/tree/master/NSScrollView