如何手動(dòng)實(shí)現(xiàn)一個(gè) UIScrollView

UIKit 坐標(biāo)系每一個(gè) View 都定義了他自己的坐標(biāo)系,如下圖所示,x 軸指向右方,y 軸指向下方:

image.png

注意:
這個(gè)邏輯坐標(biāo)系并不關(guān)注包含在其中 View 的寬度和高度,整個(gè)坐標(biāo)系沒有邊界向四周無限延伸。
我們在坐標(biāo)系中放置四個(gè)子 View,每一次色塊代表一個(gè) View

image.png
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
redView.backgroundColor = [UIColor colorWithRed:0.815 green:0.007
blue:0.105 alpha:1];

UIView *greenView = [[UIView alloc] initWithFrame:CGRectMake(150, 160, 150, 200)];
greenView.backgroundColor = [UIColor colorWithRed:0.494 green:0.827
blue:0.129 alpha:1];

UIView *blueView = [[UIView alloc] initWithFrame:CGRectMake(40, 400, 200, 150)];
blueView.backgroundColor = [UIColor colorWithRed:0.29 green:0.564
blue:0.886 alpha:1];

UIView *yellowView = [[UIView alloc] initWithFrame:CGRectMake(100, 600, 180, 150)];
yellowView.backgroundColor = [UIColor colorWithRed:0.972 green:0.905
blue:0.109 alpha:1];

[mainView addSubview:redView];
[mainView addSubview:greenView];
[mainView addSubview:blueView];
[mainView addSubview:yellowView];

bounds

Apple 關(guān)于 UIView 的文檔中是這樣描述 bounds 屬性的:

bounds矩形…描述了該視圖在其自身坐標(biāo)系中的位置和大小。

一個(gè) View 可以被看作是定義在其所在坐標(biāo)系平面上的一個(gè)矩形的可視區(qū)域,View 的邊界表明了這個(gè)矩形可視區(qū)域的位置和大小。

假設(shè)我們的 View 寬320像素,高480像素,原點(diǎn)在(0,0)。那么這個(gè) View 就變成了整個(gè)坐標(biāo)系平面的觀察口,它展示的只是整個(gè)平面的一小部分。位于該 View 邊界外的區(qū)域依然存在,只是被隱藏起來了。

image.png

一個(gè) View 提供了其所在平面的一個(gè)觀察口,Viewbounds 矩形描述了這個(gè)可是區(qū)域的位置和大小。

接下來我們來試著修改 bounds 的原點(diǎn)坐標(biāo):

CGRect bounds = mainView.bounds;
bounds.origin = CGPointMake(0, 100);
mainView.bounds = bounds;

當(dāng)我們把 bound 原點(diǎn)設(shè)為(0,100)后,整個(gè)畫面看起來就像這樣:

image.png

修改 bounds 的原點(diǎn)就相當(dāng)與在平面上移動(dòng)這個(gè)可視區(qū)域。

看起來好像是這個(gè) View 向下移動(dòng)了100像素,在這個(gè) View 自己的坐標(biāo)系中這確實(shí)沒錯(cuò)。不過這個(gè) View 真正位于屏幕上的位置(更準(zhǔn)確的說在其父 View 上的位置)其實(shí)沒有改變,因?yàn)檫@是由 Viewframe 屬性決定的,它并沒有改變:

frame矩形…定義了這個(gè)View在其父View坐標(biāo)系中的位置和大小。

由于 View 的位置是相對固定的,你可以把整個(gè)坐標(biāo)平面想象成我們可以上下拖動(dòng)的透明幕布,把這個(gè) View 想象成我們觀察坐標(biāo)平面的窗口。調(diào)整 ViewBounds 屬性就相當(dāng)于拖動(dòng)這個(gè)幕布,那么下方的內(nèi)容就能在我們 View 中被觀察到:

image.png

修改 bounds 的原點(diǎn)坐標(biāo)也相當(dāng)于把整個(gè)坐標(biāo)系向上拖動(dòng),因?yàn)?Viewframe 沒由變過,所以它相對于父 View 的位置沒有變化過。

其實(shí)這就是 UIScrollView 滑動(dòng)時(shí)所發(fā)生的事情。注意從一個(gè)用戶的角度來看,他以為時(shí)這個(gè) View 中的子 View 在移動(dòng),其實(shí)他們的在坐標(biāo)系中位置(他們的 frame )沒有發(fā)生過變化。

一個(gè) scroll view 并不需要其中子 View 的坐標(biāo)來使他們滾動(dòng),唯一要做的就是改變他的 bounds 屬性。知道了這一點(diǎn),實(shí)現(xiàn)一個(gè)簡單的 scroll view 就沒什么困難了。我們用一個(gè) gesture recognizer 來識(shí)別用戶的拖動(dòng)操作,根據(jù)用戶拖動(dòng)的偏移量來改變 bounds 的原點(diǎn):

和真正的 UIScrollView 一樣,我們的類也有一個(gè) contentSize 屬性,你必須從外部來設(shè)置這個(gè)值來指定可以滾動(dòng)的區(qū)域,當(dāng)我們改變 bounds 的大小時(shí)我們要確保設(shè)置的值是有效的。

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

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

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