前言:由于之前很早寫的關(guān)于【iOS 關(guān)于UIScrollView的幾點(diǎn)總結(jié)】,是從自己的markdown筆記直接拷貝過(guò)來(lái)后也沒(méi)有整理,所以在閱讀上顯得有點(diǎn)亂, 今天花時(shí)間重新整理排版了下,方便閱讀。還請(qǐng)見(jiàn)諒這么久才重新整理。
1、什么是
UIScrollView?
- 當(dāng)手機(jī)屏幕需要展示的內(nèi)容較多超出一個(gè)屏幕時(shí),用戶可以通過(guò)滾動(dòng)手勢(shì)來(lái)查看屏幕以外的內(nèi)容。
- 普通的
UIView不具備滾動(dòng)的功能,UIScrollView是一個(gè)能夠滾動(dòng)的視圖控件,可以用來(lái)展示大量的內(nèi)容,并且可以通過(guò)滾動(dòng)查看所有的內(nèi)容。
2、
UIScrollView的常見(jiàn)屬性
-
UIScrollView滾動(dòng)的位置
- 內(nèi)容左上角與
ScrollView左上角的間距值
@property (nonatomic) CGPoint contentOffset;
-
UIScrollView內(nèi)容的尺寸, 滾動(dòng)范圍
@property (nonatomic) CGSize contentSize;
- 在
UIScrollView的4周增加額外的滾動(dòng)區(qū)域,一般用來(lái)避免ScrollView的內(nèi)容被其它控件擋住
@property (nonatomic) UIEdgeInsets contentInset;
3、
UIScrollView各尺寸
4、
UIScrollView的其他屬性
- 回彈效果
@property (nonatomic) BOOL bounces;
// 取消回彈效果
self.scrollView.bounces = NO;
- 是否能滾動(dòng)
@property (nonatomic, getter = isScrollEnabled) BOOL scrollEnabled;
- 是否顯示水平滾動(dòng)條
@property (nonatomic) BOOL showsHorizontalScrollIndicator;
- 是否顯示垂直滾動(dòng)條
@property (nonatomic) BOOL showsVerticalScrollIndicator;
5、
UIScrollView的基本使用
設(shè)置
UIScrollView的contentSize屬性,告訴UIScrollView所有內(nèi)容的尺寸,也就是告訴它滾動(dòng)的范圍-
UIScrollView使用步驟- 創(chuàng)建
UIScrollView; - 將需要展示的內(nèi)容添加到
UIScrollView中; - 設(shè)置
UIScrollView的滾動(dòng)范圍(contentSize)。
- 創(chuàng)建
注意:如果想讓
UIScrollView進(jìn)行滾動(dòng),必須設(shè)置可以滾動(dòng)的范圍,必須設(shè)置可以滾動(dòng)的范圍
- 一個(gè)控件沒(méi)有設(shè)置
frame,默認(rèn)x/y都是0
6、
ScrollView不能滾動(dòng)的幾種情況
-
沒(méi)有設(shè)置
contentSizescrollEnabled屬性 =NO; // 代表控件不可用userInteractionEnabled屬性 =NO; // 代表控件不能和用戶交互
7、如何去掉滾動(dòng)條
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
-
注意:滾動(dòng)條也是 scrollValue 的子控件的一部分滾動(dòng)條可能在子控件的前面,也可能在子控件的后面
正是因?yàn)檫@個(gè)原因,在開(kāi)發(fā)中不推薦使用
subviews獲取子控件的方式
- 當(dāng)沒(méi)有設(shè)置
contentSize情況下,滾動(dòng)條在其它子控件的前面打印,當(dāng)設(shè)置了contentSize情況下,滾動(dòng)條在其它子控件后面打印,這說(shuō)明了滾動(dòng)條的位置是不確定的。
- 設(shè)置滾動(dòng)條的樣式
// default is UIScrollViewIndicatorStyleDefault
@property (nonatomic) UIScrollViewIndicatorStyle indicatorStyle;
- 默認(rèn)情況下UIScrollView有一個(gè)回彈效果
- 只要設(shè)置了contentSize就有回彈效果
// 回彈效果
// default YES. if YES, bounces past edge of content and back again
@property (nonatomic) BOOL bounces;
-
默認(rèn)如果不設(shè)置
contentSize,scrollView是沒(méi)有回彈效果的,可是如果設(shè)置了self.scrollView.alwaysbounceVertical = YES & self.scrollView.alwaysBounceHorizontal = YES的情況下,水平和垂直方向就都有了回彈效果- 一般應(yīng)用于下拉刷新功能
- 設(shè)置邊距
- contentInset(額外增加的邊距)
@property(nonatomic) UIEdgeInsets contentInset; // default UIEdgeInsetsZero. add additional scroll area around content
-
設(shè)置內(nèi)容偏移位
-
contentOffset(移動(dòng)的位置是一個(gè)臨時(shí)的位置,只要輕輕拖拽一下就會(huì)回到默認(rèn)的位置)
-
- 計(jì)算公式:永遠(yuǎn)都是
控件的左上角 - 內(nèi)容的左上角 = 規(guī)定的值
// animate at constant velocity to new offset
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;
8、UIScrollView代理
- 如何監(jiān)聽(tīng)一個(gè)控件的變化/狀態(tài)
- 首先需要查看該控件的頭文件,看它繼承于誰(shuí)
如果繼承于UIControl,那么就可以通過(guò)addTarget來(lái)監(jiān)聽(tīng)如果繼承于UIView,那么就必須通過(guò)代理來(lái)監(jiān)聽(tīng)
- 代理作用:
- 當(dāng)
A對(duì)象想監(jiān)聽(tīng)B對(duì)象的變化,那么可以讓A成為B的代理 - 當(dāng)
B對(duì)象發(fā)生一些變化想通知A對(duì)象,那么可以讓A成為B的代理 -
self寫在對(duì)象方法中就是當(dāng)前對(duì)象的實(shí)例對(duì)象
- 代理協(xié)議的規(guī)律:
- 定義代理都使用
id,這樣以后就任意對(duì)象都能成為代理(學(xué)官方) - 以控件的類名開(kāi)頭,后面加上
delegate - 代理協(xié)議可以寫在
interface()后面,也可以寫在類擴(kuò)展后面,都是可以的
- 代理協(xié)議中的方法名的規(guī)律:
- 一般以控件名稱去掉類前綴開(kāi)頭
- 代理協(xié)議中的方法參數(shù)的規(guī)律:
誰(shuí)觸發(fā)事件,就將誰(shuí)傳遞進(jìn)來(lái)
- 如何監(jiān)聽(tīng)
UIScrollView的變化
成為UIScrollView的代理遵守UIScrollView的協(xié)議實(shí)現(xiàn)UIScrollView協(xié)議中的方法
- 只要成為了
UIScrollView的代理,遵守代理協(xié)議,實(shí)現(xiàn)協(xié)議中的方法,當(dāng)UIScrollView放生一些變化的時(shí)候,系統(tǒng)就會(huì)自動(dòng)調(diào)用這些代理方法
-
scrollViewDidScroll:方法只要UIScrollView滾動(dòng)了,系統(tǒng)就會(huì)自動(dòng)調(diào)用
// 只要UIScrollView滾動(dòng)就會(huì)調(diào)用
// 系統(tǒng)會(huì)自動(dòng)調(diào)用這些方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView; // any offset changes
// 只要用戶準(zhǔn)備開(kāi)始拖拽就會(huì)調(diào)用
// called on start of dragging (may require some time and or distance to move)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
// 用戶停止拖拽(已經(jīng)松手)
// 但是并不意味著UIScrollView已經(jīng)停止?jié)L動(dòng)了,每次調(diào)用此方法時(shí),系統(tǒng)都會(huì)傳入一個(gè)當(dāng)前是否有慣性的參數(shù)(decelerate)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
// UIScrollView停止減速
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; // called when scroll view grinds to a halt
- 注意:
-
如果想在
UIScrollView停止?jié)L動(dòng)之后做一些操作,有以下兩種情況:- 沒(méi)有慣性:只會(huì)調(diào)用停止拖拽的方法,不會(huì)調(diào)用停止減速的方法
- 有慣性:既會(huì)調(diào)用停止拖拽的方法,也會(huì)調(diào)用停止減速的方法
-
所以:以后要判斷UIScrollView是否停止?jié)L動(dòng),需要同時(shí)重寫兩個(gè)方法:
- scrollViewDidEndDragging
- scrollViewDidEndDecelerating
// 在開(kāi)發(fā)中如果需要監(jiān)聽(tīng)scrollView滾動(dòng)是否停止可以這樣寫
- (void)scrollViewDidEndDragging:(nonnull UISrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (decelerate == NO) {
[self scrollViewDidEndDecelerating:scrolView];
} else {
}
}
- (void)scrollViewDidEndDecelerating:(nonnull UIScrollView *)scrollView
{
// 在這里面寫scrollView停止時(shí)需要做的事情
NSLog(@"UIScrollView停止?jié)L動(dòng)了");
}
- 為什么代理要用
weak
- 任何對(duì)象都能成為代理,只要兩者之間遵守了代理協(xié)議即可
原因:為了防止循環(huán)引用- 控制器-強(qiáng)引用 -> 控制器的
View-強(qiáng)引用 ->subViews數(shù)組-強(qiáng)引用 ->UIScrollView-弱引用 -> 控制器 -
如果只有一個(gè)控制器的情況,程序一啟動(dòng)就創(chuàng)建的這個(gè)控制器是不會(huì)被釋放的(如果它被釋放,它所執(zhí)行的邏輯肯定不能被執(zhí)行 ) - 只要數(shù)組中保存了對(duì)象,這個(gè)數(shù)組就會(huì)用強(qiáng)指針指向了這個(gè)對(duì)象
strong (用于對(duì)象, 強(qiáng)指針, 強(qiáng)引用)weak(用于對(duì)象, 一般應(yīng)用于控件/代理)copy(用于對(duì)象, 字符串, 主要為了防止外界修改內(nèi)部的屬性的值)assign(用于基本數(shù)據(jù)類型,int/float/double...)
9、
UIScrollView縮放
- 要想縮放,除了告訴
UIScrollView要縮放哪一個(gè)控件以外,還要告訴UIScrollView最小能縮多小,最大能放多大
- 因?yàn)樗械淖涌丶际俏覀兲砑舆M(jìn)去的,所以要縮放哪一個(gè)我們最清楚
- 只要讓控制器成為
UIScrollView的代理,當(dāng)UIScrollView不清楚要縮放哪一個(gè)控件的時(shí)候,UIScrollView就會(huì)調(diào)用它的代理方法,問(wèn)問(wèn)代理到底要縮放哪一個(gè)
self.sc.maximumZoomScale = 2.0;
self.sc.minimumZoomScale = 0.5;
- 縮放圖片分為兩步
- 成為代理,通過(guò)代理方法告訴
UIScrollView要縮放哪一個(gè)子控件 - 設(shè)置子控件和最小的縮放比
- 想要縮放,必須明確告訴
UIScrollView要縮放哪一個(gè)控件,因?yàn)?UIScrollView中可能有很多子控件
// 代理方法
// 大部分代理方法是由控件名開(kāi)頭,小部分不是
// 在此方法中告訴UIScrollView要縮放哪一個(gè)控件
- (UIView *)viewForZoomingInScrollView:(nonnull UISCrollView *)scrollView {
return 需要縮放的圖片
}
// 縮放的過(guò)程中調(diào)用
- (void)scrlooViewDidZoom:(nonnull UIScrollView *)scrolView {
}
// 縮放結(jié)束時(shí)調(diào)用
- (void)scrollViewDidEndZooming:(nonnull UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale {
}
10、
UIScrollView
- 一個(gè)控件如果沒(méi)有設(shè)置
frame,默認(rèn)x/y就是0 - 如果想讓
UIScrollView進(jìn)行滾動(dòng),必須設(shè)置可以滾動(dòng)的范圍
- 將需要展示的內(nèi)容添加到
UIScrollView中 - 設(shè)置
UIScrollView的contentSize屬性,設(shè)置滾動(dòng)范圍
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width + 100, self.scrollView.frame.size.height + 100);
- 注意:
scrollView不能滾動(dòng)的幾種情況
- 沒(méi)有設(shè)置contentSize
-
scrollEnabled屬性 =NO(代表控件是否可用) -
userINteractionEnabled屬性 =NO(代表控件不能和用戶交互,不能響應(yīng)用戶操作)
11、
UIScrollView使用步驟
- 創(chuàng)建
UIScrollView - 將需要展示內(nèi)容添加到
UISCrollView中 - 設(shè)置
UISCrollView的滾動(dòng)范圍(contentSize)
12、
UIScrollView圖片輪播器
-
pagingEnabled實(shí)現(xiàn)分頁(yè)的本質(zhì),是按照UIScrollView的寬度或者高度來(lái)分頁(yè)的.