一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

iOS翻譯-Core Graphics教程1:入門

 sungkmile 2016-05-04

翻譯了一篇raywenderlich的文章,Core Graphics的入門教程。(有部分省略,剩下的都是主要過程。)

原文鏈接: http://www./90690/modern-core-graphics-with-swift-part-1

想象一下你開發(fā)完成了你的app,并且運行良好,但是界面不太好看。你可以用Photoshop繪制多個size的控件圖片,希望Apple不會出@4x retina的屏幕。。

或者你可以提前預想到使用Core Graphice代碼創(chuàng)建一個image,這樣就能自動適應各種尺寸顯示在設備上。

Core Graphics是Apple的矢量繪圖框架。它非常強大,API功能齊全,里面有許多需要學習的知識。但不用害怕,這里三部分可以引導你入門,最后你將在app里面創(chuàng)建一個好看的圖形。

這是一個全新的系列,用先進的方法來教開發(fā)者使用Core Graphice。這個系列全部在Xcode6用Swift寫(現(xiàn)在Xcode7了,測試可以通過),包含了新的功能,例如@IBDesignable@IBInspectable,可以讓Core Graphics學起來更加有趣和容易。

帶著你最喜歡的飲料,讓我們開始吧!

介紹Flo

你將創(chuàng)建一個完整的app來記錄你喝水的習慣。

這個app很容易記錄你喝了多少水。 它會告訴我們一天喝8杯水是健康的,但很容易在記錄幾杯后就忘記了。這就是寫Flo的原因。每次你干完一杯新鮮的水,點擊計數(shù)器。你也可以在里面看見7天的記錄。

在這部分里面,你將使用UIKit的繪制方法創(chuàng)建3個控件。

在第二部分,你將深入了解Core Graphice內容,繪制圖形。

在第三部分,你將創(chuàng)建帶圖案的背景,獎勵自己一枚自己繪制的金牌.

創(chuàng)建自定義視圖

當你想自定義繪制圖形的時候,你需要三個步驟:

  • 1、創(chuàng)建UIView的子類
  • 2、覆蓋drawRect方法,在里面寫一些繪制的代碼
  • 3、沒有第三步了

讓我們嘗試做一個自定義的加號按鈕

先差創(chuàng)建一個button,命名為PushButtonView

UIButtonUIView的子類,所以在UIButton里面能夠使用UIView的所有方法,例如drawRect

打開Identity Inspector,修改class為自定義的PushButtonView

坐標和大小是X=250, Y=350, Width=100, and Height=100

增加約束

使用Auto Layout增加約束

會創(chuàng)建4個約束,你可以在Size Inspector里面看見下面的內容

移除默認的Button的title

繪制Button

首先需要明白3個原理,繪制圖片的路徑:

  • 1、路徑是可以繪制和填充的
  • 2、路徑輪廓的顏色是當前繪制的顏色
  • 3、使用當前的填充顏色填滿封閉的路徑

創(chuàng)建Core Graphice路徑可以通過UIBezierPath,他提供了友好的API創(chuàng)建路徑。無論你想要線、曲線、矩形、還有一些列的連接點。

PushButtonView.swift下面添加方法

1
2
3
4
5
 override func drawRect(rect: CGRect) {
var path = UIBezierPath(ovalInRect: rect)
UIColor.greenColor().setFill()
path.fill()
}

這里用ovalInRect橢圓形方法,傳遞了一個矩形的大小。生成一個100*100的button在storyboard.所以橢圓形實際上是圓形。

路徑本身不知道如何繪制。你可以定義一個路徑但是不會繪制任何有用的內容。為了繪制路徑,你可以給當前內容一個填充的顏色(fill color)

運行程序將看見綠色的圓形.

到目前為止,你會發(fā)現(xiàn)創(chuàng)建一個自定義的圖形是多么容易,你已經(jīng)創(chuàng)建了一個button的子類,覆蓋了drawRect方法,并且添加了UIButton在你的Storyboard上面

Core Graphics繪制的原理

每一個UIView都有一個graphics context(繪圖上下文),在設備硬件顯示前,繪制的所有視圖都會被渲染到這個上下文中.

iOS 在任何時候需要更新視圖都是通過調用drawRect方法。發(fā)生在

  • 1、視圖是在屏幕上是新的
  • 2、頂部視圖被移除
  • 3、視圖的hidden屬性改變
  • 4、明確調用setNeedsDisplay()setNeedsDisplayInRect()方法

注意:所有drawRect里面繪制,在完成之后會放到view 的graphics context中。如果你在drawRect外部繪制,你需要在最后面創(chuàng)建自己的graphics context

你還不必使用Core Graphics因為UIKit封裝了很多Core Graphics的方法。例如UIBezierPath封裝了CGMutablePath(這是Core Graphics底層的API)

注意:不要直接調用drawRect. 如果你需要更新視圖,調用setNeedsDisplay()方法
setNeedsDisplay()不會自己調用drawRect方法,但是會標記視圖,讓視圖通過drawRect重繪在下一次循環(huán)更新的時候。 所以當你在一個方法里面多次調用setNeedsDisplay()的時候,你實際上也只是調用了一次drawRect

@IBDesignable - 交互式繪制

代碼創(chuàng)建路徑去繪制,運行app去看結果看起來就像等顏料干一樣精彩。但是你有其他的選擇,Xcode6允許一個視圖通過 @IBDesignable 設置屬性。 可以在storyboard上面實時更新。

PushButtonView.swift ,在class聲明前添加@IBDesignable

打開Assistant Editor,通過下面視圖查看

最后屏幕是這個樣子的

修改顯示的顏色,改成blueColor

1
UIColor.blueColor().setFill()

你會發(fā)現(xiàn)屏幕會立即改變

下面我們來添加”+”符號的線

繪制到Context

Core Graphics使用的是”畫家繪畫的模式”(原文是”Core Graphics uses a “painter’s model.”,一開始不太明白是什么意思,但是看下文的圖再來看這句話就明白是什么意思了)

當你畫一個內容的時候,就像在制作一幅畫。你繪制了一個路徑并且填滿它,然后你在這上面又繪制了另外一個路徑填滿它。 你不可能改變繪制的像素,但是你可以覆蓋他們。

下面這張圖片來自蘋果的官方文檔,描述了是如何工作的。正如你在一塊畫板上繪制圖片,決定樣式的是你繪制的順序

你的+號在藍色圓形的上面,所以首先你需要寫繪制藍色圓形的代碼,然后才是加號的繪制。

你可以畫兩個矩形實現(xiàn)加號,但是你同樣可以畫一個路徑然后用同樣的厚度描邊

修改drawRect()的代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
	//set up the width and height variables
//for the horizontal stroke
let plusHeight: CGFloat = 3.0
let plusWidth: CGFloat = min(bounds.width, bounds.height) * 0.6

//create the path
var plusPath = UIBezierPath()

//set the path's line width to the height of the stroke
plusPath.lineWidth = plusHeight

//move the initial point of the path
//to the start of the horizontal stroke
plusPath.moveToPoint(CGPoint(
x:bounds.width/2 - plusWidth/2,
y:bounds.height/2))

//add a point to the path at the end of the stroke
plusPath.addLineToPoint(CGPoint(
x:bounds.width/2 + plusWidth/2,
y:bounds.height/2))

//set the stroke color
UIColor.whiteColor().setStroke()

//draw the stroke
plusPath.stroke()

可以在storyboard中看到是這樣的結果

在iPad2和iPhone 6 Plus模擬器上運行。你會發(fā)現(xiàn)下面的情況

點和像素

點和像素占據(jù)相同的空間和大小,本質上是相同的事情。當retain的iPhone面世的時候,相同點上有4個像素

同樣的,iPhone6 Plus再一次把每個點的像素提升了。

具體學習可以參考這篇文章

這里有一個12 * 12 像素的宮格,點是灰色和白色的。iPad2是點和像素直接映射。iPhone6是2x retain屏幕,4個像素是一個點。第三個iPhone6 Plus 是3x retain屏幕,9個像素是一個點.

剛剛畫得線是3個點的高度。線從路徑的中間開始描繪,所以1.5個點會描繪在線的兩邊。

這個圖片展示了將回執(zhí)3個點的線在設備上的情況。iPad2和iPhone6 Plus結果是需要跨越半個像素。iOS在兩種顏色中當一種顏色只有半邊像素填充的時候會抗鋸齒,所以線會看得模糊

實際的情況是,iPhone6 Plus有很多個像素,所以可能看不到模糊的情況。盡管如此,你需要檢查在真機上檢查你的app。但是假如你在不是retain的屏幕上(iPad2 or iPad mini),你可以避免抗鋸齒。

如果你的直線大小是單數(shù),你應該把她們的點增加或減少0.5為了預防鋸齒。在iPad2上將移動半個像素點,在iPhone6上,剛好充滿整個像素。在iPhone6 Plus,剛好充滿1.5個像素.

修改后的代碼

1
2
3
4
5
6
7
8
9
10
	//move the initial point of the path
//to the start of the horizontal stroke
plusPath.moveToPoint(CGPoint(
x:bounds.width/2 - plusWidth/2 + 0.5,
y:bounds.height/2 + 0.5))

//add a point to the path at the end of the stroke
plusPath.addLineToPoint(CGPoint(
x:bounds.width/2 + plusWidth/2 + 0.5,
y:bounds.height/2 + 0.5))

iOS 將清晰的渲染直線在三個設備上,因為你改變了路徑的半個點

注意:為了線展現(xiàn)完美的像素,你可以用UIBezierPath(rect:)用fill填充,取代直接畫線。使用contentScaleFactor計算矩形的高度和寬度。 不像從路徑中心像兩邊描繪,fill只會向路徑里面填充 (這個東西好重要呀。。。)

接下來化垂直的線

1
2
3
4
5
6
7
8
9
10
11
	//Vertical Line

//move to the start of the vertical stroke
plusPath.moveToPoint(CGPoint(
x:bounds.width/2 + 0.5,
y:bounds.height/2 - plusWidth/2 + 0.5))

//add the end point to the vertical stroke
plusPath.addLineToPoint(CGPoint(
x:bounds.width/2 + 0.5,
y:bounds.height/2 + plusWidth/2 + 0.5))

結果是這樣子的

@IBInspectable 自定義Storyboard屬性

@IBInspectable定義的屬性能夠在IB里面可見。這意味著你可以不用代碼,在IB里面設置button的顏色

1
2
@IBInspectable var fillColor: UIColor = UIColor.greenColor()
@IBInspectable var isAddButton: Bool = true

drawRect里面修改

1
UIColor.blueColor().setFill()

變成

1
fillColor.setFill()

最后修改好的代碼是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
	import UIKit

@IBDesignable
class PushButtonView: UIButton {

@IBInspectable var fillColor: UIColor = UIColor.greenColor()
@IBInspectable var isAddButton: Bool = true

override func drawRect(rect: CGRect) {


var path = UIBezierPath(ovalInRect: rect)
fillColor.setFill()
path.fill()

//set up the width and height variables
//for the horizontal stroke
let plusHeight: CGFloat = 3.0
let plusWidth: CGFloat = min(bounds.width, bounds.height) * 0.6

//create the path
var plusPath = UIBezierPath()

//set the path's line width to the height of the stroke
plusPath.lineWidth = plusHeight

//move the initial point of the path
//to the start of the horizontal stroke
plusPath.moveToPoint(CGPoint(
x:bounds.width/2 - plusWidth/2 + 0.5,
y:bounds.height/2 + 0.5))

//add a point to the path at the end of the stroke
plusPath.addLineToPoint(CGPoint(
x:bounds.width/2 + plusWidth/2 + 0.5,
y:bounds.height/2 + 0.5))

//Vertical Line
if isAddButton {
//move to the start of the vertical stroke
plusPath.moveToPoint(CGPoint(
x:bounds.width/2 + 0.5,
y:bounds.height/2 - plusWidth/2 + 0.5))

//add the end point to the vertical stroke
plusPath.addLineToPoint(CGPoint(
x:bounds.width/2 + 0.5,
y:bounds.height/2 + plusWidth/2 + 0.5))
}

//set the stroke color
UIColor.whiteColor().setStroke()

//draw the stroke
plusPath.stroke()

}

}

isAddButton的設置可以標識是否需要添加豎線,也就是表明是加號還是減號

改變fill顏色RGB(87, 218, 213),isAddButton為off

顯示出來的結果是

UIBezierPath 畫圓弧

下面我們自定義的視圖是這樣子的

這看起來像一個填充的形狀,但是這個圓弧實際上是一個大的描邊。外部的線是另外一個路徑的描邊組成的2個圓弧。

創(chuàng)建一個CounterView類,這個事UIView的子類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import UIKit

let NoOfGlasses = 8
let π:CGFloat = CGFloat(M_PI)

@IBDesignable class CounterView: UIView {

@IBInspectable var counter: Int = 5
@IBInspectable var outlineColor: UIColor = UIColor.blueColor()
@IBInspectable var counterColor: UIColor = UIColor.orangeColor()

override func drawRect(rect: CGRect) {

}
}

NoOfGlasses:是一個數(shù)字表明每天喝水的杯數(shù)。
counter: 記錄了喝水的杯數(shù)

在剛剛PushButtonView上面放置一個視圖,所屬類是CounterView,坐標大小是

數(shù)學知識

畫這個圓弧需要根據(jù)單位園來畫

紅色箭頭表示開始與結束的點,順時針繪畫。 從3π/4弧度開始畫。相當于135°,順時針到π/4弧度,也就是45°

畫弧度

CounterView.swift里面,drawRect方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
	// 1
let center = CGPoint(x:bounds.width/2, y: bounds.height/2)

// 2
let radius: CGFloat = max(bounds.width, bounds.height)

// 3
let arcWidth: CGFloat = 76

// 4
let startAngle: CGFloat = 3 * π / 4
let endAngle: CGFloat = π / 4

// 5
var path = UIBezierPath(arcCenter: center,
radius: radius/2 - arcWidth/2,
startAngle: startAngle,
endAngle: endAngle,
clockwise: true)

// 6
path.lineWidth = arcWidth
counterColor.setStroke()
path.stroke()
  • 1、設置中心點
  • 2、計算視圖最大尺寸的半徑
  • 3、計算扇形的厚度
  • 4、設置開始和結束的弧度
  • 5、根據(jù)中心點、半徑、還有度數(shù)畫路徑
  • 6、設置線的寬度和顏色,最后把路徑繪制出來。

注意:這里有畫弧的更詳細的介紹 Core Graphics Tutorial on Arcs and Paths

最后實現(xiàn)的效果是

圓弧的輪廓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
	//Draw the outline

//1 - first calculate the difference between the two angles
//ensuring it is positive
let angleDifference: CGFloat = 2 * π - startAngle + endAngle

//then calculate the arc for each single glass
let arcLengthPerGlass = angleDifference / CGFloat(NoOfGlasses)

//then multiply out by the actual glasses drunk
let outlineEndAngle = arcLengthPerGlass * CGFloat(counter) + startAngle

//2 - draw the outer arc
var outlinePath = UIBezierPath(arcCenter: center,
radius: bounds.width/2 - 2.5,
startAngle: startAngle,
endAngle: outlineEndAngle,
clockwise: true)

//3 - draw the inner arc
outlinePath.addArcWithCenter(center,
radius: bounds.width/2 - arcWidth + 2.5,
startAngle: outlineEndAngle,
endAngle: startAngle,
clockwise: false)

//4 - close the path
outlinePath.closePath()

outlineColor.setStroke()
outlinePath.lineWidth = 5.0
outlinePath.stroke()
  • 1、outlineEndAngle是輪廓結束的度數(shù)。根據(jù)當前的counter來計算
  • 2、outlinePath 是輪廓的路徑。
  • 3、添加一個內置的圓弧。有相同的度數(shù),不過要反著來繪畫(clockWise要設置為false)
  • 4、自動閉合路徑,畫線。

最后的結果是這樣的

讓它工作起來

在Storyboard里面調整Counter Color為RGB(87, 218, 213),Outline Color為RGB(34, 110, 100)

ViewController.swift里面增加這些屬性和方法

1
2
3
	//Counter outlets
@IBOutlet weak var counterView: CounterView!
@IBOutlet weak var counterLabel: UILabel!
1
2
3
4
5
6
7
8
9
10
@IBAction func btnPushButton(button: PushButtonView) {
if button.isAddButton {
counterView.counter++
} else {
if counterView.counter > 0 {
counterView.counter--
}
}
counterLabel.text = String(counterView.counter)
}

viewDidLoad里面設置counterLabel的更新值

1
counterLabel.text = String(counterView.counter)

最后在Storyboard里面連線

為了能夠點擊按鈕后能夠重新繪制,需要修改CounterView里面的counter屬性的setter方法,調用setNeedsDisplay

1
2
3
4
5
6
7
8
	@IBInspectable var counter: Int = 5 {
didSet {
if counter <= NoOfGlasses {
//the view needs to be refreshed
setNeedsDisplay()
}
}
}

最后app可以運行啦

總結:
1、學習了繪圖的基本原理
2、如何使用@IBDesignable@IBInspectable
3、抗鋸齒問題是如何解決的
4、繪圖的順序,以及扇形的基本知識,如何去繪制扇形

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产欧美日韩精品成人专区| 亚洲三级视频在线观看免费| 神马午夜福利免费视频| 女人精品内射国产99| 美女激情免费在线观看| 东京干男人都知道的天堂| 最好看的人妻中文字幕| 中文日韩精品视频在线| 亚洲综合伊人五月天中文| 国产级别精品一区二区视频| 黄色在线免费高清观看| 国产在线小视频你懂的| 欧美性高清一区二区三区视频| 亚洲欧美日本成人在线| 日本精品视频一二三区| 特黄大片性高水多欧美一级| 视频在线观看色一区二区| 厕所偷拍一区二区三区视频| 日韩免费av一区二区三区| 亚洲中文字幕高清乱码毛片 | 东京不热免费观看日本| 欧美大黄片在线免费观看| 国产亚洲不卡一区二区| 日韩一级一片内射视频4k| 欧美午夜一区二区福利视频| 中日韩免费一区二区三区| 亚洲日本韩国一区二区三区| 成人精品视频在线观看不卡| 欧美有码黄片免费在线视频| 日本道播放一区二区三区| 日韩毛片视频免费观看| 成人国产激情在线视频| 中文字幕不卡欧美在线| 欧美有码黄片免费在线视频| 亚洲视频一区自拍偷拍另类| 久久天堂夜夜一本婷婷| 国产精品久久香蕉国产线| 国产一级特黄在线观看| 老熟妇2久久国内精品| 欧美成人免费夜夜黄啪啪| 亚洲一区二区三区一区|