【IOS開發(fā)基礎(chǔ)系列】UIScrollView專題

1 UIScrollView原理

? ? ? ?在滾動(dòng)過程當(dāng)中汁胆,其實(shí)是在修改原點(diǎn)坐標(biāo)呛伴。當(dāng)手指觸摸后,scroll view會(huì)暫時(shí)攔截觸摸事件,使用一個(gè)計(jì)時(shí)器臣疑。假如在計(jì)時(shí)器到點(diǎn)后沒有發(fā)生手指移動(dòng)事件,那么scroll view 發(fā)送 tracking events 到被點(diǎn)擊的subview馒胆。假如在計(jì)時(shí)器到點(diǎn)前發(fā)生了移動(dòng)事件缨称,那么 scroll view 取消tracking 自己發(fā)生滾動(dòng)。

??? 子類可以重載?

touchesShouldBegin:withEvent:inContentView:

????決定自己是否接收 touch 事件

pagingEnabled:????

????當(dāng)值是 YES 會(huì)自動(dòng)滾動(dòng)到 subview 的邊界祝迂,默認(rèn)是NO

touchesShouldCancelInContentView:????

????開始發(fā)送 tracking messages 消息給 subview 的時(shí)候調(diào)用這個(gè)方法睦尽,決定是否發(fā)送 tracking messages 消息到subview。假如返回 NO型雳,發(fā)送当凡。YES 則不發(fā)送。假如 canCancelContentTouches屬性是NO纠俭,則不調(diào)用這個(gè)方法來影響如何處理滾動(dòng)手勢(shì)沿量。

??? ????????scroll view 還處理縮放和平移手勢(shì),要實(shí)現(xiàn)縮放和平移冤荆,必須實(shí)現(xiàn)委托 viewForZoomingInScrollView:和scrollViewDidEndZooming:withView:atScale: 兩個(gè)方法朴则。另外 maximumZoomScale和minimumZoomScale 兩個(gè)屬性要不一樣。


1.1 核心原理

????????UIScrollView的核心理念是匙赞,它是一個(gè)可以在內(nèi)容視圖之上佛掖,調(diào)整自己原點(diǎn)位置的視圖。它根據(jù)自身框架的大小涌庭,剪切視圖中的內(nèi)容芥被,通常框架是和應(yīng)用程序窗口一樣大坐榆。一個(gè)滾動(dòng)的視圖可以根據(jù)手指的移動(dòng)拴魄,調(diào)整原點(diǎn)的位置。展示內(nèi)容的視圖席镀,根據(jù)滾動(dòng)視圖的原點(diǎn)位置匹中,開始繪制視圖的內(nèi)容,這個(gè)原點(diǎn)位置就是滾動(dòng)視圖的偏移量豪诲。ScrollView本身不能繪制顶捷,除非顯示水平和豎直的指示器。滾動(dòng)視圖必須知道內(nèi)容視圖的大小屎篱,以便于知道什么時(shí)候停止服赎;一般而言,當(dāng)滾動(dòng)出內(nèi)容的邊界時(shí)交播,它就返回了重虑。

????????某些對(duì)象是用來管理內(nèi)容顯示如何繪制的,這些對(duì)象應(yīng)該是管理如何平鋪顯示內(nèi)容的子視圖秦士,以便于沒有子視圖可以超過屏幕的尺寸缺厉。就是當(dāng)用戶滾動(dòng)時(shí),這些對(duì)象應(yīng)該恰當(dāng)?shù)脑黾踊蛘咭瞥右晥D隧土。

???? ????因?yàn)闈L動(dòng)視圖沒有滾動(dòng)條提针,它必須知道一個(gè)觸摸信號(hào)是打算滾動(dòng)還是打算跟蹤里面的子視圖。為了達(dá)到這個(gè)目的次洼,它臨時(shí)中斷了一個(gè)touch-down的事件关贵,通過建立一個(gè)定時(shí)器,在定時(shí)器開始行動(dòng)之前卖毁,看是否觸摸的手指做了任何的移動(dòng)揖曾。假如定時(shí)器行動(dòng)時(shí),沒有任何的大的位置改變亥啦,滾動(dòng)視圖就發(fā)送一個(gè)跟蹤事件給觸摸的子視圖炭剪。如果在定時(shí)器消失前,用戶拖動(dòng)他們的手指足夠的遠(yuǎn)翔脱,滾動(dòng)視圖取消子視圖的任何跟蹤事件奴拦,滾動(dòng)它自己。子類可以重載touchesShouldBegin:withEvent:inContentView:,? pagingEnabled 和touchesShouldCancelInContentView:方法届吁,從而影響滾動(dòng)視圖的滾動(dòng)手勢(shì)错妖。

????????一個(gè)滾動(dòng)視圖也可以控制一個(gè)視圖的縮放和平鋪绿鸣。當(dāng)用戶做捏合手勢(shì)時(shí),滾動(dòng)視圖調(diào)整偏移量和視圖的比例暂氯。當(dāng)手勢(shì)結(jié)束的時(shí)候潮模,管理視圖內(nèi)容顯示的對(duì)象,就應(yīng)該恰當(dāng)?shù)纳?jí)子視圖的顯示痴施。當(dāng)手勢(shì)在處理的過程中擎厢,滾動(dòng)視圖不能夠給子視圖,發(fā)送任何跟蹤的調(diào)用辣吃。

1.2 事件處理

????????UIScrollView類有一個(gè)delegate动遭,需要適配的協(xié)議是UIScrollViewDelegate。為了縮放和平鋪工作神得,代理必須實(shí)現(xiàn)viewForZoomingInScrollView:和scrollViewDidEndZooming:withView:atScale:方法厘惦。另外,最大和最小縮放比例應(yīng)該是不同的循头。

????????重要的提示:在UIScrollView對(duì)象中绵估,你不應(yīng)該嵌入任何UIWebView和UITableView。假如這樣做卡骂,會(huì)出現(xiàn)一些異常情況国裳,因?yàn)?個(gè)對(duì)象的觸摸事件可能被混合,從而錯(cuò)誤的處理全跨。

????????這些都是官方API的解釋缝左,重點(diǎn)是理解UIScrollView怎么來控制手勢(shì)的∨ㄈ簦可以由canCancelContentTouches這個(gè)方法的運(yùn)用來解釋UIScrollView如何控制手勢(shì)的渺杉。

???? ????假如你設(shè)置canCancelContentTouches為YES,那么當(dāng)你在UIScrollView上面放置任何子視圖的時(shí)候挪钓,當(dāng)你在子視圖上移動(dòng)手指的時(shí)候是越,UIScrollView會(huì)給子視圖發(fā)送touchCancel的消息。而如果該屬性設(shè)置為NO碌上,ScrollView本身不處理這個(gè)消息倚评,全部交給子視圖處理。

????????那么這里就有疑問了馏予,既然該屬性設(shè)置未來NO了天梧,那么豈不是UIScrollView不能處理任何事件了,那么為何在子視圖上快速滾動(dòng)的時(shí)候霞丧,UIScrollView還能移動(dòng)那呢岗。這個(gè)一定要區(qū)分前面所說的UIScrollView中斷touch-Down事件,開啟一個(gè)定時(shí)器。我們?cè)O(shè)置的這個(gè)cancancelContentTouches屬性為NO時(shí)后豫,只是讓UIScrollView不能發(fā)送cancel事件給子視圖悉尾。而前面所說的時(shí),中斷touch-down事件挫酿,和取消touch事件是倆碼事焕襟,所以當(dāng)快速在子視圖上移動(dòng)的時(shí)候,當(dāng)然可以滾動(dòng)饭豹。但是如果你慢速的移動(dòng)的話,就可以區(qū)分這個(gè)屬性了务漩,假如設(shè)定為YES拄衰,在子視圖上慢速移動(dòng)也可以滾動(dòng)視圖,但是如果為NO?饵骨。因?yàn)閁IScrollView翘悉,發(fā)送了cancel事件給子視圖處理了,自己當(dāng)然滾動(dòng)不了了居触。


????????首先了解下UIScrollView對(duì)于touch事件的接收處理原理:UIScrollView應(yīng)該是重載了hitTest 方法妖混,并總會(huì)返回itself 。所以所有的touch 事件都會(huì)進(jìn)入到它自己里面去了轮洋。內(nèi)部的touch事件檢測(cè)到這個(gè)事件是不是和自己相關(guān)的制市,或者處理或者除遞給內(nèi)部的view。

? ??????為了檢測(cè)touch是處理還是傳遞弊予,UIScrollView當(dāng)touch發(fā)生時(shí)會(huì)生成一個(gè)timer祥楣。???

? ? ?(1)如果150ms內(nèi)touch未產(chǎn)生移動(dòng),它就把這個(gè)事件傳遞給內(nèi)部view汉柒;

????(2)如果150ms內(nèi)touch產(chǎn)生移動(dòng)误褪,開始scrolling,不會(huì)傳遞給內(nèi)部的view碾褂。(如當(dāng)你touch一個(gè)table時(shí)候兽间,直接scrolling,你touch的那行永遠(yuǎn)不會(huì)highlight正塌。)

????(3)如果150ms內(nèi)touch未產(chǎn)生移動(dòng)并且UIScrollView開始傳遞內(nèi)部的view事件嘀略,但是移動(dòng)足夠遠(yuǎn)的話,且canCancelContentTouches = YES传货,UIScrollView會(huì)調(diào)用touchesCancelled方法屎鳍,cancel掉內(nèi)部view的事件響應(yīng),并開始scrolling。(如當(dāng)你touch一個(gè)table问裕, 停止了一會(huì)逮壁,然后開始scrolling,那一行就首先被highlight粮宛,但是隨后就不在高亮了)

????????在滾動(dòng)過程當(dāng)中窥淆,其實(shí)是在修改原點(diǎn)坐標(biāo)卖宠。當(dāng)手指觸摸后, scroll view會(huì)暫時(shí)攔截觸摸事件,使用一個(gè)計(jì)時(shí)器。假如在計(jì)時(shí)器到點(diǎn)后沒有發(fā)生手指移動(dòng)事件忧饭,那么 scroll view 發(fā)送 tracking events 到被點(diǎn)擊的 subview扛伍。假如在計(jì)時(shí)器到點(diǎn)前發(fā)生了移動(dòng)事件,那么 scroll view 取消 tracking 自己發(fā)生滾動(dòng)词裤。


1.3 內(nèi)存重用

????????事件處理看過了刺洒,就要考慮scrollView如何重用內(nèi)存的,下面寫了一個(gè)例子模仿UITableView的重用的思想吼砂,這里只是模仿逆航,至于蘋果公司怎么實(shí)現(xiàn)這種重用的,他們應(yīng)該有更好的方法渔肩。

?????這里的例子是在scrollView上放置4個(gè)2排2列的視圖因俐,但是內(nèi)存中只占用6個(gè)視圖的內(nèi)存空間。當(dāng)scrollView滾動(dòng)的時(shí)候周偎,通過不停的重用之前視圖的內(nèi)存空間抹剩,從而達(dá)到節(jié)省內(nèi)存的效果。重用的方法如下:

????1.如果scrollView向下面滾動(dòng)蓉坎,一旦一排視圖滾出了可視范圍澳眷,就改變滾動(dòng)出去的那個(gè)view在scrollView中的frame,也就是改變位置到達(dá)末尾蛉艾,達(dá)到重用的效果境蔼。

????2.如果scrollView向上面滾動(dòng),一旦最末排的視圖view滾出了可視范圍伺通,就改變滾動(dòng)出去的那個(gè)view在scrollView中的frame箍土,移動(dòng)到最前面。

???????下面就需要在你創(chuàng)建的視圖控制器中罐监,創(chuàng)建一個(gè)重用的視圖數(shù)組吴藻,用來把這些要顯示的視圖放入內(nèi)存中,這里雖然界面上顯示的是2排2列的四個(gè)視圖弓柱,但是當(dāng)拖動(dòng)的時(shí)候沟堡,可能出現(xiàn)前面一排的視圖顯示一部分,末尾一排的視圖顯示一部分的情況矢空,所以重用的數(shù)組中要放置6個(gè)視圖航罗。下面是定義的一些宏:

#define?sMyViewTotal?6

#define?sMyViewWidth?150

#define?sMyViewHeight?220

#define?sMyViewGap?10


具體實(shí)現(xiàn)代碼如下:

_aryViews?=?[[NSMutableArray?alloc]?init];

for?(int?i?=?0;?i?<?sMyViewTotal;?i++)?{

????CGFloat?x;

????if?(i%2)?{

????????x?=?sMyViewWidth?+?sMyViewGap?+?sMyViewGap/2;

????}

????else{

????x?=?sMyViewGap/2;

????}

????CGFloat?y?=?(sMyViewHeight?+?sMyViewGap)*(i/2);

????MyView?*myView?=?[[MyView?alloc]?initWithFrame: CGRectMake(x, y,?sMyViewWidth, sMyViewHeight)];

????myView.showNumber?=?i;

????[myScrollView?addSubview: myView];

????[_aryViews?addObject: myView];

????[myView?release];

}


所以這里的核心方法是,首先要判斷是向上滾動(dòng)還是向下滾動(dòng)方法如下:

-?(void) scrollViewDidScroll: (UIScrollView?*)scrollView{

????BOOL?directDown;

????if?(previousOffSet.y?<?scrollView.contentOffset.y)?{

????????directDown?=?YES;

????}

????else{

????????directDown?=?NO;

????}

????previousOffSet.y?=?scrollView.contentOffset.y;

????//防止最開始就向上面拖動(dòng)的時(shí)候屁药,改變數(shù)組視圖樹的位置粥血。

????if?(scrollView.contentOffset.y?<?0)?{

????????return;

????}


????if?(directDown)?{

????????NSLog(@"down");

????????MyView?*?subView?=?[_aryViews?objectAtIndex: firstViewIndex];

????????CGFloat?firstViewYOffset?=?subView.frame.origin.y?+?subView.frame.size.height?+?sMyViewGap;

????????//尋找第一個(gè)視圖是否滾動(dòng)出去

????????if?(firstViewYOffset?<?scrollView.contentOffset.y)?{

????????????//改變數(shù)組中第一排可見視圖的位置。

????????????[self?moveIndexInViewsWithDirect: YES];

????????}

????}

????else{

????????NSLog(@"up");

????????MyView?*?subView?=?[_aryViews?objectAtIndex: (firstViewIndex?+ sMyViewTotal -?2) % sMyViewTotal];

????????CGFloat?lastViewYOffset?=?subView.frame.origin.y?-?scrollView.bounds.size.height;

????????if?(lastViewYOffset?>?scrollView.contentOffset.y)?{

????????????[self?moveIndexInViewsWithDirect: NO];

????????}

????}

}


????????每次滾動(dòng)的時(shí)候先判斷滾動(dòng)位置即offset,和先前的比較复亏。如果先前的大就是向下滾動(dòng)趾娃,否則就是向上滾動(dòng)。

????????找到了向下滾動(dòng)了缔御,就該判斷是否子視圖已經(jīng)離開了可視范圍抬闷。方法就是判斷當(dāng)前offset和視圖的位置進(jìn)行比較。如果判斷滾到離開了可視范圍耕突,然后就是要改變重用視圖數(shù)組中第一個(gè)視圖的位置了笤成。這里用了firstViewIndex來記錄scrollView中第一個(gè)可見視圖的位置,?循環(huán)使用這6個(gè)視圖達(dá)到重用的目的眷茁。自然firstViewIndex上面的一個(gè)視圖就是最后一個(gè)視圖的位置(firstViewIndex?+?sMyViewTotal?-?1) %sMyViewTotal疹启。所以這里需要改變重用視圖中firstViewIndex即第一個(gè)可見視圖的位置。代碼如下:

-?(void) moveIndexInViewsWithDirect: (BOOL)forward{

????[UIView?setAnimationsEnabled: NO];

????if?(forward)?{

????????for?(int?i?=?firstViewIndex;?i?<?(firstViewIndex?+?2);?i++)?{

????????????MyView?*subView?=?[_aryViews?objectAtIndex: i % sMyViewTotal];

????????????subView.showNumber?=?subView.showNumber?+?sMyViewTotal;

????????????subView.frame?=?CGRectMake(subView.frame.origin.x,?subView.frame.origin.y?+?(sMyViewTotal/2)?*?(sMyViewHeight?+?sMyViewGap),?subView.frame.size.width,?subView.frame.size.height);

????????}

????????firstViewIndex?=?(firstViewIndex?+?2) % sMyViewTotal;

????}

????else{

????????int?lastViewIndex?=?firstViewIndex?+?sMyViewTotal?-?1;

????????for?(int?i?=?lastViewIndex;?i?>?(lastViewIndex?-?2);?i-)?{????????????

????????????MyView?*subView?=?[_aryViews?objectAtIndex:(firstViewIndex?+ sMyViewTotal?-?i) % sMyViewTotal];

???????????subView.showNumber?=?subView.showNumber?-?sMyViewTotal;

????????????subView.frame?=?CGRectMake(subView.frame.origin.x,?subView.frame.origin.y?-?(sMyViewTotal/2)?*?(sMyViewHeight?+?sMyViewGap),?subView.frame.size.width,?subView.frame.size.height);

????????}

????????firstViewIndex?=?(firstViewIndex?+?sMyViewTotal?-?2) % sMyViewTotal;

????}

????[UIView?setAnimationsEnabled: YES];

}


??????這里創(chuàng)建的子視圖數(shù)字屬性蔼卡,是用來在視圖上畫數(shù)字的,這樣就可以看到視圖重用的效果了挣磨,應(yīng)該是從0開始到無窮多雇逞,但是實(shí)際上內(nèi)存中就創(chuàng)建了6個(gè)視圖。

-?(void)drawRect:(CGRect)rect

{

????//?Drawing?code

????NSString?*text?=?[NSString?stringWithFormat:@"%d",showNumber];

????[[UIColor?redColor]?set];

????[text?drawInRect: CGRectMake(rect.origin.x, rect.origin.y?+?rect.size.height/2?-?30, rect.size.width, 30) withFont:[UIFont??????fontWithName: @"Helvetica"?size:20] lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentCenter];

}


2 開發(fā)運(yùn)用

2.1 重要屬性

2.1.1 Contentsize與contentInset

????????contentsize是內(nèi)容的寬和高茁裙,contentsize.width是內(nèi)容的寬度塘砸,contentsize.heght是高度,contentsize是UIScrollView的一個(gè)屬性晤锥,它是一個(gè)CGSize掉蔬,是由核心圖形所定義的架構(gòu),那定義了你可以滾軸內(nèi)容的寬度和高度矾瘾,你也可以添加可以上下滾動(dòng)的額外區(qū)域女轿。第一種方法是你可以通過添加內(nèi)容的大小來完成。另外一個(gè)比較動(dòng)態(tài)的選擇是UIScrollView的另一個(gè)屬性contentInset壕翩,contentInset增加你在contentsize中指定的內(nèi)容能夠滾動(dòng)的上下左右區(qū)域數(shù)量contentInset.top以及contentInset.buttom分別表示上面和下面的距離蛉迹。

????????在滾軸視圖中,有一個(gè)叫做ContentOffset的屬性跟蹤UIScrollView的具體位置放妈,你能夠自己獲取和設(shè)置它北救,ContentOffset是你當(dāng)前可視內(nèi)容在滾軸視圖邊界的左上角那個(gè)點(diǎn)。如圖:

????????可以看出芜抒,ContentOffset內(nèi)容中的那個(gè)點(diǎn)不是從contentInset的左上角開始的珍策,而是內(nèi)容的左上角,此時(shí)的ContentOffset是正值宅倒,但有時(shí)也是負(fù)值攘宙,如下圖所示:

2.1.2 API介紹

touchesShouldBegin:withEvent:inContentView:?

????決定自己是否接收 touch 事件

pagingEnabled:

????當(dāng)值是 YES 會(huì)自動(dòng)滾動(dòng)到 subview 的邊界,默認(rèn)是NO

touchesShouldCancelInContentView:?

? ? 開始發(fā)送 tracking messages 消息給 subview 的時(shí)候調(diào)用這個(gè)方法,決定是否發(fā)送 tracking messages 消息到subview模聋。假如返回 NO肩民,發(fā)送。YES 則不發(fā)送链方。假如 canCancelContentTouches屬性是NO持痰,則不調(diào)用這個(gè)方法來影響如何處理滾動(dòng)手勢(shì)。


????????scroll view 還處理縮放和平移手勢(shì)祟蚀,要實(shí)現(xiàn)縮放和平移工窍,必須實(shí)現(xiàn)委托 viewForZoomingInScrollView:和scrollViewDidEndZooming:withView:atScale:兩個(gè)方法。另外 maximumZoomScale和minimumZoomScale 兩個(gè)屬性要不一樣前酿。

????幾個(gè)屬性介紹:

tracking

????當(dāng) touch 后還沒有拖動(dòng)的時(shí)候值是YES患雏,否則NO

zoomBouncing

????當(dāng)內(nèi)容放大到最大或者最小的時(shí)候值是 YES,否則NO

zooming

????當(dāng)正在縮放的時(shí)候值是 YES罢维,否則NO

decelerating

????當(dāng)滾動(dòng)后淹仑,手指放開但是還在繼續(xù)滾動(dòng)中。這個(gè)時(shí)候是 YES肺孵,其它時(shí)候是NO

decelerationRate

????設(shè)置手指放開后的減速率

maximumZoomScale

????一個(gè)浮點(diǎn)數(shù)匀借,表示能放最大的倍數(shù)

minimumZoomScale

????一個(gè)浮點(diǎn)數(shù),表示能縮最小的倍數(shù)

pagingEnabled

????當(dāng)值是 YES 會(huì)自動(dòng)滾動(dòng)到 subview 的邊界平窘。默認(rèn)是NO

scrollEnabled

????決定是否可以滾動(dòng)

delaysContentTouches

????是個(gè)布爾值吓肋,當(dāng)值是 YES 的時(shí)候,用戶觸碰開始瑰艘,scroll view要延遲一會(huì)是鬼,看看是否用戶有意圖滾動(dòng)。假如滾動(dòng)了紫新,那么捕捉 touch-down 事件均蜜,否則就不捕捉。假如值是NO芒率,當(dāng)用戶觸碰兆龙, scroll view 會(huì)立即觸發(fā)touchesShouldBegin:withEvent:inContentView:,默認(rèn)是YES

canCancelContentTouches

????當(dāng)值是 YES 的時(shí)候敲董,用戶觸碰后紫皇,然后在一定時(shí)間內(nèi)沒有移動(dòng),scrollView 發(fā)送 tracking events腋寨,然后用戶移動(dòng)手指足夠長(zhǎng)度觸發(fā)滾動(dòng)事件聪铺,這個(gè)時(shí)候,scrollView 發(fā)送了 touchesCancelled:withEvent: 到 subview萄窜,然后 scroView 開始滾動(dòng)铃剔。假如值是 NO撒桨,scrollView 發(fā)送 tracking events 后,就算用戶移動(dòng)手指键兜,scrollView 也不會(huì)滾動(dòng)凤类。

contentSize

????里面內(nèi)容的大小,也就是可以滾動(dòng)的大小普气,默認(rèn)是0谜疤,沒有滾動(dòng)效果。

showsHorizontalScrollIndicator

????滾動(dòng)時(shí)是否顯示水平滾動(dòng)條

showsVerticalScrollIndicator

????滾動(dòng)時(shí)是否顯示垂直滾動(dòng)條

bounces

????默認(rèn)是 yes现诀,就是滾動(dòng)超過邊界會(huì)反彈有反彈回來的效果夷磕。假如是 NO,那么滾動(dòng)到達(dá)邊界會(huì)立刻停止仔沿。

bouncesZoom

????和 bounces 類似,區(qū)別在于:這個(gè)效果反映在縮放上面坐桩,假如縮放超過最大縮放,那么會(huì)反彈效果封锉;假如是 NO绵跷,則到達(dá)最大或者最小的時(shí)候立即停止。

directionalLockEnabled

????默認(rèn)是 NO成福,可以在垂直和水平方向同時(shí)運(yùn)動(dòng)碾局。當(dāng)值是 YES 時(shí),假如一開始是垂直或者是水平運(yùn)動(dòng)闷叉,那么接下來會(huì)鎖定另外一個(gè)方向的滾動(dòng)。 假如一開始是對(duì)角方向滾動(dòng)脊阴,則不會(huì)禁止某個(gè)方向

indicatorStyle

????滾動(dòng)條的樣式握侧,基本只是設(shè)置顏色『倨冢總共3個(gè)顏色:默認(rèn)品擎、黑、白

scrollIndicatorInsets

????設(shè)置滾動(dòng)條的位置


2.2 具體使用范例

使用一個(gè)ScrollView

// 創(chuàng)建一個(gè)UIScrollView

CGRectframe = CGRectMake( 0, 0, 200, 200);

scrollView = [[UIScrollView alloc] initWithFrame: frame];

// 添加子視圖(框架可以超過scroll view的邊界)

frame = CGRectMake( 0, 0, 500, 500);

myImageView = [[UIImageView alloc] initWithFrame: frame];

[scrollView addSubview: myImageView];

// 設(shè)置內(nèi)容尺寸

scrollView.contentSize = CGSize(500,500);


2.3 擴(kuò)展ScrollView的行為

????????應(yīng)用程序通常需要知道有關(guān)的滾圖的事件:

????scrolloffset改變的時(shí)候

????拖動(dòng)開始和結(jié)束

? ? 減速的開始和結(jié)束


2.3.1 通過子類化擴(kuò)展ScrollView的行為

????????創(chuàng)建一個(gè)子類

????????重寫一些功能并改變行為

????????關(guān)于這種方式的爭(zhēng)議

? ? ? ? 應(yīng)用程序的邏輯和行為變成了視圖本身的一部分备徐,就像萄传,你可能有一些定制的滾軸邏輯,蜜猾,在那你只在意一個(gè)視圖控制秀菱,但你想在不同地方重復(fù)使用你的滾軸視圖,如果你必須為每個(gè)都子類化蹭睡,你最后會(huì)有很多不同的滾軸視圖子類以及在視圖中的特定應(yīng)用邏輯衍菱。

? ? ? ? 編寫很多子類是很沉悶的事情,你最后會(huì)有很多無法重復(fù)使用的單獨(dú)視圖肩豁,而MVC的視圖部分的一個(gè)重點(diǎn)是視圖是可以在不同的控制器和不同的模式之中重復(fù)使用的脊串,如果我們把所有邏輯都放在視圖中辫呻,它減少了可復(fù)用性。

? ? ? ?你的代碼變得很牢固地配對(duì)在一起琼锋,它實(shí)際上變成了超類的一部分放闺,你無法從UIScrollView中析取它,之后用其它東西代替缕坎,如果它在你控制器中且為控制器的一部分怖侦,在之后更容易改變它工作的方式和重新安排你應(yīng)用程序的一些部分。


2.3.2 通過委托來擴(kuò)展ScrollView的行為(常用的)

????????委托是一個(gè)單獨(dú)的對(duì)象念赶,協(xié)議础钠,定義了委托會(huì)實(shí)現(xiàn)的一系列功能的Objective-C協(xié)議,它創(chuàng)建了一系列很清晰的撤銷點(diǎn)叉谜,在那里你能定制行為和外觀旗吁。它在這些對(duì)象之間保持了松散的配對(duì),視圖本身與視圖控制器或任何其它的控制器對(duì)象停局,委托不是滾軸視圖的直接子類很钓,它比起牢固配對(duì)的子類更加的松散。


2.4 開發(fā)技巧

2.4.1 計(jì)算當(dāng)前頁(yè)面數(shù)

- (void) scrollViewDidEndDecelerating: (UIScrollView*)scrollView {

????// 得到每頁(yè)寬度

??? CGFloat pageWidth = CGRectGetWidth(self.paggingScrollView.frame);


??? // 根據(jù)當(dāng)前的x坐標(biāo)和頁(yè)寬度計(jì)算出當(dāng)前頁(yè)數(shù)

??? //此屬性變化會(huì)調(diào)用Set方法

??? self.currentPage = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;

}


- (void) setCurrentPage: (NSInteger)currentPage {

??? if (_currentPage==currentPage)

??????? return;

??? _lastPage = _currentPage;

??? _currentPage= currentPage;

??? self.paggingNavbar.currentPage= currentPage;


??? [self setupScrollToTop];

??? [self callBackChangedPage];

}


2.4.2? 指定Cell大小與間距



2.4.3 支持點(diǎn)擊狀態(tài)欄回到頁(yè)面頂部

????????scrollsToTop是UIScrollView的一個(gè)屬性董栽,主要用于點(diǎn)擊設(shè)備的狀態(tài)欄時(shí)码倦,是scrollsToTop == YES的控件滾動(dòng)返回至頂部。

????????每一個(gè)默認(rèn)的UIScrollView的實(shí)例锭碳,他的scrollsToTop屬性默認(rèn)為YES袁稽,所以要實(shí)現(xiàn)某一UIScrollView的實(shí)例點(diǎn)擊設(shè)備狀態(tài)欄返回頂部,則需要關(guān)閉其他的UIScrollView的實(shí)例的scrollsToTop屬性為NO擒抛。很好理解:若多個(gè)scrollView響應(yīng)返回頂部的事件推汽,系統(tǒng)就不知道到底要將那個(gè)scrollView返回頂部了,因此也就不做任何操作了歧沪。


3 參考資料

Scroll View Programming Guide for iOS筆記

http://blog.sina.com.cn/s/blog_67419c420100phyf.html


第二歹撒、UIScrollView的使用大全

http://blog.csdn.net/ch_soft/article/details/6947695


[置頂] UIScrollView用法

http://blog.csdn.net/mengtnt/article/details/6723245


UIScrollView原理詳解

http://blog.csdn.net/likendsl/article/details/7592867


TwitterPaggingViewer——類似Twitter,將滑動(dòng)視圖的UIPageControl(就是記錄當(dāng)前頁(yè)面的一串小點(diǎn))放到導(dǎo)航欄

http://code4app.com/ios/TwitterPaggingViewer/53a7ed4a933bf0794c8b48f9


UICollectionViewLayout

http://blog.csdn.net/majiakun1/article/details/17204921


ios開發(fā)——解決UICollectionView的cell間距與設(shè)置不符問題

http://www.bkjia.com/IOSjc/917782.html


IOS中scrollsToTop問題小結(jié)

http://blog.csdn.net/enuola/article/details/32331933


ios重寫Cell后tabelView不能響應(yīng)點(diǎn)擊狀態(tài)欄回到到頂部

http://www.cocoachina.com/bbs/read.php?tid-248386.html


深入理解iOS開發(fā)中的UIScrollView

http://mobile.51cto.com/hot-443341.htm


IOS學(xué)習(xí)——iOS組件之UIScrollView詳解

https://segmentfault.com/a/1190000002412930


IOS發(fā)UI—UIScrollView控件介

http://www.cnblogs.com/wendingding/p/3754210.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市诊胞,隨后出現(xiàn)的幾起案子暖夭,更是在濱河造成了極大的恐慌,老刑警劉巖撵孤,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迈着,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡邪码,警方通過查閱死者的電腦和手機(jī)寥假,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霞扬,“玉大人糕韧,你說我怎么就攤上這事枫振。” “怎么了萤彩?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵粪滤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我雀扶,道長(zhǎng)杖小,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任愚墓,我火速辦了婚禮予权,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浪册。我一直安慰自己扫腺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布村象。 她就那樣靜靜地躺著笆环,像睡著了一般。 火紅的嫁衣襯著肌膚如雪厚者。 梳的紋絲不亂的頭發(fā)上躁劣,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音库菲,去河邊找鬼账忘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛熙宇,可吹牛的內(nèi)容都是我干的鳖擒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼奇颠,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼败去!你這毒婦竟也來了放航?” 一聲冷哼從身側(cè)響起烈拒,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎广鳍,沒想到半個(gè)月后荆几,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赊时,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年吨铸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祖秒。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诞吱,死狀恐怖舟奠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情房维,我是刑警寧澤沼瘫,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站咙俩,受9級(jí)特大地震影響耿戚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阿趁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一膜蛔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧脖阵,春花似錦皂股、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至纷铣,卻和暖如春卵史,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搜立。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工以躯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人啄踊。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓忧设,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親颠通。 傳聞我的和親對(duì)象是個(gè)殘疾皇子址晕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 掌握 UIScrollView的常見屬性 UIScrollView的常用代理方法 UIScrollView的縮放 ...
    JonesCxy閱讀 2,715評(píng)論 1 12
  • 一、簡(jiǎn)介 <<繼承關(guān)系:UIScrollView --> UIView-->UIResponder-->NSObj...
    無邪8閱讀 1,849評(píng)論 0 0
  • 在本課中顿锰,你將連接FoodTracker應(yīng)用的基本UI到代碼谨垃,并定義一些用戶可以在這UI上進(jìn)行的操作。完成后硼控,應(yīng)用...
    raingu24閱讀 1,947評(píng)論 0 2
  • 餓了就吃飯刘陶,困了就睡覺。 人活一世牢撼,最怕的就是匙隔,吃飯時(shí)千般思索,睡覺時(shí)萬(wàn)般思量熏版。 人生以人生為目的纷责,好好活在當(dāng)下捍掺。...
    豫視西影閱讀 471評(píng)論 0 0