使用 UIPageControl 與 UIScrollView 來實作畫面切換的效果,在 iOS 中應該算是最常見的應用。UIPageControl,一個可以顯示目操作狀態 UIControl 元件;UIScrollView 一個提供捲軸功能的 UIView 元件,下面就來看看如何透過這兩個元件來幫助我們達成切換畫面的效果。
實作 UIScrollView 捲動
由於我們要透過 UIScrollView 在捲動時的狀況來設定 UIPageControl,所以必須替實作的 Class 新增 <UIScrollViewDelegate> 協定,才能透過協定內的 scrollViewDidScroll: 方法函式取得 UIScrollView 的捲動狀況。
@interface ViewController : UIViewController <UIScrollViewDelegate>
接下來,分別對兩個元件作初始化的設定,將 UIPageControl 的範圍設定成 5(0~4),並且隱藏 UIScrollView 中所有的捲軸介面,與開啟 Paging 的功能,這樣才能讓使用者在捲頁時是以整個 UIScrollView 為單位,而不是以 Pixel 為單位。 最後我們使用一個 for 迴圈來產生 UIScrollView 中的每個 SubView,其程式碼如下。
//UIPageControl設定
[pageControl setNumberOfPages:5];
[pageControl setCurrentPage:0];
//UIScrollView設定
[scrollView setPagingEnabled:YES];
[scrollView setShowsHorizontalScrollIndicator:NO];
[scrollView setShowsVerticalScrollIndicator:NO];
[scrollView setScrollsToTop:NO];
[scrollView setDelegate:self];
CGFloat width, height;
width = scrollView.frame.size.width;
height = scrollView.frame.size.height;
[scrollView setContentSize:CGSizeMake(width * 5, height)];
//製作ScrollView的內容
for (int i=0; i!=pageControl.numberOfPages; i++) {
CGRect frame = CGRectMake(width*i, 0, width, height);
UIView *view = [[UIView alloc]initWithFrame:frame];
CGFloat r, g ,b;
r = (arc4random() % 10) / 10.0;
g = (arc4random() % 10) / 10.0;
b = (arc4random() % 10) / 10.0;
[view setBackgroundColor:[UIColor colorWithRed:r green:g blue:b alpha:0.3]];
//使用QuartzCore.framework替UIView加上圓角
[view.layer setCornerRadius:15.0];
[scrollView addSubview:view];
}
程式碼到此, UIScrollView 已經有捲頁的效果,只是它還無法與 UIPageControl 做溝通,不能將捲動的頁數設定在 UIPageControl 上,同樣地,操作 UIPageControl 來換頁,也無法反映於 UIScrollView 裡。(關於 UIView 圓角的製作請參考關於 UIView 圓角的二三事一文)
透過 UIScrollView 來設定 UIPageControl 的狀態
在這個部分我們將會實作 <UIScrollViewDelegate> 協定中的方法函式 scrollViewDidScroll:,來將目前 UIScrollView 所捲動的位移量換算成 UIPageControl 的頁數。
- (void)scrollViewDidScroll:(UIScrollView *)sender {
CGFloat width = scrollView.frame.size.width;
NSInteger currentPage = ((scrollView.contentOffset.x - width / 2) / width) + 1;
[pageControl setCurrentPage:currentPage];
}
透過 UIPageControl 來設定 UIScrollView 的狀態
在這部分我們會透過一個自定義的方法函式 changeCurrentPage: 來將 UIPageControl 的頁數換算成 UIScrollView 的位移量,並且讓 UIScrollView 使用動畫的方式捲動過去,你可以將此方法函式與 UIPageControl 中的 Value Changed 事件做連結,這樣每當使用者操作 UIPageControl 改變頁數時,就會呼叫此函式並實作裡面的方法。
- (IBAction)changeCurrentPage:(UIPageControl *)sender {
NSInteger page = pageControl.currentPage;
CGFloat width, height;
width = scrollView.frame.size.width;
height = scrollView.frame.size.height;
CGRect frame = CGRectMake(width*page, 0, width, height);
[scrollView scrollRectToVisible:frame animated:YES];
}
ps:上述所使用的方式是一次產生所有的 SubView, 並將它們全部丟入 UIScrollView 中,這樣的方法雖然相當方便也容易理解,但是如果你的 UIScrollView 內容過於龐大複雜時,卻很容易占用過多的資源,一個比較好的方法是,建立一個 NSMutableArray 來存放這些 UIView 的 UIViewController,並且使用 [NSNull null] 來做暫時的初始化,等到 UIView 真的要顯示時才去產生它。
謝的挺好的^^
回覆刪除多謝指教!
刪除學習了,感恩~
回覆刪除您太客氣了!
刪除成功了 謝謝
回覆刪除但有一個問題想問
我想同時顯示3幅image
我將scrollview 的size 於xib中拉闊至3倍後
再將以上.m file的width都除3了
現在成功同時顯示3個image
但捲動時的step size卻很奇怪
於第1頁scroll 一下就去到第4頁
再scroll 一下去到第5貢
想問捲動的size可以調較嗎?
還是有其他方法解決以上問題?
Jacky 您好:
刪除從你設計的角度來看你把它拉長就可以在同一個UIView下顯示3張圖片,這點來看是沒有錯的。
但是你在捲頁移動時所需要的移動量,並不需要改變,他應該要和你的 scrollview 寬度一樣。
舉個簡單的例子,就像你在使用「延伸桌面的感覺依樣」,你有兩個同大小螢幕,螢幕的大小就是你的 scrollview 大小,當你想要呈現你右手邊的螢幕畫面時只要移動一個螢幕大小的寬度就可以了,也許你只是邏輯上有點打結。
另外關於程式碼第4行 [pageControl setCurrentPage:currentPage] 這邊,只是運算上的問題而已,如果你顯示的畫面都正常,例如一開始你可以看到圖片 123,換到下一頁也可以看到圖片 456,那表示你的時做都沒有問題,再來我解釋一下為什麼是/2,因為我判斷是否成功切換到下一個畫面的依據是,當捲動的位移量超過寬度的一半時,所以這邊是除以二。
有關您的提問,有關調整捲動的大小在程式碼第9行 [scrollView scrollRectToVisible:frame animated:YES], 參數 frame 就是位移量的大小。
最後,希望你可以順利排除錯誤!
[pageControl setCurrentPage:0];
回覆刪除設定為其它頁數似乎沒有反應...
cg2010studio 您好
刪除這只是設定起始數值,如果你一開始就要在其他的分頁畫面,要對 scrollView 做設定才對。
建立一個 NSMutableArray 來存放這些 UIView 的 UIViewController,並且使用 [NSNull null] 來做暫時的初始化,等到 UIView 真的要顯示時才去產生它。
回覆刪除我想問[NSNull null] 是怎樣用的?
即是在PageControl的Delegate裡,計算Page的Frame,再調用這個Function ? ->[scrollView addSubview:view]~~
需不需要前後都計算來避免有Delay ?
WENNY BEN 您好:
回覆刪除有關於 [NSNull null] 的問題,你可以前往 iOS Developer Library 下載他的示範程式碼,這邊的這記概念就是使用 [NSNull null] ,你可以在 PhoneContentController.m 中看到宣告一個 NSMutableArray 之後,先給予 [NSNull null] ,等到要使用時才去建立 UIViewController。
http://developer.apple.com/library/ios/#samplecode/PageControl/Introduction/Intro.html
希望對你有幫助!
你好,我想問可否給予其它設定變數參考?因我是新手,而且對此功能很感興趣。但找了很多資料也做不到。這是我的郵箱:ifong92@gmail.com.
回覆刪除謝謝你!
Stanley Lo 您好:
刪除稍後會將demo寄給您!
哈囉你好
回覆刪除我最近在寫相關的程式,卻又因為是初學者 又是自學很多地方都不懂
在.h的部分是不是還有些程式碼?
不知是否可以請您寄demo給我 讓我參考
我的信箱是:s98113210@stu.edu.tw 感謝您 謝謝
謝至騏 您好:
刪除稍後會將完整的程式碼寄給您!
"建立一個 NSMutableArray 來存放這些 UIView 的 UIViewController,並且使用 [NSNull null] 來做暫時的初始化,等到 UIView 真的要顯示時才去產生它。 "
回覆刪除請問有教學嗎?
不好意思想要做可是還是不太知道要怎麼做:(
您好:
刪除這邊沒有範例耶,因為作法實在非常多,當你先宣告 UIViewController 之後先別急著分配記憶體位置(alloc)或是初始化(init)它,這時候你就可以使用 NULL 來判斷這些尚未設定的 UIView,在進行初始化,這樣的好處在 ps 紅字部分也已經說明。
我找了一了範例,你可以參考一下:
http://www.edumobile.org/iphone/iphone-programming-tutorials/pagecontrol-example-in-iphone/
使用這樣的結構來設計,也可以充分利用物件導向多型的特性,幫助你建立不同類型的 UIViewController。
您好
回覆刪除我照著您的步驟做了
但scrollView無法滑動,也沒跟pagecontrol一起切換
請問哪邊出了問題
不好意思附上我的步驟忘了說我的步驟
回覆刪除將物件pagecontrol跟scrollView
outlet到pageControl跟scrollView
階有@property跟@synthesize
委派跟framework都有弄好
pagecontrol的valueChange也有outlet
您好:
刪除你這樣說我還是不知道問題出在哪,scrollView無法滑動應該是你沒有把它的interaction打開,要啟用互動。
不過也有可能是你沒有把view成功加入到scrollView中,變成內容一片空白你才會覺得他無法滑動。
你可以設定中斷點看看上面這些函式是否有正確被觸發!
如果是CGRect frame = CGRectMake(width*i, 0, 100, 100);
回覆刪除這樣的話就有5個view跑出來
雖說有跑出來卻也無法滑動
但若是照版大您的作法,在我試過後反而看不到
interaction有打開了
還是找不出問題出在哪><
我剛剛想到一個,你是不是使用最新的xcode,回不會是AutoLayout的關係,你試試看把它關掉,下面的連結裡有關掉的方法
刪除http://furnacedigital.blogspot.tw/2012/10/uiview.html
不過無法滑動,有可能你的scrollView上面又有新的View導致無法直接與scrollView做互動!
牛奶大太神了
刪除我把AutoLayout取消勾選run後
終於可以滑動了^^
感謝牛奶大的幫忙
您好:
刪除不客氣,我自己之前也在AutoLayout這邊卡了很久︿︿;
我剛剛照著您的文章做,還一知半解
回覆刪除後來看到Apple的範例就恍然大悟了
http://developer.apple.com/library/ios/#samplecode/PageControl/Introduction/Intro.html
這邊補上大大漏說的部分
ViewController.m檔的部分加上
@interface ViewController ()
{
IBOutlet UIPageControl *pageControl;
IBOutlet UIScrollView *scrollView;
}
@end
然後在Interface Builder上
各拉一個UIPageControl與UIScrollView
將畫面上的UIPageControl
拉關聯(Referencing Outlets) 至 pageControl
另外拉Value Changed的Event 至
- (IBAction)changeCurrentPage:(UIPageControl *)sender上
將畫面上的UIScrollView
拉關聯至 scrollView
另外它的delegate要拉到File's Owner
您好:
刪除謝謝您,不過我大部分的文章都沒有將元件與程式碼做結合,但在命名上也都竟量保留元件的名稱,不過還是非常感謝您的指點。
如果想要了解元件與程式碼之間的運作,可以參考 「從使用 UIButton 說 Hello 開始說起(上)」
http://furnacedigital.blogspot.tw/2011/03/uibutton-hello.html
與「從使用 UIButton 說 Hello 開始說起(下)」
http://furnacedigital.blogspot.tw/2011/03/uibutton-hello_11.html
兩篇文章︿︿;
你好,我是新手,在學純code開放pageview畫面切換的例子,請問能寄demo的程式碼給我參考嗎? chuangyeong@gmail.com,謝謝。
回覆刪除Yon 您好
刪除稍後會將完整的程式碼寄給您!
謝謝您的教學,特別是Auto Layout的部份,受益良多!
回覆刪除您好:
刪除新年快樂,不客氣!
我是一名新手,能將源程式發給我嗎??
回覆刪除citedjade@gmail.com
謝謝!!!
您好 想了解一下 Scrollview 和 pageController的切換,能否跟您取得範例程式碼
回覆刪除謝謝
tamd1980@gmail.com
稍後會將完整的程式碼寄給您!
刪除跪求此demo code 謝謝 email: poseton1@gmail.com
回覆刪除稍後會將完整的程式碼寄給您!
刪除可以跟您要一下code嗎? 謝謝
回覆刪除Email:0801ctc@gmail.com
我照著文章做了之後 跟我說這兩個找不到(showsHorizontalScrollIndicator &showsVerticalScrollIndicator )
稍後會將完整的程式碼寄給您!
刪除你好 我想問問 能用來轉VIEW嗎 我想學
回覆刪除可以以唷 裡面就是放UIView
刪除