UIScrollView實現(xiàn)原理 以及和masonry配合使用

UIScrollView使用masonry布局, 必須得給一個固定的contentsize,如果像普通的uiview一樣去布局,那么它將不會具備滾動的效果,只能當做view去使用。
因為UIScrollview內(nèi)部實現(xiàn)原理是依托于已知contentsize去實現(xiàn)的。
使用masonry布局, 首先需要在scrollview上加一個子視圖contentView,通過子視圖的尺寸去撐起scrollview,這樣scrollview就有了具體的contentsize。

具體實現(xiàn)代碼:

myScrollView = [[UIScrollView alloc] init];
    [self.view addSubview:myScrollView];
    myScrollView.backgroundColor = [UIColor whiteColor];
    [myScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        STRONGSELF
        make.edges.mas_equalTo(strongSelf.view);
    }];
    contentView = [[UIView alloc] init];
    [myScrollView addSubview:contentView];
    contentView.backgroundColor = [UIColor whiteColor];
    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_equalTo(myScrollView);
        make.width.mas_equalTo(myScrollView);
        make.height.greaterThanOrEqualTo(@0.f);//此處保證容器View高度的動態(tài)變化 大于等于0.f的高度
    }];

然后將所有的子視圖放在contentView上面,此處的例子是高度不固定,所以scrollview是上下滾動的,所以需要最下面的子視圖來撐起contentview的底部。

UIScrollView實現(xiàn)原理

scrollView繼承自UIView,檢測手指滑動應(yīng)該是在view上放置了一個手勢識別。

- (instancetype)initWithFrame:(CGRect)frame {

self = [super initWithFrame:frame];

if (self) {

UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] init];

[panGesture addTarget:self action:@selector(panGestureAction:)];

[self addGestureRecognizer:panGesture];

}

return self;

}

實現(xiàn)scrollview的滾動,首先要理解frame和bounds的概念。

提到它們,大家都知道frame是相對于父視圖坐標系來說自己的位置和尺寸,bounds相對于自身坐標系來說的位置和尺寸,并且origin一般為(0,0)。

當我們嘗試改變bounds的origin時,我們就會發(fā)現(xiàn)視圖本身沒有發(fā)生變化,但是它的子視圖的位置卻發(fā)生了變化,其實當我們改變bounds的origin的時候,視圖本身位置沒有變化,但是由于origin的值是基于自身的坐標系,所以自身坐標系的位置被我們改變了。而子視圖的frame正是基于父視圖的坐標系,當我們更改父視圖bounds中origin的時候子視圖的位置就發(fā)生了變化,這就是實現(xiàn)scrollView的關(guān)鍵點?。?!

- (void)panGestureAction:(UIPanGestureRecognizer *)pan {

// 記錄每次滑動開始時的初始位置

if (pan.state == UIGestureRecognizerStateBegan) {

self.startLocation = self.bounds.origin;

NSLog(@"%@", NSStringFromCGPoint(self.startLocation));

}

// 相對于初始觸摸點的偏移量

if (pan.state == UIGestureRecognizerStateChanged) {

CGPoint point = [pan translationInView:self];

NSLog(@"%@", NSStringFromCGPoint(point));

CGFloat newOriginalX = self.startLocation.x - point.x;

CGFloat newOriginalY = self.startLocation.y - point.y;

CGRect bounds = self.bounds;

bounds.origin = CGPointMake(newOriginalX, newOriginalY);

self.bounds = bounds;

}

}

理解了上邊內(nèi)容的關(guān)鍵點,下邊我們將對我們實現(xiàn)的scrollView做一個簡單的優(yōu)化。通過contentSize限制scrollView的內(nèi)部空間,實現(xiàn)代碼如下

if (newOriginalX < 0) {

newOriginalX = 0;

} else {

CGFloat maxMoveWidth = self.contentSize.width - self.bounds.size.width;

if (newOriginalX > maxMoveWidth) {

newOriginalX = maxMoveWidth;

}

}

if (newOriginalY < 0) {

newOriginalY = 0;

} else {

CGFloat maxMoveHeight = self.contentSize.height - self.bounds.size.height;

if (newOriginalY > maxMoveHeight) {

newOriginalY = maxMoveHeight;

}

通過contentOffset設(shè)置scrollView的初始偏移量,相信大家已經(jīng)懂了如何設(shè)置偏移量了吧?沒錯我們只需設(shè)置view自身bounds的origin是實現(xiàn)代碼如下:

- (void)setContentOffset:(CGPoint)contentOffset {

_contentOffset = contentOffset;

CGRect newBounds = self.bounds;

newBounds.origin = contentOffset;

self.bounds = newBounds;

}

http://www.itdecent.cn/p/a9a1ca54ca54
關(guān)于scrollview原理的內(nèi)容大部分轉(zhuǎn)載了該作者的內(nèi)容。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容