iOS開發(fā)之UIScrollView控件詳解
一、UIScrollView控件是什么?
(1)移動(dòng)設(shè)備的屏幕⼤大⼩小是極其有限的,因此直接展⽰示在⽤用戶眼前的內(nèi)容也相當(dāng)有限
(2)當(dāng)展⽰示的內(nèi)容較多,超出⼀一個(gè)屏幕時(shí),⽤用戶可通過滾動(dòng)⼿手勢(shì)來查看屏幕以外的內(nèi)容
(3)普通的UIView不具備滾動(dòng)功能,不能顯⽰示過多的內(nèi)容
(4)UIScrollView是一個(gè)能夠滾動(dòng)的視圖控件,可以⽤用來展⽰示⼤大量的內(nèi)容,并且可以通過滾 動(dòng)查看所有的內(nèi)容
(5) 舉例:手機(jī)上的“設(shè)置”、其他⽰示例程序
二、UIScrollView的簡(jiǎn)單使用
(1)將需要展⽰的內(nèi)容添加到UIScrollView中
(2)設(shè)置UIScrollView的contentSize屬性,告訴UIScrollView所有內(nèi)容的尺⼨寸,也就是告訴 它滾動(dòng)的范圍(能滾多遠(yuǎn),滾到哪⾥里是盡頭)
注: 本文中所說的"內(nèi)容視圖"在官方文檔中稱作"content view",表示UIScrollView中可以用來展示內(nèi)容的部分
三、屬性與方法
內(nèi)容視圖相關(guān)
// 內(nèi)容視圖的大小,默認(rèn)為CGSizeZero @property(nonatomic) CGSize contentSize; // 為內(nèi)容視圖周圍增加可滾動(dòng)區(qū)域,默認(rèn)為UIEdgeInsetsZero @property(nonatomic) UIEdgeInsets contentInset; // 內(nèi)容視圖的原點(diǎn)相對(duì)于scrollView的原點(diǎn)的偏移量(左上方向偏移為正數(shù)),默認(rèn)為CGPointZero @property(nonatomic) CGPoint contentOffset; // 設(shè)置內(nèi)容視圖的原點(diǎn)相對(duì)于scrollView的原點(diǎn)的偏移量 - (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
滑動(dòng)相關(guān)
// 是否允許滑動(dòng),默認(rèn)為YES @property(nonatomic,getter=isScrollEnabled) BOOL scrollEnabled; // 是否只允許同時(shí)滑動(dòng)一個(gè)方向,默認(rèn)為NO,如果設(shè)置為YES,用戶在水平/豎直方向開始進(jìn)行滑動(dòng),便禁止同時(shí)在豎直/水平方向滑動(dòng)(注: 當(dāng)用戶在對(duì)角線方向開始進(jìn)行滑動(dòng),則本次滑動(dòng)可以同時(shí)在任何方向滑動(dòng)) @property(nonatomic, getter=isDirectionalLockEnabled) BOOL directionalLockEnabled; // 是否允許點(diǎn)擊狀態(tài)欄讓距離狀態(tài)欄最近的scrollView滑動(dòng)到頂部,默認(rèn)為YES(注: 在iPhone中如果有多個(gè)將該屬性設(shè)置為YES的scrollView,則該方法無效;在iPad中則將距離狀態(tài)欄最近的scrollView滑動(dòng)到頂部) @property(nonatomic) BOOL scrollsToTop; // 是否按頁(yè)數(shù)進(jìn)行滑動(dòng),默認(rèn)為NO,如果設(shè)置為YES,則在滑動(dòng)時(shí)只會(huì)停止在scrollView的bounds的倍數(shù)處 @property(nonatomic, getter=isPagingEnabled) BOOL pagingEnabled; // 是否有觸底反彈效果,默認(rèn)為YES @property(nonatomic) BOOL bounces; // 是否總是有觸底反彈效果(即使內(nèi)容視圖小于scrollView的大小),默認(rèn)為NO(注: 生效的前提條件為bounces = YES) @property(nonatomic) BOOL alwaysBounceHorizontal; @property(nonatomic) BOOL alwaysBounceVertical; // 指定用戶手指離開屏幕后滑動(dòng)減速的比率,默認(rèn)為UIScrollViewDecelerationRateNormal(慢慢停止),其余可選項(xiàng)為UIScrollViewDecelerationRateFast(快速停止) @property(nonatomic) CGFloat decelerationRate; // 將指定區(qū)域滑動(dòng)到剛好可見處(即距離邊緣最近處) - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;
指示器相關(guān)
// 指示器樣式,默認(rèn)為UIScrollViewIndicatorStyleDefault(黑內(nèi)容白邊框,適用于任何背景),其余可選項(xiàng)為UIScrollViewIndicatorStyleBlack(全黑)和UIScrollViewIndicatorStyleWhite(全白) @property(nonatomic) UIScrollViewIndicatorStyle indicatorStyle; // 為指示器周圍增加可滾動(dòng)區(qū)域,默認(rèn)為UIEdgeInsetsZero @property(nonatomic) UIEdgeInsets scrollIndicatorInsets; // 是否在滑動(dòng)時(shí)指示器可見,默認(rèn)為YES @property(nonatomic) BOOL showsHorizontalScrollIndicator; @property(nonatomic) BOOL showsVerticalScrollIndicator; // 閃一下指示器(注: 建議在scrollView展示給用戶時(shí)調(diào)用一下,以提醒用戶該處可滑動(dòng)) - (void)flashScrollIndicators;
事件相關(guān)
UIScrollView處理觸摸事件原理
當(dāng)用戶在UIScrollView的一個(gè)子視圖上按下時(shí),UIScrollView并不知道用戶是想要滑動(dòng)內(nèi)容視圖還是點(diǎn)擊對(duì)應(yīng)子視圖,所以在按下的一瞬間,事件UIEvent從UIApplication傳遞到UIScrollView后,其會(huì)先將該事件攔截而不會(huì)立即傳遞給對(duì)應(yīng)的子視圖,同時(shí)開始一個(gè)150ms的倒計(jì)時(shí),并監(jiān)聽用戶接下來的行為
1、當(dāng)?shù)褂?jì)時(shí)結(jié)束前,如果用戶的手指發(fā)生了移動(dòng),則直接滾動(dòng)內(nèi)容視圖,不會(huì)將該事件傳遞給對(duì)應(yīng)的子視圖;
2、當(dāng)?shù)褂?jì)時(shí)結(jié)束時(shí),如果用戶的手指位置沒有改變,則調(diào)用自身的-touchesShouldBegin:withEvent:inContentView:
方法詢問是否將事件傳遞給對(duì)應(yīng)的子視圖(如果返回NO,則該事件不會(huì)傳遞給對(duì)應(yīng)的子視圖,如果返回YES,則該事件會(huì)傳遞給對(duì)應(yīng)的子視圖,默認(rèn)為YES)
3、當(dāng)事件被傳遞給子視圖后,如果手指位置又發(fā)生了移動(dòng),則調(diào)用自身的-touchesShouldCancelInContentView:
方法詢問是否取消已經(jīng)傳遞給子視圖的事件
// 返回是否用戶已經(jīng)觸碰了內(nèi)容視圖準(zhǔn)備進(jìn)行滑動(dòng)(注: 該值被設(shè)置為YES的時(shí)候可能用戶只是觸碰了內(nèi)容視圖,但是并沒有開始進(jìn)行滑動(dòng)) @property(nonatomic,readonly,getter=isTracking) BOOL tracking; // 返回是否用戶已經(jīng)開始滑動(dòng)內(nèi)容視圖(注: 該值被設(shè)置為YES之前可能需要先滑動(dòng)一段時(shí)間或距離) @property(nonatomic,readonly,getter=isDragging) BOOL dragging; // 返回是否處于減速狀態(tài)(即手指已經(jīng)離開屏幕,但scrollView仍然處于滑動(dòng)中) @property(nonatomic,readonly,getter=isDecelerating) BOOL decelerating; // 是否延遲事件傳遞,默認(rèn)為YES,如果設(shè)置為NO,scrollView會(huì)立即調(diào)用-touchesShouldBegin:withEvent:inContentView:方法以進(jìn)行下一步操作 @property(nonatomic) BOOL delaysContentTouches; // 是否可以取消內(nèi)容視圖被觸摸,默認(rèn)為YES,如果設(shè)置為NO,則一旦開始跟蹤事件,即使手指進(jìn)行移動(dòng)也不會(huì)取消已經(jīng)傳遞給子視圖的事件 @property(nonatomic) BOOL canCancelContentTouches; // 在UIScrollView的子類中重寫該方法,用于返回是否將事件傳遞給對(duì)應(yīng)的子視圖,默認(rèn)返回YES,如果返回NO,該事件不會(huì)傳遞給對(duì)應(yīng)的子視圖 - (BOOL)touchesShouldBegin:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view; // 在UIScrollView的子類中重寫該方法,用于返回是否取消已經(jīng)傳遞給子視圖的事件,默認(rèn)當(dāng)子視圖是UIControl時(shí)返回NO,否則返回YES(注: 該方法被調(diào)用的前提是canCancelContentTouches = YES) - (BOOL)touchesShouldCancelInContentView:(UIView *)view;
縮放相關(guān)
當(dāng)用戶使用兩個(gè)手指進(jìn)行縮放操作時(shí),我們調(diào)整內(nèi)容視圖的偏移量和縮放比例(注: 用戶兩個(gè)手指操作結(jié)束后,有可能仍然有一個(gè)手指在操作,這時(shí)不會(huì)將事件傳遞給子視圖)
// 最小縮放比例,默認(rèn)為1.0 @property(nonatomic) CGFloat minimumZoomScale; // 最大縮放比例,默認(rèn)為1.0(必須大于minimumZoomScale才能正常工作) @property(nonatomic) CGFloat maximumZoomScale; // 縮放比例,默認(rèn)為1.0 @property(nonatomic) CGFloat zoomScale; // 設(shè)置縮放比例 - (void)setZoomScale:(CGFloat)scale animated:(BOOL)animated; // 縮放到指定區(qū)域 - (void)zoomToRect:(CGRect)rect animated:(BOOL)animated; // 是否允許觸底反彈,默認(rèn)為YES @property(nonatomic) BOOL bouncesZoom; // 返回是否正在縮放 @property(nonatomic,readonly,getter=isZooming) BOOL zooming; // 返回是否正在觸底反彈 @property(nonatomic,readonly,getter=isZoomBouncing) BOOL zoomBouncing;
鍵盤相關(guān)
// 隱藏鍵盤模式,默認(rèn)為UIScrollViewKeyboardDismissModeNone(不隱藏鍵盤),其余可選項(xiàng)為UIScrollViewKeyboardDismissModeOnDrag(當(dāng)拖拽scrollView時(shí)隱藏鍵盤)和UIScrollViewKeyboardDismissModeInteractive(當(dāng)拖拽鍵盤上方時(shí)隱藏鍵盤) @property(nonatomic) UIScrollViewKeyboardDismissMode keyboardDismissMode;
代理
滑動(dòng)相關(guān)
// 當(dāng)scrollView的contentOffset發(fā)生變化時(shí)調(diào)用 - (void)scrollViewDidScroll:(UIScrollView *)scrollView; // 將要開始拖拽時(shí)調(diào)用(注: 該方法可能需要先滑動(dòng)一段時(shí)間或距離才會(huì)被調(diào)用) - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView; // 當(dāng)用戶停止拖拽時(shí)調(diào)用(注: 應(yīng)用程序可以通過修改targetContentOffset參數(shù)的值來調(diào)整內(nèi)容視圖content view停止的位置) - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset; // 當(dāng)用戶停止拖拽時(shí)調(diào)用(注: 如果內(nèi)容視圖content view在停止拖拽后繼續(xù)移動(dòng),則decelerate參數(shù)為YES) - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; // 將要開始減速時(shí)調(diào)用(僅當(dāng)停止拖拽后繼續(xù)移動(dòng)時(shí)才會(huì)被調(diào)用) - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView; // 已經(jīng)結(jié)束減速時(shí)調(diào)用(僅當(dāng)停止拖拽后繼續(xù)移動(dòng)時(shí)才會(huì)被調(diào)用) - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; // 返回是否允許點(diǎn)擊狀態(tài)欄讓scrollView滑動(dòng)到頂部,如果未實(shí)現(xiàn)該方法,則默認(rèn)為YES(僅當(dāng)scrollsToTop屬性為YES時(shí)才調(diào)用) - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView; // 當(dāng)scrollView已經(jīng)滑動(dòng)到頂部時(shí)調(diào)用(僅當(dāng)點(diǎn)擊狀態(tài)欄讓scrollView滑動(dòng)到頂部才調(diào)用) - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView; // 當(dāng)-setContentOffset:animated:/-scrollRectVisible:animated:方法動(dòng)畫結(jié)束時(shí)調(diào)用(僅當(dāng)animated設(shè)置為YES時(shí)才調(diào)用) - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;
縮放相關(guān)
// 當(dāng)縮放比例更改時(shí)調(diào)用 - (void)scrollViewDidZoom:(UIScrollView *)scrollView; // 參與縮放的子視圖 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView; // 將要開始縮放時(shí)調(diào)用 - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view; // 已經(jīng)結(jié)束縮放時(shí)調(diào)用 - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale;
常見需求原理解析
導(dǎo)航欄半透明效果
原理解析:
默認(rèn)情況下,在有UINavigationBar存在時(shí),系統(tǒng)為了防止UIScrollView被遮擋,其contentInset和scrollIndicatorInsets屬性都會(huì)被設(shè)置為UIEdgeInsetsMake(64, 0, 0, 0);
在有UITabBar存在時(shí),系統(tǒng)為了防止UIScrollView被遮擋,其contentInset和scrollIndicatorInsets屬性都會(huì)被設(shè)置為UIEdgeInsetsMake(0, 0, 49, 0)
因此,為了使用此種半透明效果,可以直接將UIScrollView的frame設(shè)置為整個(gè)屏幕的大小
注1: 系統(tǒng)只在UIScrollView是控制器視圖的第0個(gè)子視圖時(shí)才會(huì)自動(dòng)修改contentInset和scrollIndicatorInsets屬性
注2: 如果不想讓系統(tǒng)自動(dòng)修改contentInset和scrollIndicatorInsets屬性,可以設(shè)置self.automaticallyAdjustsScrollViewInsets = NO;
控件懸停
原理解析:
方式一: 在懸停位置放置一個(gè)與待懸??丶嗤目丶?通過-scrollViewDidScroll:
代理方法跟蹤contentOffset的的變化,當(dāng)不滿足懸停條件時(shí),將該控件hidden屬性設(shè)置為YES;當(dāng)滿足懸停條件時(shí),將該控件hidden屬性設(shè)置為NO
方式二: 通過-scrollViewDidScroll:
代理方法跟蹤contentOffset的的變化,當(dāng)不滿足懸停條件時(shí),待懸??丶儆赨IScrollView的子視圖,當(dāng)滿足懸停條件時(shí),待懸停控件屬于UIScrollView的父視圖的子視圖
// 以"方式二"為例 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView.contentOffset.y >= 100) { CGRect rect = label.frame; rect.origin.y = 0; label.frame = rect; [self.view addSubview:label]; } else { CGRect rect = label.frame; rect.origin.y = 100; label.frame = rect; [scrollView addSubview:label]; } }
下拉頭部圖片放大
原理解析:
通過-scrollViewDidScroll:
代理方法跟蹤contentOffset的的變化,根據(jù)contentOffset動(dòng)態(tài)設(shè)置圖片的縮放比例
// 以"動(dòng)態(tài)修改圖片縮放比例于1倍和2倍之間"為例 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat scale = 1 - (scrollView.contentOffset.y / 100); scale = (scale >= 1) ? scale : 1; scale = (scale <= 2) ? scale : 2; imageView.transform = CGAffineTransformMakeScale(scale, scale); }
圖片無限輪播
原理解析:
在已知圖片數(shù)組有N個(gè)元素前提下,在UIScrollView中創(chuàng)建N+2個(gè)UIImageView,其中第1個(gè)至第N個(gè)圖片為真實(shí)內(nèi)容,第0個(gè)與第N個(gè)一樣,第N+1個(gè)與第1個(gè)一樣,通過-scrollViewDidScroll:
代理方法跟蹤contentOffset的的變化,在滑動(dòng)到首尾兩個(gè)圖片處直接設(shè)置contentOffset到真實(shí)圖片處即可
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)各位iOS開發(fā)者們能有所幫助,如果有疑問大家可以留言交流。
相關(guān)文章
IOS UITableView和UITableViewCell的幾種樣式詳細(xì)介紹
這篇文章主要介紹了IOS UITableView和UITableViewCell的幾種樣式詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2016-12-12iOS安全防護(hù)系列之重簽名防護(hù)與sysctl反調(diào)試詳解
這篇文章主要給大家介紹了關(guān)于iOS安全防護(hù)系列之重簽名防護(hù)與sysctl反調(diào)試的相關(guān)資料,文中通過示例代碼以及圖文介紹的非常詳細(xì),對(duì)各位iOS開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07iOS仿小紅書呼吸燈動(dòng)畫(核心動(dòng)畫和定時(shí)器)兩種方式實(shí)現(xiàn)
本篇文章主要介紹了iOS仿小紅書呼吸燈動(dòng)畫(核心動(dòng)畫和定時(shí)器)兩種方式實(shí)現(xiàn),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04iOS錄屏和截屏監(jiān)聽的實(shí)現(xiàn)代碼
本篇文章主要介紹了iOS錄屏和截屏監(jiān)聽的實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05上傳IPA出現(xiàn)的錯(cuò)誤提示“application loader“上傳出錯(cuò)解決方法
這篇文章主要介紹了上傳IPA出現(xiàn)的錯(cuò)誤提示“application loader“上傳出錯(cuò)解決方法的相關(guān)資料,需要的朋友可以參考下2017-06-06IOS 調(diào)整內(nèi)存中的圖片大小實(shí)例詳解
這篇文章主要介紹了IOS 調(diào)整內(nèi)存中的圖片大小實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-0412個(gè)iOS技術(shù)面試題及答案總結(jié)
這篇文章給大家總結(jié)了在iOS面試的時(shí)候可能會(huì)遇到的12個(gè)技術(shù)面試題,以及這些面試題但答案,這些答案只是給大家一些參考,大家可以再結(jié)合自己理解進(jìn)行回答,有需要的朋友們下面來一起看看吧。2016-09-09