HW009從程式製作國旗圖案(#43)

好一陣子沒有碰程式,在畫國旗這項作業也花了一些時間去測試,

以下是這次的試錯重點!

1. 可直接用貝茲曲線內的參數直接畫出特定形狀,如方形rect、圓形oval。

原本以為形狀是直接用別種方式產生出來。貝茲只是畫線用的。待之後再深入瞭解,

2. 在CAShapeLayer繪圖時,記得一定要把path掛上去。

3. 使用backgroundcolor時,永遠都是黑色,要別的顏色就直接填色(fill)上去。

日本國旗

程式碼:

        let drawArea = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 500, height: 930))
let layoutdrawArea = CAShapeLayer()
layoutdrawArea.path = drawArea.cgPath
layoutdrawArea.fillColor = CGColor(red: 0.3, green: 0.3, blue: 0.3, alpha: 0.6)
view.layer.addSublayer(layoutdrawArea)

let flagJapanBasic1 = UIBezierPath(rect: CGRect(x: 80, y: 200, width: 300, height: 200))
let layoutflagJaoanBasic1 = CAShapeLayer()
layoutflagJaoanBasic1.path = flagJapanBasic1.cgPath
layoutflagJaoanBasic1.fillColor = CGColor(red: 1, green: 1, blue: 1, alpha: 1)
view.layer.addSublayer(layoutflagJaoanBasic1)

let flagJapanCircle = UIBezierPath(ovalIn: CGRect(x: 80, y: 200, width: 120, height: 120))
let layoutflagJapanCircle = CAShapeLayer()
layoutflagJapanCircle.path = flagJapanCircle.cgPath
layoutflagJapanCircle.fillColor = CGColor(red: 188/255, green: 0/255, blue: 45/255, alpha: 1)
view.layer.addSublayer(layoutflagJapanCircle)

修改peter的sample並簡單註記另種繪圖的方式(在playground內)

import UIKit
var rect = CGRect(x: 0, y: 0, width: 300, height: 200)
//建立300x200的矩形
let backgroundView = UIView(frame: rect)
backgroundView.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
//繪出白色的矩形底。

rect = CGRect(x: (backgroundView.frame.width - 120)/2, y: (backgroundView.frame.height - 120) / 2, width: 120, height: 120)
//重新定義rect的大小為寬120、高120,且位置在(x:90, y:40), 為使用中心大小去推算座標所在位置。
let circleView = UIView(frame: rect)
circleView.backgroundColor = UIColor(red: 188/255, green: 0, blue: 45/255, alpha: 1)
backgroundView.addSubview(circleView)
circleView.layer.cornerRadius = 60
//藉由剛剛好的圓角化致使方形變成圓形。(二分之一的大小:120/2 = 60)
backgroundView

找到別種方式繪圖,使用UIView!
但總覺得上下的紅色好像不太一樣。

在此程式的上方是使用UIBezierPath內建的rect及oval產生形狀,
再用CAShapeLayer繪圖出來。
所用到的color是CGColor

而此程式的下方則是使用UIView產生矩形,
並用圓角化製造出圓形顯示出來。
用到的則是UIColor。

※此範例僅在此有效,面對複雜的形狀還是得用UIBezierPath產出形狀!
        //底色:
let drawArea = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 500, height: 930))
let layoutdrawArea = CAShapeLayer()
layoutdrawArea.path = drawArea.cgPath
layoutdrawArea.fillColor = CGColor(red: 0.3, green: 0.3, blue: 0.3, alpha: 0.6)
view.layer.addSublayer(layoutdrawArea)

//使用UIBezierPath繪圖
let flagJapanBasic1 = UIBezierPath(rect: CGRect(x: 80, y: 200, width: 300, height: 200))
let layoutflagJaoanBasic1 = CAShapeLayer()
layoutflagJaoanBasic1.path = flagJapanBasic1.cgPath
layoutflagJaoanBasic1.fillColor = CGColor(red: 1, green: 1, blue: 1, alpha: 1)
view.layer.addSublayer(layoutflagJaoanBasic1)

let flagJapanCircle = UIBezierPath(ovalIn: CGRect(x: 170, y: 240, width: 120, height: 120))
let layoutflagJapanCircle = CAShapeLayer()
layoutflagJapanCircle.path = flagJapanCircle.cgPath
layoutflagJapanCircle.fillColor = CGColor(red: 188/255, green: 0/255, blue: 45/255, alpha: 1)
view.layer.addSublayer(layoutflagJapanCircle)


// 使用UIView繪圖:
let rect01 = UIView(frame: CGRect(x: 80, y: 500, width: 300, height: 200))
rect01.backgroundColor = .white
view.addSubview(rect01)

let circle01 = UIView(frame: CGRect(x: 170, y: 540, width: 120, height: 120))
circle01.backgroundColor = UIColor(red: 188/255, green: 0, blue: 45/255, alpha: 1)
circle01.layer.cornerRadius = 60
view.addSubview(circle01)

智利國旗

在卡關於顯示問題以及鏡像繪圖問題時,意外看到智利國旗,覺得是另一種挑戰,畫一個相對位置的國旗,不會因為改變起始點位置或是比例大小而造成圖樣跑掉。程式寫到一半時,突然發覺應該可以直接套用function!?改天再來試試吧。20231103

可隨意調整位置及大小。起始位置:(110, 310), 國旗大小:23 * 6

先畫星星

重新畫這個星星,要滿足三個條件,比較好運用:

1-要在1平方單位的方框內,或是用10,我就是用10個單位長,方便計算。

2-最上方的頂點要切齊邊線,作為繪畫的初始點,是因為好計算。

3-最上方的頂點要置中,方便用在鏡像製圖的運用,也是方便計算。

智利國旗。起始位置:(100, 100), 國旗大小:49 * 6
            // Do any additional setup after loading the view.
let basicX = 110 //這裡調整要放置的位置灰底x軸。避免因為底色是白色而混淆
let basicY = 310 //這裡調整要放置的位置灰底y軸。避免因為底色是白色而混淆
let propoData = 23 // //這裡調整國旗的比例,因為國旗是6:4。會依據比例自動調整大小
let flagRed = UIBezierPath()
flagRed.move(to: CGPoint(x: basicX , y: basicY ))
flagRed.addLine(to: CGPoint(x: basicX + 6 * propoData, y: basicY ))
flagRed.addLine(to: CGPoint(x: basicX + 6 * propoData, y: basicY + 4 * propoData))
flagRed.addLine(to: CGPoint(x: basicX, y: basicY + 4 * propoData))
flagRed.close()
let flagWhite = UIBezierPath()
flagWhite.move(to: CGPoint(x: basicX, y: basicY))
flagWhite.addLine(to: CGPoint(x: basicX + 6 * propoData, y: basicY))
flagWhite.addLine(to: CGPoint(x: basicX + 6 * propoData, y: basicY + 2 * propoData))
flagWhite.addLine(to: CGPoint(x: basicX, y: basicY + 2 * propoData))
flagWhite.close()
let flagBlue = UIBezierPath()
flagBlue.move(to: CGPoint(x: basicX , y: basicY ))
flagBlue.addLine(to: CGPoint(x: basicX + 2 * propoData, y: basicY ))
flagBlue.addLine(to: CGPoint(x: basicX + 2 * propoData, y: basicY + 2 * propoData))
flagBlue.addLine(to: CGPoint(x: basicX, y: basicY + 2 * propoData))
let starflag = UIBezierPath()
starflag.move(to: CGPoint(x: basicX + Int(Double(propoData) * 0.5) , y: basicY ))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.61226), y: basicY + Int(Double(propoData) * 0.34549)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.97553), y: basicY + Int(Double(propoData) * 0.34549)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.68164), y: basicY + Int(Double(propoData) * 0.55902)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.79389), y: basicY + Int(Double(propoData) * 0.90451)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.5), y: basicY + Int(Double(propoData) * 0.69098)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.20611), y: basicY + Int(Double(propoData) * 0.90451)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.31836), y: basicY + Int(Double(propoData) * 0.55902)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.02447), y: basicY + Int(Double(propoData) * 0.34549)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.38774), y: basicY + Int(Double(propoData) * 0.34549)))
starflag.close()

let showRed = CAShapeLayer()
showRed.path = flagRed.cgPath
showRed.fillColor = CGColor(srgbRed: 213/255, green: 43/255, blue: 30/255, alpha: 1)
let showWhite = CAShapeLayer()
showWhite.path = flagWhite.cgPath
showWhite.fillColor = CGColor(red: 1, green: 1, blue: 1, alpha: 1)
let showBlue = CAShapeLayer()
showBlue.path = flagBlue.cgPath
showBlue.fillColor = CGColor(red: 0/255, green: 57/255, blue: 166/255, alpha: 1)
let showStar = CAShapeLayer()
showStar.path = starflag.cgPath
showStar.fillColor = UIColor.white.cgColor
showStar.setAffineTransform(CGAffineTransform(translationX: CGFloat(Float(propoData) * 0.5), y: CGFloat(Float(propoData) * 0.5)))
//加入灰底色以利區分
let backgroundView = UIView(frame: CGRect(x: basicX - 20 , y: basicY - 20, width: basicX + 6 * propoData + 20 , height: basicY + 4 * propoData + 20))
backgroundView.backgroundColor = UIColor.gray
//開始顯示國旗
view.addSubview(backgroundView)
view.layer.addSublayer(showRed)
view.layer.addSublayer(showWhite)
view.layer.addSublayer(showBlue)
view.layer.addSublayer(showStar)

改良版(方形function化):

                // Do any additional setup after loading the view.
let basicX = 20 //這裡調整要放置的位置灰底x軸。避免因為底色是白色而混淆
let basicY = 500 //這裡調整要放置的位置灰底y軸。避免因為底色是白色而混淆
let propoData = 64 // //這裡調整國旗的比例,因為國旗是6:4。會依據比例自動調整大小
//加入灰底色以加強顯示國旗
let backgroundView = UIView(frame: CGRect(x: basicX - 20 , y: basicY - 20, width: 6 * propoData + 40 , height: 4 * propoData + 40))
backgroundView.backgroundColor = UIColor.gray
view.addSubview(backgroundView)
//方形圖案:大小及色彩,之後使用function來呼叫 //////////// 這是改良版
func rectFun(_ setXr: Int,_ setYr: Int, colorR: Double = 1 , colorG: Double = 1 , colorB: Double = 1) {
let flagRect = UIBezierPath()
flagRect.move(to: CGPoint(x: basicX , y: basicY ))
flagRect.addLine(to: CGPoint(x: basicX + setXr * propoData, y: basicY ))
flagRect.addLine(to: CGPoint(x: basicX + setXr * propoData, y: basicY + setYr * propoData))
flagRect.addLine(to: CGPoint(x: basicX, y: basicY + setYr * propoData))
flagRect.close()
let showRect = CAShapeLayer()
showRect.path = flagRect.cgPath
showRect.fillColor = CGColor(srgbRed: colorR, green: colorG, blue: colorB, alpha: 1)
view.layer.addSublayer(showRect)
}
//星星圖案:形狀、大小及色彩
let starflag = UIBezierPath()
starflag.move(to: CGPoint(x: basicX + Int(Double(propoData) * 0.5) , y: basicY ))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.61226), y: basicY + Int(Double(propoData) * 0.34549)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.97553), y: basicY + Int(Double(propoData) * 0.34549)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.68164), y: basicY + Int(Double(propoData) * 0.55902)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.79389), y: basicY + Int(Double(propoData) * 0.90451)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.5), y: basicY + Int(Double(propoData) * 0.69098)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.20611), y: basicY + Int(Double(propoData) * 0.90451)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.31836), y: basicY + Int(Double(propoData) * 0.55902)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.02447), y: basicY + Int(Double(propoData) * 0.34549)))
starflag.addLine(to: CGPoint(x: basicX + Int(Double(propoData) * 0.38774), y: basicY + Int(Double(propoData) * 0.34549)))
starflag.close()
let showStar = CAShapeLayer()
showStar.path = starflag.cgPath
showStar.fillColor = UIColor.white.cgColor
showStar.setAffineTransform(CGAffineTransform(translationX: CGFloat(Float(propoData) * 0.5), y: CGFloat(Float(propoData) * 0.5)))
//開始顯示國旗
let textLabel1 = UILabel()
textLabel1.frame = CGRect(x: basicX - 16 , y: basicY - 20, width: 80, height: 20)
textLabel1.text = "智利國旗"
view.addSubview(textLabel1)

rectFun(6,4, colorR: 213 / 255 , colorG: 43 / 255 , colorB: 30 / 255 )
rectFun(6,2, colorR: 255 / 255 , colorG: 255 / 255 , colorB: 255 / 255 )
rectFun(2,2, colorR: 0 / 255 , colorG: 57 / 255 , colorB: 166 / 255 )
view.layer.addSublayer(showStar)

以下註解掉的地方是突發奇想,想用文字的星星圖樣取代掉原本的星星,但是發現還是有所不同,就先不這樣使用了。


/*
let textLabel0 = UILabel()
textLabel0.frame = CGRect(x: basicX - 5 + Int(Double(propoData) * 0.5) , y: basicY - 11 + Int(Double(propoData) * 0.5), width: 80, height: 80)
textLabel0.text = "★"
textLabel0.font = UIFont.systemFont(ofSize: 66)
textLabel0.textColor = UIColor.white
view.addSubview(textLabel0)
*/

參考來源:

https://www.geogebra.org/calculator

20231030

--

--