前言
這是斯坦福大學在線課程-Developing iOS 9 Apps with Swift 的學習內容,在iTunes上就可以搜到,有興趣的小伙伴可以一起學習一起進步哈!這里我將一些我認為的關鍵知識點摘錄在我的學習筆記系列中。之前用英文寫了幾篇,感覺沒什么人看,其實個人認為用英文學再用英文寫其實更簡單方便一些。
Demo
首先,是一張萌蠢的笑臉,你要是看著不舒服,你可以從我的github中下載相應代碼,或者自己敲哈,讓它哭也成。
Views
-
先亂入一條(別打我),swift的命名規范:在swift中,所有類型的名稱的首字母大寫。
比如private enum Eye
,private struct Ratios
- 一個view(比如:UIView)表示的是一個矩形的區域,定義了一個坐標空間。它可以用來畫圖(比如這個demo),也可以用來處理點擊事件。
- view在swift中是分級的,也就是說
- 一個view只能有一個superview,
var superview: UIView?
- 一個view可以有很多個subview,
var subviews: [UIView]
- subview的范圍甚至可以在他老爸view的范圍之外。
- view是有順序之分的,后來者居上。
- UIWindow在view(分級)中處在非常高級的位置,在一個app中一般只有一個。
初始化一個UIView
有兩種不同的方式:
- init(frame: CGRect) // 由代碼創建生成
- init(coder: NSCoder) // 由storyboard生成
如果你需要一個初始化程序,那這兩種初始化都需要執行:
func setup() { ... }
override init(frame: CGRect) { // a designed initializer
super.init(frame: frame)
setup()
}
required init(coder aDecoder: NSCoder) { // a required initializer
super.init(coder: aDecoder)
setup()
}
另一個初始化方式:使用awakeFromNib()
,這只能用于storyboard上創建的UIView。注意這不是一個初始化器,它是“初始化完成之后立馬被調用”。
坐標系統數據結構
- CGFloat
在UIView的坐標系統中,使用CGFloat類型的數據而不是Double或者Float。你可以將Double或者Float轉換成CGFloat, 比如:let cgf = CGFloat(aDouble)
- CGPoint
比如:var point = CGPoint(x: 37.0, y: 52.0)
其實就是由兩個CGFloat類型的數組成的一個簡單結構。 - CGSize
和CGPoint差不多,也是由兩個CGFloat類型的數組成的簡單結構。
比如:
var size = CGSize(width: 100.0, height: 50.0)
size.width += 10
size.height += 5
- CGRect
由CGPoint和CGSize組成的結構
struct CGRect {
var origin: CGPoint
var size: CGSize
}
let rect = CGRect(origin: aCGPoint, size: aCGSize) //當然可以用別的初始化方式
這結構里自帶了很多好東西:
var minX: CGFloat //最小的x
var midY: CGFloat //中間點的y
intersects(CGRect) -> Bool //判斷和別的CGRect有沒有相交
intersect(CGRect) //返回相交的部分
contains(CGRect) -> Bool //判斷是否包含了另一個CGRect
View的坐標系統
-
左上是初始點。如下圖:
!注意,單位是點,不是
像素,點不是像素,點等于幾個像素。比如在6 plus上,每個點有3個像素;有些手機則是2個像素一個點。
你可以通過這條語句知道你的設備一個點有多少像素,var contentScaleFactor: CGFloat
當你需要畫圖的時候,使用
var bounds: CGRect
,這是一個包含了你自己的坐標系統的畫圖空間的矩形,也就是說,它在你自己的畫圖空間里,由你在view中的代碼實現來定義bounds.origin。那么UIView在哪里?
var center: CGPoint // UIView的中心坐標(在它的superview的坐標系統中)
var frame: CGRect // 包含UIView的矩形(在它的superview的坐標系統中)
。 frame指的是你的view在superview中的位置,也就是說這是放在superview的坐標系統中的,而不是你的畫圖坐標系統中。
。 center相應的,也是指的superview中的center,和你的畫圖空間并沒有毛線關系~當你畫圖的時候用bounds就好啦。看代碼理解也許會比較清晰一點,可以以上面提到的demo為例,
。 frame和bounds的寬高也不同,因為view可以旋轉。
創建一個view
在上面提到的demo中,我們做的是一個笑臉,而iOS并沒有smileview這個東西,所以我們要自己建。我們使用的是一般view(generic view),就當是一般類吧,可以拿來隨意發揮。
你可以在object library里輕松找到它,或者搜“view“
e.g.
// 假設這段代碼在UIViewController中
let labelRect = CGRect(x: 20, y: 20, width: 10, height: 10)
let label = UILabel(frame: labelRect) // UILabel是UIView的子類,所以那些UILabel中的那些字也是一筆一畫畫出來的。。
label.text = "hello"
view.addSubview(label)
自定義Views
何時需要自定義UIView的子類
我想自定義繪圖
我想以一些特殊的方式處理點擊事件(這里不同于button或者slider)
至于畫圖,只需要創建一個UIView的子類,然后override drawRect:
override func drawRect(regionThatNeedsToBeDrawn: CGRect)
如之前所說,你可以畫在regionThatNeedsToBeDrawn的范圍之外。
- UIView的邊界定義了我們整個畫圖區域,region只是一個子區域!!!絕對不能直接調用drawRect,它是系統的專屬天使。但是當你需要畫圖怎么辦呢?告訴系統,你要用這個方法了,用以下的語句:
setNeedsDisplay()
setNeedsDisplayInRect(regionThatNeedsToBeRedrawn: CGRect)
iOS會在一個適當的時機調用drawRect,比如你的破事全部決定了之后,一次性將要重畫(redraw)的東西全部drawRect。
那么我怎么實現drawRect呢?
你可以使用一個類C的API(不是面向對象的),叫Core Graphics,swift是完全面相對象的,摻和進來這玩意應該不是好事吧 ==
你還可以使用面向對象的類-UIBezierPath,這也是我們在demo中所使用的。
Core Graphics的一些基本概念
- 使用
UIGraphicsGetCurrentContext()
來獲取一些能在drawRect中使用的文本內容(context,打印的,屏幕外的緩存中的, etc.) - 創建路徑(線,圓)
- 設定一些相關屬性,比如顏色,字體,線寬之類的。
-
stroke
或者fill
以上創建的路徑。
UIBezierPath
和上面那個家伙差不多,只是UIBezierPath自動知道context。定義一個路徑
創建一個UIBezierPath
let path = UIBezierPath()
- 加幾條線,或者圓弧
path.moveToPoint(CGPoint(x: 80, y: 50))
path.addLineToPoint(CGPoint(x:140, y: 150))
path.addLineToPoint(CGPoint(x: 10, y: 150))
- 可以閉合路徑
path.closePath()
此時就已經得到了一個可愛的三角形。但是并沒有畫出來
-
注意, 你僅僅將上面創建的線條放在drawRect中,并不會顯示什么。必須要設置相應的屬性(顏色,線寬等等),然后
stroke
/fill
,才能在屏幕上顯示出來。
UIColor.greenColor().setFill() // 注意這是UIColor中的方法
UIColor.redColor().setStroke() // 注意這是UIColor中的方法
path.lineWidth = 3.0 // 這是UIBezierPath中的屬性
path.fill() // UIBezierPath中的方法
path.stroke() // UIBezierPath中的方法
- 你也可以用UIBezierPath畫很多其它類型的圖,比如:
let roundRect = UIBezierPath(roundedRect: CGRect, cornerRadius: CGFloat)
let oval = UIBezierPath(ovalInRect: aCGRect)
- 也可以圓滑夾角,就是給每個角增加一個弧度。使用
addClip()
- 也可以進行碰撞監測,就是檢測一個點是不是在閉合路徑里面。
func containsPoint(CGPoint) -> Bool
UIColor
- 對于很多普通顏色來講,有很多類方法可以使用,比如
let green = UIColor.greenColor()
,可以用RGB, HSB, 甚至可以使用某些樣式(比如圖片)。 - UIView的背景色,
var backgroundColor: UIColor
- 顏色可以有alpha,可以設置透明度
let transparentYellow = UIColor.yellowColor().colorWithAlphaComponent(0.5) // 這是個instance method, 不是type method
alpha: 0.0(完全透明) - 1.0(完全不透明)
如果想要在程序中設置顏色的透明度,必須設置
var opaque = false
, 來讓系統知道這些都不是不透明的,也就是你要開始設置透明度了。也可以設置整個UIView的透明度
var alpha: CGFloat
通過alpha,可是設計一個漸出(慢慢消失)的動畫。
- 也可以隱藏一個view,通過
var hidden: Bool
顯示(畫)文本
- 一般我們使用UILabel來顯示文本,但我們有時候還是需要在drawRect中直接顯示文本
- 在drawRect中,可以使用NSAttributedString
AttributedString就是每個string中的字符,都有一個字典存儲相應的每個字符的屬性信息,比如顏色,字體等。
let text = NSAttributedString("hello")
text.drawAtPoint(aCGPoint)
let textSize: CGSize = text.size //這個字符串需要多少空間
- NSAttributedString的兩個弊端
- 我們知道,var具有可變性(mutability),let沒有。但是在NSAttributedString中,不管是var還是let,都是不可變的(immutable)。因為這是個objective-c的類,所以swift中還是有點缺陷。要想做到可變形,你可以使用另一個類,NSMutableAttributedString,如下語句:
let mutableString = NSMutableAttributedString("some text")
注意,NSAttributedString不是String,也不是NSString.
- swift的string是unicode的,比oc的強大太多,所以它們的string也不一樣,在NSAttributedString中,需要使用NSRange,注意這不是Range,這是oc里的NSRange。所以在使用的時候,需要將range轉換成NSRange(可自動完成),然后才能在NSAttributedString中用NSRange。
func setAttributes(attributes: Dictionary, range: NSRange)
func addAttributes(attributes: Dictionary, range: NSRange)
在Attributes中可以放以下這些dictionary:
NSForegroundColorAttributeName: UIColor
NSStrokeWidthAttributeName: UIFloat
NSFontAttributeName: UIFont
字體
字體在蘋果的產品中占有非常重要的地位,畢竟藝術品。
- 使用字體的最好的方式
- 對于文本內容,采用preferred font
static func preferredFontForTextStyle(UIFontTextStyle) -> UIFont
UIFontTextStyle.Headline
UIFontTextStyle.Body
UIFontTextStyle.Footnote
- 對于按鈕之類的,使用系統字體(system fonts)
static func systemFontOfSize(pointSize: CGFloat) -> UIFont
static func boldSystemFontOfSize(pointSize: CGFloat) -> UIFont
在用戶的文本信息中,不要使用這些系統字體
- 其它方式:UIFont和UIFontDescriptor
顯示圖片
有個UILabel相類似的類,UIImageView,當然你還是有可能想在drawRect中直接顯示圖片的,那么。。。
- 創建UIImage -
let image: UIImage? = UIImage(named: "foo")
,optional是因為有可能沒有圖片 - 從系統文件中創建(files in the file system)
let image: UIImage? = UIImage(contentsOfFile: aString)
let image: UIImage? = UIImage(data: anNSData) // jpg, png, tiff, etc.
- 開始畫
let image: UIImage = ...
image.drawAtPoint(aCGPoint) // 圖片的左上角
image.drawInRect(aCGRect) // 將圖片按比例擴充到aCGRect中
image.drawAsPatternInRect(aCGRect) //將圖片平鋪到aCGRect中
歡迎轉載,轉載請注明出處。訪問我的個人主頁,了解更多。