# Views features ## Bounds and Center #### `inset(by:)` 在特定的 view 插入一個 view ```swift let v1 = UIView(frame:CGRect(113, 111, 132, 194)) //1. v1.backgroundColor = UIColor(red: 1, green: 0.4, blue: 1, alpha: 1) let v2 = UIView(frame:v1.bounds.insetBy(dx: 10, dy: 10)) //2. v2.backgroundColor = UIColor(red: 0.5, green: 1, blue: 0, alpha: 1) self.view.addSubview(v1) v1.addSubview(v2) ``` ![](https://i.imgur.com/OuWaceP.png) 1. 首先製作一個空的 view ,之後用來插入另一個 view 2. 製作 view v2 並在初始化時 `frame` 直接利用 `inset(by)` 傳入 v1 的 `bounds`, 如此一來 dx 和 dy 就是插入後的間距。 `inset(by)`,可以幫你做好需要插入一個置中 `superview` 的 `subview` 可以直接利用 `superview` 的 `bounds` 來當作 subview 的 frame。 v2 的 frame 遵從其 superview v1 的 bound,代表 v1 的 origin x, y 各自加 10 的話,v2 會跑到 v1 的左上角。 在上面的 code 上再加上這兩行: ```swift v1.bounds.origin.x += 10 v1.bounds.origin.y += 10 ``` ![](https://i.imgur.com/x7ymaru.png) 會跑到左上角是因為我們修改了 v1 的 frame ,本來在 v2 的 frame 是靠在 v1 的 bounds (x:10, y:10) 的地方,但因為現在 v1 的 bounds 已經移動到 (x:10, y:10) 的地方, 所以修改後 v2 看起反而是往左上移動了。 - 如果需要置中一個 subview 你可以這樣做: ```swift let v1 = UIView(frame:CGRect(113, 111, 132, 194)) v1.backgroundColor = UIColor(red: 1, green: 0.4, blue: 1, alpha: 1) let v2 = UIView(frame:CGRect(0, 0, 122, 184)) v2.backgroundColor = UIColor(red: 0.5, green: 1, blue: 0, alpha: 1) self.view.addSubview(v1) v1.addSubview(v2) // 幫你置中 v2 如果是 v1 是 subview v2.center = v1.convert(v1.center, from:v1.superview) ``` ![](https://i.imgur.com/ornXSLb.png) ## Transform 一個 view 可以不只是矩形的,他可以變形,變形的依據透過一個 struct `CGAffineTransform` 用來表示一個 3X3 的矩陣,struct 包含 6 個變數,剩餘的 3 個值是常數不變的。 在初始化 `CGAffineTransform` 時,就提供了基本變形的選項,如: rotation, scaling, translation 旋轉,變形,移動。 如以下選轉 v1 的角度: ```swift let v1 = UIView(frame:CGRect(113, 111, 132, 194)) v1.backgroundColor = UIColor(red: 1, green: 0.4, blue: 1, alpha: 1) let v2 = UIView(frame:v1.bounds.insetBy(dx: 10, dy: 10)) v2.backgroundColor = UIColor(red: 0.5, green: 1, blue: 0, alpha: 1) self.view.addSubview(v1) v1.addSubview(v2) v1.transform = CGAffineTransform(rotationAngle: 45 * .pi/180) print(v1.frame) ``` 結果為: ![](https://i.imgur.com/WCOA46H.png) 即使 superview 旋轉了,bounds 也沒有被改變,所以 subview 的位置不會被改變。這件觀念告訴我們,如果預設的 transform 已經被改變,那麼 view 的 frame 不應該再去設定,因為它僅僅代表包圍 view 的範圍。 ## UITraitCollection `traitCollection` 包含了 iOS 裝置的各種特性參數,囊括了`horizontalSizeClass`,`verticalSizeClass`, `displayScale` (螢幕解析度), 及 `userInterfaceIdiom` (顯示 ipad 或 iPhone),在用`traitCollection` 的所有參數之前的類別需要採取 `UITraitEnvironment` protocol. ### Size Class 在 View 裡,我們關心的是 `UIUserInterfaceSizeClass` 他擁有這兩個參數 與`horizontalSizeClass`,`verticalSizeClass`, 而這兩個參數他用一個 enum 來代表 view 目前的兩種 case: - .regular - .compact 你可以透過 XCode 來研究各個裝置的 width 跟 height 的 size class 如下圖: ![](https://i.imgur.com/AEJjjCa.png) 透過切換裝置按鈕可以看出 plus 當橫置時他的 width 是 R(regular) ,height 是 C(compact)跟其他的 iPhone 裝置是不太一樣的。 Size class 在 app 運行的期間,會因為使用者的行為改變而改變,因此便會重送這些訊息到 `traitCollectionDidChange(_:) ` delegate,舊的 trait collection 會被當作參數,而目前的 trait collection 可以經由 `self.traitCollection` 取得。 ### Layout #### Autoresizing Autoresizing 就像是給 subview strut (支柱) 或者 spring (彈簧),strut 是固定的,spring 則是可以移動的,Autoresizing 可以是設定 view 的內部,或者是外部,以及水平或垂直。 - 假設有一個 subview 要建立在 superview 裡且置中,但他會依 superview 去做變形,所以我們會在 subview 裡設定 `.flexibleHeight`, `.flexibleWidth`, subview 外部設定 strut。 - 假設有一個 subview 要建立在 superview 裡且置中,但不會因 superview 變形而變形 ,這時 subview 裡面要設定 sturt。 - 假設有一個確認按鈕要建立在 superview 的右下角,這時 strut 要在 button 的外部右下邊設定, 要在外部的左上邊設定。 組合 autoresizeMask layout: 1. 首先產生三個 view 如下圖: ![](https://i.imgur.com/XVbPR63.png) ```swift let v1 = UIView(frame:CGRect(100, 111, 132, 194)) v1.backgroundColor = UIColor(red: 1, green: 0.4, blue: 1, alpha: 1) let v2 = UIView(frame:CGRect(0, 0, 132, 10)) v2.backgroundColor = UIColor(red: 0.5, green: 1, blue: 0, alpha: 1) let v3 = UIView(frame:CGRect( v1.bounds.width-20, v1.bounds.height-20, 20, 20)) v3.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1) self.view.addSubview(v1) v1.addSubview(v2) v1.addSubview(v3) ``` 上面的 code 中, v1 為綠色也是 v2, v3 的 superview,接下來我們要讓 v2 跟著 superview 延展,而 v3 不動。 透過以下兩條 layout 來固定: ```swift v2.autoresizingMask = .flexibleWidth v3.autoresizingMask = [.flexibleTopMargin, .flexibleLeftMargin] ``` v2 加入了延展邊緣的條件, v3 加入兩個 spring 延展至 superview 的左上邊