Swift學習筆記2 - Views

前言

這是斯坦福大學在線課程-Developing iOS 9 Apps with Swift 的學習內容,在iTunes上就可以搜到,有興趣的小伙伴可以一起學習一起進步哈!這里我將一些我認為的關鍵知識點摘錄在我的學習筆記系列中。之前用英文寫了幾篇,感覺沒什么人看,其實個人認為用英文學再用英文寫其實更簡單方便一些。

Demo

首先,是一張萌蠢的笑臉,你要是看著不舒服,你可以從我的github中下載相應代碼,或者自己敲哈,讓它哭也成。

smile

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

有兩種不同的方式:

  1. init(frame: CGRect) // 由代碼創建生成
  2. 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的一些基本概念

  1. 使用UIGraphicsGetCurrentContext()來獲取一些能在drawRect中使用的文本內容(context,打印的,屏幕外的緩存中的, etc.)
  2. 創建路徑(線,圓)
  3. 設定一些相關屬性,比如顏色,字體,線寬之類的。
  4. 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中,并不會顯示什么。必須要設置相應的屬性(顏色,線寬等等),然后strokefill,才能在屏幕上顯示出來。
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的兩個弊端
  1. 我們知道,var具有可變性(mutability),let沒有。但是在NSAttributedString中,不管是var還是let,都是不可變的(immutable)。因為這是個objective-c的類,所以swift中還是有點缺陷。要想做到可變形,你可以使用另一個類,NSMutableAttributedString,如下語句:
let mutableString = NSMutableAttributedString("some text")

注意,NSAttributedString不是String,也不是NSString.

  1. 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中

歡迎轉載,轉載請注明出處。訪問我的個人主頁,了解更多。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容