iOS 關(guān)于UIScrollView的幾點(diǎn)總結(jié)

- 什么是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)容

---

#### UIScrollView的常見(jiàn)屬性

- UIScrollView滾動(dòng)的位置

+ 內(nèi)容左上角與scrollView左上角的間距值

```objc

@property (nonatomic) CGPoint contentOffset;

```

- UIScrollView內(nèi)容的尺寸,滾動(dòng)范圍

```objc

@property (nonatomic) CGSize contentSize;

```

- 在UIScrollView的4周增加額外的滾動(dòng)區(qū)域,一般用來(lái)避免scrollView的內(nèi)容被其它控件擋住

```objc

@property (nonatomic) UIEdgeInsets contentInset;

```

- UIScrollView各尺寸


---

#### UIScrollView的其他屬性

- 回彈效果

```objc

@property (nonatomic) BOOL bounces;

// 取消回彈效果

self.scrollView.bounces = NO;

```

- 是否能滾動(dòng)

```objc

@property (nonatomic, getter = isScrollEnabled) BOOL scrollEnabled;

```

- 是否顯示水平滾動(dòng)條

```objc

@property (nonatomic) BOOL showsHorizontalScrollIndicator;

```

- 是否顯示垂直滾動(dòng)條

```objc

@property (nonatomic) BOOL showsVerticalScrollIndicator;

```

---

#### UIScrollView的基本使用

- 設(shè)置UIScrollView的contentSize屬性,告訴UIScrollView所有內(nèi)容的尺寸,也就是告訴它滾動(dòng)的范圍

- **`UIScrollView使用步驟`**

+ **`1.創(chuàng)建UIScrollView`-**

+ **`2.將需要展示的內(nèi)容添加到UIScrollView中`**

+ **`3.設(shè)置UIScrollView的滾動(dòng)范圍(contentSize)`**

- 注意:如果想讓UIScrollView進(jìn)行滾動(dòng),必須設(shè)置可以滾動(dòng)的范圍,必須設(shè)置可以滾動(dòng)的范圍

+ 一個(gè)控件沒(méi)有設(shè)置frame,默認(rèn)x/y都是0

- `scrollView不能滾動(dòng)的幾種情況`

+ 沒(méi)有設(shè)置contentSize

+ scrollEnabled屬性 = NO; // 代表控件不可用

+ userInteractionEnabled屬性 = NO; // 代表控件不能和用戶交互

- 如何去掉滾動(dòng)條

```objc

self.scrollView.showsHorizontalScrollIndicator = NO;

self.scrollView.showsVerticalScrollIndicator = NO;

```

- `注意:滾動(dòng)條也是scrollValue的子控件的一部分`

+ `滾動(dòng)條可能在子控件的前面,也可能在子控件的后面`

+ 正是因?yàn)檫@個(gè)原因,在開發(fā)中不推薦使用subviews獲取子控件的方式

* 當(dāng)沒(méi)有設(shè)置contentSize情況下,滾動(dòng)條在其它子控件的前面打印,當(dāng)設(shè)置了contentSize情況下,滾動(dòng)條在其它子控件后面打印,`這說(shuō)明了滾動(dòng)條的位置是不確定的`

- 設(shè)置滾動(dòng)條的樣式

```objc

@property(nonatomic)? ? ? ? UIScrollViewIndicatorStyle? indicatorStyle;? ? ? ? ? ? ? ? // default is UIScrollViewIndicatorStyleDefault

```

- 默認(rèn)情況下UIScrollView有一個(gè)回彈效果

+ 只要設(shè)置了contentSize就有回彈效果

```objc

// 回彈效果

@property(nonatomic)? ? ? ? BOOL? ? ? ? ? ? ? ? ? ? ? ? bounces;? ? ? ? ? ? ? ? ? ? ? ? // default YES. if YES, bounces past edge of content and back again

```

- 默認(rèn)如果不設(shè)置contentSize,scrollView是沒(méi)有回彈效果的,可是如果設(shè)置了`self.scrollView.alwaysbounceVertical = YES & self.scrollView.alwaysBounceHorizontal = YES `的情況下,水平和垂直方向就都有了回彈效果

+ 一般應(yīng)用于下拉刷新功能

- 設(shè)置邊距

+ contentInset(額外增加的邊距)

```objc

@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ī)定的值`

```objc

- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated;? // animate at constant velocity to new offset

```

---

#### UIScrollView代理

- 如何監(jiān)聽一個(gè)控件的變化/狀態(tài)

+ 首先需要查看該控件的頭文件,看它繼承于誰(shuí)

* `如果繼承于UIControl,那么就可以通過(guò)addTarget來(lái)監(jiān)聽`

* `如果繼承于UIView,那么就必須通過(guò)代理來(lái)監(jiān)聽`

- 代理作用:

+ 當(dāng)A對(duì)象想監(jiān)聽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é)官方)

+ 以控件的類名開頭,后面加上delegate

+ 代理協(xié)議可以寫在interface()后面,也可以寫在類擴(kuò)展后面,都是可以的

- 代理協(xié)議中的方法名的規(guī)律:

+ 一般以控件名稱去掉類前綴開頭

- 代理協(xié)議中的方法參數(shù)的規(guī)律:

+ `誰(shuí)觸發(fā)事件,就將誰(shuí)傳遞進(jìn)來(lái)`

- `如何監(jiān)聽UIScrollView的變化`

+ `1.成為UIScrollView的代理`

+ `2.遵守UIScrollView的協(xié)議`

+ `3.實(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)用

```objc

// 只要UIScrollView滾動(dòng)就會(huì)調(diào)用

// 系統(tǒng)會(huì)自動(dòng)調(diào)用這些方法

- (void)scrollViewDidScroll:(UIScrollView *)scrollView; // any offset changes

// 只要用戶準(zhǔn)備開始拖拽就會(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

```objc

// 在開發(fā)中如果需要監(jiān)聽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...)`**

---

#### 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è)

```objc

self.sc.maximumZoomScale = 2.0;

self.sc.minimumZoomScale = 0.5;

```

- 縮放圖片分為兩步

+ 成為代理,通過(guò)代理方法告訴UIScrollView要縮放哪一個(gè)子控件

+ 設(shè)置子控件和最小的縮放比

- 想要縮放,必須明確告訴UIScrollView要縮放哪一個(gè)控件,因?yàn)閁IScrollView中可能有很多子控件

```objc

// 代理方法

// 大部分代理方法是由控件名開頭,小部分不是

// 在此方法中告訴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{

}

```

---

#### 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)范圍

```objc

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)用戶操作)

---

##### UIScrollView使用步驟

- 創(chuàng)建UIScrollView

- 將需要展示內(nèi)容添加到UISCrollView中

- 設(shè)置UISCrollView的滾動(dòng)范圍(contentSize)

#### UIScrollView圖片輪播器

- pagingEnabled實(shí)現(xiàn)分頁(yè)的本質(zhì),是按照UIScrollView的寬度或者高度來(lái)分頁(yè)的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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