Standford 2015 iOS讀書會 week3
彼得潘
1. Objective-C Compatibility, Property List, Views
Bridge:⾃自動轉型變⾝身var name1:String = "20.2" var name2:NSString = "10.0" name2 = name1 name1 = name2 as Stringname1 = String(name2) name2.doubleValue (name1 as NSString).doubleValue
有問題的程式:
name1.doubleValue name1 = name2
NSString -> String 要另外轉型
Bridge:⾃自動轉型變⾝身var num1:Int = 3 var num2:Float = 2.5 var num3:Double = 3.2 var num4:Bool = true var num5:NSNumber = 3 num1 = num5 as Int num1 = Int(num5) num1 = num5.integerValue num3 = num5 as Double num3 = Double(num5) num3 = num5.doubleValue
有問題的程式: num1 = num5
NSNumber -> Int, Float, Double, Bool 要另外轉型
Bridge:⾃自動轉型變⾝身var array1:[Int] = [2,3] var array2:NSArray = NSArray(object: 1) array2 = array1 array1 = array2 as! [Int] (array1 as NSArray).componentsJoinedByString(",")
可能轉型失敗,要⽤用as!
array1 = array2 as! [Double] array1 = array2
有問題的程式:
NSArray -> Array 要另外轉型,⽽而且可能失敗
NSDictionary同NSArray, 同樣NSDictionary -> Dictionary要另外轉型
Bridge
String 轉換成NSStringstruct變成object !
⼀一定要import SDK的framework, ex Foundation
Property List包含以下六種型別資料的集合(容不下其它型別)
NSString NSArray NSDictionary NSNumber
NSData NSDate
NSDictionary和NSArray裡的資料也必須是這六種型別
像是⼩小型的database
property list
Wealthy App的記帳類別
property list
預設唯讀
修改 copy到可讀寫的doc路徑
func copyItemAtURL(_ srcURL: NSURL, toURL dstURL: NSURL,
error error: NSErrorPointer) -> Bool
NSUserDefaults
每個App都有的propert list
永久存在適⽤用例⼦子: App的相關設定資料
只適合儲存少量資料存太多資料時,存取也會較花時間
user’s defaults database
NSString NSArray NSDictionary NSNumber
NSData NSDate
可寫⼊入的資料
NSUserDefaults let defaults = NSUserDefaults.standardUserDefaults() defaults.setObject("peter", forKey: "name") if let name = defaults.objectForKey("name") as! String? { println("name \(name.uppercaseString)")
} if let name = defaults.stringForKey("name") { println("name \(name.uppercaseString)")
} defaults.setInteger(3, forKey: "age") var age = defaults.integerForKey("age") println("age \(age)") defaults.removeObjectForKey("age") var ageObj = defaults.objectForKey("age") println("age \(ageObj)") defaults.synchronize()
synchronize:寫⼊入disk,定期被呼叫,⾃自⼰己呼叫更保險
standford demovar program:PropertyList { get { var returnValue = Array<String>() for op in opStack { returnValue.append(op.description) } return returnValue } } Array<String>轉換成內容為NSString的NSArray
get { return opStack.map{$0.description} }
typealias PropertyList = AnyObject
幫型別取個好聽名字 typealias
standford demoset { if let opSymbols = newValue as? Array<String> { var newOpStack = [Op]() for opSymbol in opSymbols { if let op = knownOps[opSymbol] { newOpStack.append(op) } else if let operand = NSNumberFormatter().numberFromString(opSymbol)?.doubleValue { newOpStack.append(.Operand(operand)) } } opStack = newOpStack } }
View
⻑⾧長⽅方形 Touch事件畫圖 var superview: UIView? { get } var subviews: [AnyObject] { get }
UIWindow: 最底層的Viewindex愈⾼高在愈上層
sv Optional(<UIWindow: 0x7fae6b2823b0; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7fae6b289be0>; layer = <UIWindowLayer: 0x7fae6b294790>>)
空⽩白View Controller的superView
Navigation Controller的superViewsv Optional(<UIViewControllerWrapperView: 0x7f8103779fb0; frame = (0 0; 320 568); autoresize = RM+BM; layer = <CALayer: 0x7f8103780f40>>)
sv Optional(<UINavigationTransitionView: 0x7f810376e3c0; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x7f810376d7a0>>)
sv Optional(<UILayoutContainerView: 0x7f8103419250; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x7f8103776020>; layer = <CALayer: 0x7f810341b530>>)
sv Optional(<UIWindow: 0x7f8103562eb0; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7f81035636b0>; layer = <UIWindowLayer: 0x7f810354ec30>>)
畫⾯面上的UI元件可以存取到Window
ex: self.button.window
⼀一般⼀一個App只有⼀一個window
View
從storyboard建⽴立
從程式加⼊入或移除,利⽤用addSubview(aView: UIView),removeFromSuperview()
View Controller有個view property,連結到其控制的view
初始viewinit(frame: CGRect)
從程式建⽴立view
init(coder: NSCoder)
可從這裡初始storyboard或xib建⽴立的view
override init(frame: CGRect) { super.init(frame: frame) }
覆寫designated initializer要加上override,覆寫convenience initializer不⽤用加override
required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
⼀一旦定義了init(frame: CGRect),required init(coder aDecoder: NSCoder) 也要定義
若先定義了required init(coder aDecoder: NSCoder) ,init(frame: CGRect)則不⼀一定要定義
防⽌止絕技失傳的 required initializer
SuperBaby⾃自⼰己定義designated initializer, 不再繼承init( )
防⽌止絕技失傳的 required initializer
防⽌止絕技失傳的 required initializer
func awakeFromNib()
初始storyboard上元件的另⼀一個⽅方法
在init(coder: NSCoder)後被呼叫
定義⻑⾧長⽅方形的元素 CGFloat
struct CGPoint { var x: CGFloat var y: CGFloat init() init(x: CGFloat, y: CGFloat) }
struct CGSize { var width: CGFloat var height: CGFloat init() init(width: CGFloat, height: CGFloat) }
float不能直接指派給CGFloat
var number1:Float = 5.1 var number2:CGFloat = 3.2 number2 = CGFloat(number1) number1 = Float(number2)
定義⻑⾧長⽅方形的元素
struct CGRect { var origin: CGPoint var size: CGSize init() init(origin: CGPoint, size: CGSize) }
let rect = CGRect(x: 10, y: 10, width: 100, height: 100)
CGRect的property & method
var minX: CGFloat { get } var midX: CGFloat { get } var maxX: CGFloat { get } var minY: CGFloat { get } var midY: CGFloat { get } var maxY: CGFloat { get }
func intersects(rect: CGRect) -> Bool
mutating func intersect(withRect: CGRect)
func contains(rect: CGRect) -> Bool func contains(point: CGPoint) -> Bool
座標系統origin: 左上座標
x -> 愈向右愈⼤大y -> 愈向下愈⼤大
單位points,不是pixel
retina : 2x, 2*2 retina HD: 3x, 3*3, iPhone 6 plus
frame & boundsframe:定位 bounds:繪製元件
frame & bounds let yellowView = UIView(frame: CGRect(x: 50, y: 50, width: 150, height: 150)) yellowView.backgroundColor = UIColor.yellowColor() self.view.addSubview(yellowView)
let blueView = UIView(frame: CGRect(x: 50, y: 50, width: 150, height: 150)) blueView.backgroundColor = UIColor(red: 0, green: 0, blue: 1, alpha: 0.5) self.view.addSubview(blueView) println("frame \(blueView.frame) bounds \(blueView.bounds) center \(blueView.center)") blueView.bounds = CGRect(x: 0, y: 0, width: 300, height: 300) println("frame \(blueView.frame) bounds \(blueView.bounds) center \(blueView.center)")
blueView.frame = CGRect(x: 50, y: 50, width: 150, height: 150) println("frame \(blueView.frame) bounds \(blueView.bounds) center \(blueView.center)") let angel = CGFloat(M_PI/4) let transform = CGAffineTransformMakeRotation(angel) blueView.transform = transform
println("frame \(blueView.frame) bounds \(blueView.bounds) center \(blueView.center)")
360度: M_PI * 2
旋轉後的touch
只有bounds區塊是touch範圍
建⽴立View
從storyboard
從程式
從Identity Inspector設定物件的類別
繪製Viewoverride func drawRect(rect: CGRect) { // Drawing code }
func setNeedsDisplay() func setNeedsDisplayInRect(rect: CGRect)
觸發重新繪製
不要直接呼叫drawRect
func drawRect(rect: CGRect)
利⽤用Core Graphics
UIGraphicsGetCurrentContext()
利⽤用UIBezierPath
以Core Graphics為基礎
繪製三⾓角形
UIColor的set()同時設定fill & stroke
UIBezierPath
let roundRect = UIBezierPath(roundedRect: aCGRect, cornerRadius: aCGFloat) let oval = UIBezierPath(ovalInRect: aCGRect)
UIColor self.view.backgroundColor = UIColor.blueColor()
let image = UIImage(named: "book") self.view.backgroundColor = UIColor(patternImage: image!)
self.view.backgroundColor = UIColor.yellowColor().colorWithAlphaComponent(0.5)
alpha : (透明 )0 ~ 1 (不透明 )
self.view.alpha = 0.5
self.view.hidden = true
影響subView的透明度
不影響subView的透明度
字型
字型 let font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
App內容
let font = UIFont.systemFontOfSize(20)
button等元件的⽂文字
let font = UIFont.boldSystemFontOfSize(20)
let font = UIFont(name: "Papyrus", size: 20)
字型
iOS內建font
http://iosfonts.com
加⼊入第三⽅方字型
ttf,otf
http://codewithchris.com/common-mistakes-with-adding-custom-fonts-to-your-ios-app/
⽂文字let text = NSAttributedString(“hello") text.drawAtPoint(aCGPoint)
let mutableText = NSMutableAttributedString("some string")
func setAttributes(attributes: Dictionary, range: NSRange) func addAttributes(attributes: Dictionary, range: NSRange)
NSForegroundColorAttributeName : UIColor NSStrokeWidthAttributeName : CGFloat NSFontAttributeName : UIFont
UILabel
NSMutableAttributedString let attrMessage = NSMutableAttributedString(string:"天⻑⾧長地久有沒有") let font = UIFont.boldSystemFontOfSize(24) attrMessage.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, attrMessage.length)) attrMessage.addAttribute(NSForegroundColorAttributeName, value: UIColor.blueColor(), range: NSMakeRange(0, 4)) attrMessage.addAttribute(NSForegroundColorAttributeName, value:UIColor.blackColor(), range: NSMakeRange(4, attrMessage.length-4))
self.label.attributedText = attrMessage
1個label即可搞定
ImageUIImageView & UIImage
Images.xcassets
let image: UIImage? = UIImage(named: “foo”)optional
let image: UIImage? = UIImage(contentsOfFile: aString) let image: UIImage? = UIImage(data: anNSData)
UIGraphicsBeginImageContext 程式繪製ex: App畫⾯面截圖
Imagelet image: UIImage = ... image.drawAtPoint(aCGPoint) // the upper left corner of the image put at aCGPoint
image.drawInRect(aCGRect) // scales the image to fit aCGRect
image.drawAsPatternInRect(aCGRect) // tiles the image into aCGRect
contentMode
Image View的content mode
content mode redraw的影響:Standford Happiness App Demo
Happiness App Demo
⾃自訂controllerIdentity Inspector
設定第⼀一個畫⾯面的controller
也可以點選arrow移動
Reset to Suggested Constraints
ctrl + shift + 點選觸控版
顯⽰示點選位置的UI元件清單
convertPoint func convertPoint(point: CGPoint, fromView view: UIView?) -> CGPoint
將參數fromView中的point座標,轉換為呼叫者view的座標
let point = redView.convertPoint(redView.center, fromView: self.view) println("point \(redView.center) \(point)")
point (100.0, 100.0) (50.0, 50.0)
因為Content Mode為ScaleToFill, 當bounds改變時, ⾃自動縮放原來的image
笑臉變型問題
Redraw
設為Redraw時, bounds改變時重新繪製, 呼叫drawRect
定義常數的⽅方法
private struct Scaling { static let FaceRadiusToEyeRadiusRatio:CGFloat = 10 static let FaceRadiusToEyeOffsetRatio:CGFloat = 3 static let FaceRadiusToEyeSeparationRatio:CGFloat = 1.5 static let FaceRadiusToMouthWidthRatio:CGFloat = 1 static let FaceRadiusToMouthHeightRatio:CGFloat = 3 static let FaceRadiusToMouthOffsetRatio:CGFloat = 3
}