UIDynamic是從iOS 7開始引入的一種新技術(shù)吸申,隸屬于UIKit框架可以認(rèn)為是一種物理引擎两嘴,能模擬和仿真現(xiàn)實(shí)生活中的物理重力、彈性碰撞届慈、附著行為徒溪、捕捉行為、推動行為和動力元素等現(xiàn)象金顿。
首先要在stroyboard里添加一個UIView臊泌, 并設(shè)置constraint跟父View邊界相同(點(diǎn)擊Reset to Suggested Constraints), 即充滿屏幕揍拆。
我從這個Demo里總結(jié)了一些實(shí)際編碼中可以用到的技巧渠概, 供大家參數(shù)。
技巧1: 如果需要實(shí)現(xiàn)extension礁凡, 可以新建一個Swift文件高氮, 一個類/枚舉/結(jié)構(gòu)體的所有擴(kuò)展都放在同一個文件里(例如在A文件里擴(kuò)展UIView慧妄,在B文件也擴(kuò)展UIView顷牌, 這個語法不好維護(hù),對同一個數(shù)據(jù)結(jié)構(gòu)的擴(kuò)展要放在一起H汀)窟蓝; 擴(kuò)展在整個程序內(nèi)都有效;示例代碼:
<pre>
extension UIView {
//根據(jù)坐標(biāo)判斷對應(yīng)的UIView
func hitTest(p: CGPoint) -> UIView? {
return hitTest(p, with: nil)
}
}
extension UIBezierPath {
//靜態(tài)函數(shù), 畫直線
class func lineFrom(from: CGPoint, to: CGPoint) -> UIBezierPath {
let path = UIBezierPath()
path.move(to: from)
path.addLine(to: to)
return path
}
}
</pre>
技巧2:得到隨機(jī)數(shù), 在Swift語言里使用arc4random()方法运挫,實(shí)際編碼中建議使用擴(kuò)展語法實(shí)現(xiàn)状共。 示例代碼是CGFloat, 還可以是Int谁帕、Double等等峡继。
<pre>
extension CGFloat {
/**
* 返回范圍內(nèi)的隨機(jī)數(shù)
* @param max, 最大值
*/
static func random(max: Int) -> CGFloat {
return CGFloat(arc4random() % UInt32(max))
}
}
</pre>
技巧3: UIView是所有界面空間的基類, 能添加子UIView(這點(diǎn)跟Andriod的View不同)匈挖; 注意父UIView可以添加子UIView碾牌, 但是需要使用子UIView的方法才能移除(這點(diǎn)跟Android的ViewGroup不同)。
<pre>
let drop = UIView(frame: frame) //創(chuàng)建一個UIView
addSubview(drop) //添加drop到當(dāng)前UIView里
drop.removeFromSuperview() //drop從父UIView中移除儡循, 考慮一下drop執(zhí)行了哪些生命周期函數(shù)舶吗?
</pre>
技巧4: 使用閉包語法為變量賦初值, lazy關(guān)鍵字為懶加載择膝,即運(yùn)行時調(diào)用了animator變量后才會執(zhí)行閉包代碼誓琼。
<pre>
private lazy var animator: UIDynamicAnimator = {
let animator = UIDynamicAnimator(referenceView: self)
animator.delegate = self
return animator
}()
</pre>
技巧5: 監(jiān)聽屬性變化didSet/WillSet事件(觀察者模式)并添加對應(yīng)邏輯。 還記得前面博文提到的兩個類相互引用的問題么肴捉,使用weak關(guān)鍵字解開閉環(huán)腹侣;注意下面代碼, 如果在閉包里使用了self每庆, 那么外部類實(shí)例和閉包之間形成了相互引用的關(guān)系筐带, 這時需要使用[unowned self]避免內(nèi)存泄漏。
<pre>
private var attachment: UIAttachmentBehavior? {
willSet {
if attachment != nil {
... //attachment值變化前缤灵,做邏輯
}
}
didSet {
if attachment != nil {
... //attachment值變化后伦籍,做邏輯
attachment!.action = {[unowned self] in
if let attachedrop = self.attachment!.items.first as? UIView {
self.bezierPaths["line"] = UIBezierPath.lineFrom(from: (self.attachment?.anchorPoint)!, to: attachedrop.center)
}
}
}
}
}<</pre>
技巧6: if邏輯判斷需要where關(guān)鍵字的功能, 這時要使用逗號腮出。 下面示例代碼的意思是dropToAttachTo不是nil時才執(zhí)行后面的語句dropToAttachTo.superview != nil 帖鸦, 如果條件都滿足則進(jìn)入代碼塊。
<pre>
if let dropToAttachTo = lastDrop, dropToAttachTo.superview != nil {
attachment = UIAttachmentBehavior(item: dropToAttachTo, attachedToAnchor: gesturePoint)
}
</pre>
技巧7:對應(yīng)Optional參數(shù)類型胚嘲,即值可能為nil作儿。 在Java語法里要寫一堆的判空,語句間使用&&連接馋劈; Swift3.0省略了判空操作攻锰,再也不用寫蛋疼的判空語句了。
請問下面的語句會崩潰嗎妓雾?<pre>
attachment = nil
attachment?.anchorPoint = gesturePoint //attatchment后面是問號娶吞,說明他是Optional類型
</pre>答: 不會!
翻譯一下: 如果attachment等于nil則不調(diào)用.后面的參數(shù)械姻, 如果attachment有值則調(diào)用后面的參數(shù)妒蛇。擴(kuò)展一下可以是這樣: attachment?.param1?.param2?.param3?.someValue , 如果用Java寫這條語句要被累死!P宥帷吏奸!
技巧8: 自定義UIView繪制若干個圖形時,可以使用Dictionary數(shù)組陶耍。 注意setNeedsDisplay函數(shù)類似于Android的invalidate奋蔚,相當(dāng)于設(shè)置個邏輯判斷參數(shù)為true,UIView會在下個繪制周期時調(diào)用drawRect函數(shù)烈钞; 自定義UIView定義一個數(shù)組旺拉, 在drawRect函數(shù)里遍歷并繪制。
<pre>
var bezierPaths = String:UIBezierPath {
didSet {
setNeedsDisplay() //觸發(fā)刷新
}
}
override func draw(_ rect: CGRect) {
for (_, path) in bezierPaths {
path.stroke() //畫線
}
} </pre>