引文:
照片瀏覽滑動效果UIScrollView和UIPageControl組合 -- tada
使用UIScrollView 結(jié)合 UIImageView 實現(xiàn)圖片循環(huán)滾動?-- 兩個和三個ImgView哪個性能更好?
UIScrollView新手教程? --? 不錯
理解Scroll View? -- 光柵化和組合,原理好文
計算機(jī)圖形渲染的流程? -- ?知識拓展,很通俗
繪制像素到屏幕上? -- ?底層繪圖
ScrollView 與 Autolayout? -- ?一個坑,應(yīng)該先加一個contentView
UIScrollView 實踐經(jīng)驗? -- ?好好領(lǐng)悟
UIScrollView
首先正好說一下 frame 和 bounds的區(qū)別:
contentOffset
巧妙的通過改變scrollView的bounds,每個單獨的子視圖都被移動了。這正是一個scrollView的工作原理。當(dāng)設(shè)置contentOffset時,它改變scrollView.bounds.origin。(子視圖的frame是相對于父視圖bounds的布局)
contentSize
contentSize > bounds,可以滾動視圖

contentOffset就等同于bounds.origin
contentInsets
contentInset屬性可以改變contentOffset的最大值和最小值,這樣便可以滾動出可滾動的區(qū)域。新手小例子中用contentInsets來控制縮小的圖片居中。
UITableView 刷新原理
tableView為了適應(yīng)每個cell,可滾動區(qū)域是通過精心計算的。當(dāng)你滾動經(jīng)過tableView的第一個或最后一個cell邊界時,tableView將contentOffset彈回并復(fù)位,所以cells又一次緊貼scrollView的bounds。所以,必須將?refresh control放在可滾動區(qū)域的上方。這將允許首先contentOffset彈回第一行。
當(dāng)向下拉動出足夠多的區(qū)域時,tableView設(shè)置contentInsets,擴(kuò)大了contentOffset的區(qū)域,refreshControl的區(qū)域就被包含進(jìn)來。刷新完成后,contentInsets恢復(fù)原始值,contentOffset也恢復(fù)。(EGOTableViewPullRefresh實現(xiàn))
小應(yīng)用
當(dāng)鍵盤出現(xiàn)在界面上的時候,擋住了scrollView原本顯示的一部分。通過設(shè)置contentInsets.bottom = 鍵盤的高度,可以暫時擴(kuò)大contentOffset的向下最大可視范圍,從而能拖動看到被鍵盤擋住的那部分。鍵盤消失時,再恢復(fù)contentInsets。
ScrollView && AutoLayout?
對于 UIScrollView 的 subview 來說,它的 leading/trailing/top/bottom space 是相對于 UIScrollView 的 contentSize 而不是 bounds 來確定的,所以當(dāng)你嘗試用 UIScrollView 和它 subview 的 leading/trailing/top/bottom 來互相決定大小的時候,就會出現(xiàn) ? ? ? ? ? ? ? ? ?「Has ambiguous scrollable content width/height」的 warning。
正確的姿勢是用 UIScrollView 外部的 view 或 UIScrollView 本身的 width/height 確定 subview 的尺寸,進(jìn)而確定 contentSize。
因為 UIScrollView 本身的 leading/trailing/top/bottom 變得不好用,所以我習(xí)慣的做法是在 UIScrollView 和它原來的 subviews 之間增加一個 content view。
delegate調(diào)用順序
scrollViewDidScroll:? --? 在任何方式觸發(fā) contentOffset 變化的時候都會被調(diào)用
scrollViewWillBeginDragging:? --? dragging noDecelerating
scrollViewWillEndDragging: withVelocity: targetContentOffset:? --? dragging noDecelerating
scrollViewDidEndDragging: willDecelerate:? --? dragging noDecelerating
scrollViewWillBeginDecelerating:? --? dragging decelerating
scrollViewDidEndDecelerating:? --? noDragging noDecelerating
分頁優(yōu)化
pagingEnabled
缺點蠻多,具體padding還不懂
Snap
最后沒到位,動畫會突然到位,是突兀
targetContentOffset
更平滑,之前計算好,動畫自然
視覺差
通過 scrollViewDidScroll 實時改變另一個scrollView的contentOffSet,和新手教程里的原理類似。
重用
維護(hù)一個重用隊列
當(dāng)元素離開可見范圍時,removeFromSuperview 并加入重用隊列(enqueue)
當(dāng)需要加入新的元素時,先嘗試從重用隊列獲取可重用元素(dequeue)并且從重用隊列移除
如果隊列為空,新建元素
這些一般都在 scrollViewDidScroll: 方法中完成
note that:
當(dāng)重用對象為 view controller 時,記得 addChildViewController
當(dāng) view 或 view controller 被重用但其對應(yīng) model 發(fā)生變化的時候,需要及時清理重用前留下的內(nèi)容
數(shù)據(jù)可以適當(dāng)做緩存,在重用的時候嘗試從緩存中讀取數(shù)據(jù)甚至之前的狀態(tài)(如 table view 的 contentOffset),以得到更好的用戶體驗
當(dāng) on screen 的元素數(shù)量可確定的時候,有時候可以提前 init 這些元素,不會在 scroll 過程中遇到因為 init 開銷帶來的卡頓(尤其是以 view controller 為重用對象的時候)
引文:
觸摸事件:?
touchesBegan:withEvent:
touchesMoved:withEvent:
touchesEnded:withEvent:
touchesCancelled:withEvent: ?-- ?電話導(dǎo)入取消
(1) 單tap下,touches == event.allTouches。 兩指,event.allTouches.count == 2;
(2) 連tap兩下,touches -> touch -> tapCount == 2 ?-- 想到很多連擊游戲,如果可以MS到方法里把tapCnt改個100。

通過實現(xiàn)一個TableView來理解iOS UI編程
(1)UIView中:
initWithFrame:-- ?初始化
layoutSubviews ?-- ?布局 (setNeedsLayout)
CGGeometry.h -- CGRectGetMaxX
(2)首先將編譯選項改為 OC++。
如果頭文件中用 @class 聲明一個類,那么這個類中的對象在被外界訪問的時候就會出現(xiàn) Member access into incomplete type "~~"`
(3)子類化UIScrollView實現(xiàn)對Cell的布局 ?-- ?高度和Y值進(jìn)行布局
(4)Cell的重用 ?-- ?visibleCells(刪除入隊) 和 cacheCells(獲取出隊)
和VC重用思路類似。
在要使用一個Cell的時候我們先去看看tableView中有沒有可以重用的cell,如果有就用這個可以重用的cell,只有在沒有的時候才去創(chuàng)建一個Cell。這就是享元模式。
享元模式可以理解成,當(dāng)細(xì)粒度的對象數(shù)量特別多的時候運行的代價會相當(dāng)大,此時運用共享的技術(shù)來大大降低運行成本。比較突出的表現(xiàn)就是內(nèi)容有效的抑制內(nèi)存抖動的情況發(fā)生,還有控制內(nèi)存增長。它的英文名字是flyweight,讓重量飛起來。
(5)響應(yīng)和處理事件? -- ?addGesture (點擊位置與cellFrame)
(6)接口和數(shù)據(jù)獲取 ?-- ?protocol (數(shù)據(jù)源,點擊事件)
(7)選中態(tài) ?-- ?事件方法判斷,backgroundView展示
UITableView 滾動流程性優(yōu)化? -- ?O(1)
詳細(xì)整理:UITableView優(yōu)化技巧??--? 用到很多不熟悉的方法
UITableView性能優(yōu)化-一次面試后的反思總結(jié)
提升UITableView性能-復(fù)雜頁面的優(yōu)化??-- ?類似
UIScrollView 實踐經(jīng)驗--? 好棒幾個例子,最佳技巧UITableView
如何加強(qiáng) iOS 里的列表滾動時的順暢感?-- ?很多
iOS 保持界面流暢的技巧??-- ?ibib
一次 TableView 性能優(yōu)化經(jīng)歷
10個加速Table Views開發(fā)的Tips
阿崢教你實現(xiàn)UITableView循環(huán)利用
UITableView
1. 快速滑動
當(dāng)用戶手動拖動tableView時,加載cell圖片。
當(dāng)用戶快速滑動的減速過程中, 有緩存就加載,沒緩存不加載cell圖片。
targetContentOffset位置直接設(shè)置加載,滾動到的時候已經(jīng)開始加載。
2. LazyLoad
- fetchDataFromServer ?- AFHTTPRequestOperationManager
- heightForRowAtIndexPath
- setupCell: withIndexPath:? --? SDWebImageDownloader
- loadImageForVisibleCells
- scrollViewDelegate - 3
3. Cell重用機(jī)制
[tableView dequeueReusableCellWithIdentifier:(NSString)identifier ?forIndexPath:(NSIndexPath)indexPath];
(1) Storyboard: 定義Cell的Prototype,并設(shè)置其Reusable Identifier
(2) Xib自定義: [registerNib:(nullable UINib)nib forCellReuseIdentifier:(NSString)identifier];
(3) 代碼自定義:[registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier];
重寫自定義cell的 initWithStyle:withReuseableCellIdentifier: 方法進(jìn)行布局。
自定義cell時,記得將其他內(nèi)容加到self.contentView 上,而不是直接添加到 cell 本身上。
4. 設(shè)計統(tǒng)一規(guī)格的Cell
- ?等高的Cell好設(shè)計
- ?動態(tài)計算高度的Cell也應(yīng)該統(tǒng)一設(shè)計
5. 提前計算并緩存cell的UI尺寸信息
創(chuàng)建ViewModel,計算并儲存Cell的UI尺寸信息
tableView:heightForRowAtIndexPath: --> tableView:cellForRowAtIndexPath
使用了ViewModel來保存UI信息,Cell?高度的計算?和?使用的時機(jī)?需要特別留意。
6. 圓角,陰影,mask
(1) Cell中的view盡可能不要使用透明 -- opaque不透明的話,繪畫的時候就不會去畫下層的視圖。盡量減少cell中子視圖透明化以及做切圓操作,在layer層渲染圖層時會涉及上下文切換以及離屏渲染之類的,系統(tǒng)開銷會很大,特別是在cell視圖很復(fù)雜的時候,由于渲染問題導(dǎo)致的內(nèi)存開銷會讓你的tableview非??D。比如cell中需要設(shè)置頭像圓形直接設(shè)置圓角會很卡,一般用CG把拿到的圖片處理一遍在給cell使用就好了。圓角、陰影之類的全部 bitmap 化,或者放到后臺 draw 好了再拿來用
(2) 用代碼自定義的cell,使用時要做 layer 柵格化處理
(3) 減少子視圖的層級關(guān)系
(4) 圖片載入在后臺進(jìn)程進(jìn)行,滾出可視范圍的載入進(jìn)程cancel掉
(5) 后臺對圖片先進(jìn)行解碼
UIImageView 的載入是惰性的說法,是對的。但是大部分開發(fā)者都沒有正確理解這一點。下面就詳細(xì)解釋一下:
[UIImage imageWithContentOfFile:] 出來的 UIImage 其實并沒有真正把文件解碼到內(nèi)存,而是要等到用的時候(例如去顯示或者去 scale)才會去做這件事情。但問題就在于 UIImageView 試圖去 draw 圖片的時候,它讀文件、渲染也是在主線程里做的,所以你要讀入的圖片如果很大(比如 iPad3 上的 @2x 圖),這一步就很容易會卡一下。這也就是為什么我說圖片要放到后臺進(jìn)程去解碼完之后,在主線程顯示。
iOS中線寬與像素的關(guān)系? -- ?補(bǔ)補(bǔ)補(bǔ)
UITableViewCell
1. UITableViewCell的估算機(jī)制與高度計算
iOS7?
estimatedRowHeight, SectionHeaderHeight, SectionFooterHeight ? ? ? ? ? ? ? ? ? ? iOS7中每個cell的高度會被系統(tǒng)自動緩存起來,不會再重復(fù)計算了
[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; 可以通過約束計算到cell的高度。要求使用者對約束設(shè)置的比較熟練,要保證 contentView 內(nèi)部上下左右所有方向都有約束支撐,設(shè)置不合理的話計算的高度就成了0。
另外需要注意的是, 在iOS7下, 如果布局中有UILabel, 并且行數(shù)大于0時, 需要指定preferredMaxLayoutWidth, 這樣Label才能知道自己什么時候該換行, 然后-systemLayoutSizeFittingSize才能得到正確的高度.
另一種方案就是,給cell的contentView添加一個和tableView寬度相同的寬度約束, 這樣就能在UILabel約束完備的情況下算出UILabel的寬度.(因為contentView寬度的計算需要知道子控件寬度的累加,而UILabel的換行卻依賴著contentView的寬度,不換行就不知道UILabel的高度!)
iOS8
self-sizing cell
2.?制作一個可以滑動操作的 Table View Cell
創(chuàng)建一個自定義 Cell
-- button1? button2 點擊傳遞給delegate去處理? -- 添加一個 Delegate
-- contentView 用于覆蓋,Label用于顯示
為按鈕添加 Action
showDetailWithText: -- presentDetailNav
添加頂層視圖并添加滑動 Action
添加數(shù)據(jù) -- labelText由cell.label托管
手勢識別
-- panRecognizer - panThisCell:
-- panStartPoint 開始點,判斷左右滑動
-- startingRightLayoutConstraintConstant 右約束
-- contentViewLeftConstraint & contentViewRightConstraint
移動這些約束
buttonTotalWidth
- (void)resetConstraintContstantsToZero:(BOOL)animated notifyDelegateDidClose:(BOOL)endEditing
- (void)setConstraintsToShowAllButtons:(BOOL)animated notifyDelegateDidOpen:(BOOL)notifyDelegate
UIGestureRecognizerStateBegan & UIGestureRecognizerStateChanged
Snap!
- (void)updateConstraintsIfNeeded:(BOOL)animated completion:(void(^)(BOOL finished))completion
set & reset
UIGestureRecognizerStateEnded & UIGestureRecognizerStateCancelled
更好地處理 Table View
Gesture沖突 -- shouldRecognizeSimultaneouslyWithGestureRecognizer:
重用cell出現(xiàn)打開 -- prepareForReuse
- (void)cellDidOpen:(UITableViewCell *)cell;
- (void)cellDidClose:(UITableViewCell *)cell;
- (void)openCell;
set & reset + delegate方法
cellsCurrentlyEditing -- 打開添加關(guān)閉移除沒問題,打開cell狀態(tài)滑動tableView,會進(jìn)行重用會調(diào)用cellForRowAtIndexPath,所以檢測是否包含在currentlyEditing數(shù)組中,如果在就
3.?很炫的table view cell切換效果? SvpplyTable
看到簡單函數(shù)內(nèi)部又調(diào)用復(fù)雜函數(shù),現(xiàn)在終于想明白了,是為了對外提供簡介的API,然后復(fù)雜的邏輯在自己內(nèi)部做。我以后也要這么干。
如果多次跳轉(zhuǎn)調(diào)用函數(shù),傳遞參數(shù)名盡量不要變,不然會給閱讀增加負(fù)擔(dān)。
_ivar 比 self.ivar 的一個好處在于調(diào)試時候可以更容易看到值
4. 利用長按手勢移動 Table View Cells? --? 小而美
UICollectionView
UICollectionView Tutorial Part 1: Getting Started
UICollectionView Tutorial Part 2: Reusable Views and Cell Selection
現(xiàn)在,UICollectionViews有了簡單的重排功能? -- 太棒
葉孤城:UICollectionView自定義布局教程——Pinterest
UICollectionView 高級進(jìn)階篇? -- 各種酷炫
自定義 Collection View 布局? -- ?中規(guī)中矩
UICollectionView Custom Layout Tutorial: A Spinning Wheel? -- ?旋轉(zhuǎn)視圖, 改變錨點, 自定義 collection view layout
Vertical? --? from left to right,horizontal? --? from top to bottom
Supplementary views 和 decoration views 必須是UICollectionReusableView的子類。
header && footer
UICollectionViewController,UICollectionView,UICollectionViewCell,UICollectionReuseableView,UICollectionViewLayout,UICollectionViewLayoutAttributes
- (void)prepareLayout? -- ?這個整個布局過程中最重要的方法之一。因為這里可以創(chuàng)建和存儲layout attributes。
- (CGSize)collectionViewContentSize
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
- (UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
動畫:
插入和刪除
initialLayoutAttributesForAppearingItemAtIndexPath:
initialLayoutAttributesForAppearingSupplementaryElementOfKind:atIndexPath:
initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:
finalLayoutAttributesForDisappearingItemAtIndexPath:
finalLayoutAttributesForDisappearingSupplementaryElementOfKind:atIndexPath:
finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:
布局間切換
將一個 collection view 布局動態(tài)的切換到另外一個布局。setCollectionViewLayout:animated:(突然想到那種四角碰撞,同時形變的小例子)
發(fā)現(xiàn)快捷鍵: option + command = 在IB中動態(tài)標(biāo)尺