最近切實的感覺到了本身在界面這一塊基礎原理的匱乏,所以決定深刻學習瞭解一下Core Animation, 可是在學習Core Animation的開端,不由又懷疑本身,UIWindow是什麼?它的做用你真的明白嗎?爲何要有UIWindow呢,若是沒有的話行不行呢?一系列問題層出不窮,所以我決定在研究學習Core Animation以前去學習學習蘋果的官方文檔View Programming Guide for iOS, 那麼在開始的這一篇我只會去寫一寫我對於UIView的學習,總結,應該還會有一些問題,但願和你們一塊兒交流交流。html
可能在文中會用到不一樣的詞,可是他們是一個含義:
view == view對象 == 視圖對象 == UIView對象
window == window對象 == 視窗對象 == UIWindow對象
(注:UIWindow的基類是UIView)
複製代碼
View
究竟是什麼?View
對象在屏幕上定義了一塊矩形的區域而且處理這個區域內部的事件。在UIKIT
中,每個UIView對象
都有一個CALayer對象
的layer屬性,layer對象
負責視圖內容的繪製,處理視圖動畫相關的事宜。視圖由layer繪製,動畫也由layer處理,那麼UIView對象
作什麼呢?其實UIView對象
能夠理解爲是對layer
的封裝,提供了處理觸摸事件的具體功能以及Core Animation
底層方法的接口。面試
Core Animation
呢?Core Animation
是是iOS和OSX上可用的圖形渲染和動畫基礎結構,用於爲應用的視圖和其餘視覺元素設置動畫。它把大量的繪圖工做交給GPU去加速渲染,因此能夠實現高幀率高流暢度的動畫效果,並不會去負載CPU而使得手機卡頓。數組
Core Animation 並非一個繪圖系統,而是使用硬件去合成和處理視圖內容的基礎框架,而這個基礎框架的核心就是layer對象
,那麼layer
又是如何對視圖內容進行處理的呢?它會將其轉化爲GPU便宜處理的bitmap,而後GPU再去執行相應的操做,大多數APP中layer都是用來管理視圖內容的,可是也能夠去單獨的建立獨立的layer。bash
那麼如今能夠對Core Animation
能夠進行一些底層的瞭解了:markdown
Core Animation是一套包含圖形繪製、投影、動畫的Objective-C類集合,該框架包含在QuartzCore.framework中. app
上圖的OpenGL ES是一個C語言寫的很是底層的圖形處理框架。是個移動設備上繪製2D和3D計算機圖形的標準的開源庫,普遍地被用在遊戲的圖形的繪製上負責直接驅動GPU,效率很高,可是使用起來很複雜。框架
Core Animation的核心就是對於OpenGL ES的抽象,它並不作渲染工做,而是使用OpenGL ES的功能,讓GPU去處理渲染。從上圖的結構能夠知道Core Graphic 的繪製是須要消耗CPU的,而Core Animation渲染消耗的是GPU。Core Animation最繁重的任務是去判斷出哪些layer須要被從新繪製,而OpenGL ES要作的就是將layer合併、顯示在屏幕上。ide
Core Graphic, Core Animation, Core Image是三個不一樣的核心庫,它們之間可能會有交互,可是不存在一個包含的關係。上圖是它們的工做流程圖oop
當你設置一個 layer 的內容爲 CGImageRef 時,Core Animation 會建立一個 OpenGL 紋理,並確保在這個圖層中的位圖被上傳到對應的紋理中。以及當你重寫 -drawInContext 方法時,Core Animation 會請求分配一個紋理,同時確保 Core Graphics 會將你所作的(即你在drawInContext中繪製的東西)放入到紋理的位圖數據中。一個layer的屬性和 CALayer 的子類會影響到 OpenGL 的渲染結果,許多底層的 OpenGL ES 行爲被簡單易懂地封裝到 CALayer 概念中。佈局
好了,走偏了咱們仍是繼續聊一聊UIView吧。
每個父視圖都會維持一個子視圖數組,在數組最後一個子視圖就是最上層的子視圖,若是子視圖重疊了,數組中靠後的子視圖位於上方,父視圖和子視圖的關係會影響子視圖的顯示,在代碼中常見的有兩個場景
//1. 要求子視圖不透明,父視圖透明 layerView.backgroundColor = UIColor.black.withAlphaComponent(0.1) //2. scrollView自動調整子視圖size如何解決? let scrollView = UIScrollView.init(frame: CGRect.init(x: 0, y: 0, width: 100, height: 100)) scrollView.autoresizesSubviews = false 複製代碼
當談及UIView和CALayer的主要區別時,最重要的區別就是UIView是能夠響應事件的,那麼View是如何響應事件的呢?簡單來說分爲兩步:
- 尋找發生觸摸事件的視圖(從上往下)
- 找到事件的第一響應者(從下往上)
當view第一次在屏幕上顯示的時候,系統會繪製它的內容,而後系統會截取內容的快照,而且將快照做爲視圖的可見外觀,若是你永遠不改變視圖的內容,那麼視圖的繪製代碼永遠不會改變。若是更改了視圖的內容,不用直接從新繪製,而是使用setNeedsDisplay
或者setNeedsDisplayInRect
方法是視圖無效。這些方法會告知視圖內容以及改變而且須要在下一次進行重繪。若是須要立馬重繪,那麼須要使用layoutIfNeeded
方法。
有時候只須要可視視圖的一部份能夠被伸縮,這個在設置按鈕背景圖片的場景是很是常見的,那麼如何讓這個常見的需求實現呢?使用resizableImageWithCapInsets:
方法,能夠肯定可縮放的視圖的內容,以下:
var image = UIImage.init(named: "image.png") image = image?.resizableImage(withCapInsets: UIEdgeInsetsMake(10, 10, 10, 10), resizingMode: UIImageResizingMode.stretch) let imageview = UIImageView.init(image: image) 複製代碼
伸縮背景的效果以下:(使四個角不變,中心進行縮放)
視圖能夠實現的動畫效果的屬性以下:
UIKit的座標系以屏幕的左上角爲原點
若是是OpenGL ES或者是Core Graphic的話是以屏幕的左下角爲座標原點的一個笛卡爾座標系那麼window的職責是什麼,爲何要有Window的存在呢?沒有Window行不行呢? 下面試官網的原文
* It contains your application’s visible content. * It plays a key role in the delivery of touch events to your views and other application objects. * It works with your application’s view controllers to facilitate orientation changes. 複製代碼
若是把viewController拿出來看,咱們知道viewController通常對應着相應的應用內部模塊,若是要和其餘的應用交互呢?這個就須要靠Window
了;固然還有一點是屏幕的方向,這個也是經過Window
來控制的!
在大多數時候,咱們只須要在didFinishLaunchingWithOptions:
中初始化window以後就不會去涉及其餘的window操做了,若是使用IB的話,連window的初始化也沒有必要了;可是在實際的代碼過程當中仍然可能會涉及兩個任務
其實吧,分屏是一個很是常見的功能,若是接觸過度屏的話就須要去仔細的研究研究分屏相關的代碼,這一塊也是和UIWindow息息相關的。
在佈局中有一個很討厭的事情,就是明明你的frame都已經設定好了,可是依然在運行的時候就會發生變化,其實不少這種狀況的緣由就是被添加的子視圖的frame會隨着父視圖的frame的變化而發生變化;其二就是有時候子視圖須要保持和父視圖一致的大小變換,或者維持原有的尺寸不變,這個時候就須要視圖的自動化調整佈局了。
父視圖的 autoresizesSubviews
屬性決定全部子視圖是否須要調整。若是屬性設置爲 YES,視圖會使用每一個子視圖的 autoresizingMask
屬性決定子視圖的位置和尺寸。每一個子視圖的尺寸變動會對它們的子視圖觸發一樣的佈局調整。每個子視圖的autoresizingMask
屬性如何決定呢?
UIViewAutoresizingFlexibleHeight
當父視圖高度變動時視圖的高度也變動。若是這個常量沒被包含,視圖的高度將不會變動。UIViewAutoresizingFlexibleWidth
當父視圖寬度變動時視圖的寬度也變動。若是這個常量沒被包含,視圖的寬度將不會變動。UIVIewAutoresizingFlexibleLeftMargin
視圖的左邊緣和父視圖的左邊緣之間的距離根據須要增加或縮短。若是這個常量沒有設置,視圖的左邊緣與父視圖的左邊緣之間的距離保持固定。UIViewAutoresizingFlexibleRightMargin
視圖的右邊緣和父視圖的右邊緣之間的距離根據須要增加或縮短。若是這個常量沒有設置,視圖的右邊緣與父視圖的右邊緣之間的距離保持固定。UIViewAutoresizingFlexibleBottomMargin
視圖的底部邊緣和父視圖的底部邊緣之間的距離根據須要增加或縮短。若是這個常量沒有設置,視圖的底部邊緣與父視圖的底部邊緣之間的距離保持固定。UIViewAutoresizingFlexibleTopMargin
視圖的頂部邊緣和父視圖的頂部邊緣之間的距離根據須要增加或縮短。若是這個常量沒有設置,視圖的頂部邊緣與父視圖的頂部邊緣之間的距離保持固定。在使用code時: initWithFrame: 在使用nib時: initWithCoder: -> awakeFromNib
在實際的操做中,要儘可能少的使用drawRect:方法,若是要使用此方法,明確它的職責:繪製內容。使用的時候要配置環境,繪製內容,儘量快結束繪製。 提升繪製性能的兩個小tips:
這個就很是常見了,大多使用的是UIView自帶的Block動畫,這個就不在細聊了,有一點想提一提,就是普通的動畫只能是從A -> B兩種狀態之間進行切換,若是加上交互的話,動畫就會變得不流暢了,因此Apple在iOS10添加了一個新的特性:UIViewPropertyAnimator ,這個在後面再聊吧。
也不知道爲何寫了這麼多,其實寫的時候,主要仍是不少東西都是有關聯的,一旦深刻其實還會有很是多的東西在裏面,以上是個人學習和一些總結。若是寫的很差,歡迎指出問題,這樣我就能夠慢慢改進了,下一篇,我會用比較短的篇幅聊一聊UIViewController,而後就正式的進入個人Core Animation的學習過程當中了。