寫APP那件事#9.客製 App 畫面
Published in
11 min readAug 16, 2020
溫故知新篇
*程式畫圖步驟1234
1.利用 UIBezierPath 繪製路徑(B)
繪製前,需先製作一個view-畫板(A)
製作畫板let view = UIView()常用路徑寫法如下:1.線條: let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 10, y: 10))
path.close()2.圓形:let path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 10, height: 10))3.長方形: let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 10, height: 10))4.圓角長方形: let path=UIBezierPath.init(roundedRect:CGRect(x: 0, y: 0, width: 10, height: 10), cornerRadius: 5)From:Peter的補充
若只想特定方位有圓角,利用 UIBezierPath 的init(roundedRect:byRoundingCorners:cornerRadii:)
byRoundingCorners: 型別為 UIRectCorner,控制長方形圓角的位置。
cornerRadii: 控制圓角的程度,在此我們傳入的 CGSize 只要指定寬度即可,高度可設為 0。【寫法】
let path = UIBezierPath(roundedRect: CGRect(x: 10, y: 10, width: 80, height: 50), byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: 5, height: 0))5.在圓上的曲線:
let aDegree = CGFloat.pi / 180
let path = UIBezierPath(arcCenter: CGPoint(x: 0, y: 0), radius: 10, startAngle: aDegree * 0, endAngle: aDegree * 180, clockwise: true)6-1.特定弧度的曲線,1個控制點:
path.addQuadCurve(to: CGPoint(x: 10, y: 10), controlPoint: CGPoint(x: 50, y: 50))
6-2.特定弧度的曲線,2個控制點:
path.addCurve(to: CGPoint(x: 10, y: 10), controlPoint1: CGPoint(x: 50, y: 50), controlPoint2: CGPoint(x: 80, y: 80))
參考1.運用 UIBezierPath 繪製各種形狀
2.利用 CAShapeLayer製作圖層(C)
3.最後把 CAShapeLayer 加到 view 上(A)
讓路徑-線條( B )/圖層-紙張( C ),都能覆蓋於畫板( A )上
let circleLayer = CAShapeLayer()
circleLayer.path = path.cgPath應用1-填滿,內建為黑色
view.layer.addSublayer(circleLayer)
應用2-只有線條,需設定顏色/寬度
circleLayer.strokeColor = CGColor(Red: 10, green: 10, blue: 10, alpha: 1)
circleLayer.lineWidth = 10
view.layer.addSublayer(circleLayer)
4.進階調整- 讓View縮放/位移/旋轉/鏡像翻轉
1.縮放5倍
寫法1-View.transform = CGAffineTransform(scaleX: 5, y: 5)
寫法2-View.transform = CGAffineTransform.identity.scaledBy(x: 5, y: 5)2.位移
View.transform = CGAffineTransform(translationX: 10, y: 50)3.旋轉
let oneDegree = CGFloat.pi / 180
View.transform = CGAffineTransform(rotationAngle: oneDegree * 45)4.鏡像翻轉
View.transform = CGAffineTransform(scaleX: -1, y: 1)From:Peter的提醒
結合縮放,位移和旋轉值得注意的,結合縮放,位移和旋轉時,順序很重要,因為背後牽扯到矩陣的數學運算,所以先 translatedBy 再 scaledBy 跟先 scaledBy 再 translatedBy 是不一樣的,通常先 translatedBy 再 scaledBy 會是我們想要的效果。【寫法】
let oneDegree = CGFloat.pi / 180
View.transform = CGAffineTransform.identity.translatedBy(x: 100, y: 300).scaledBy(x: 0.5, y: 0.5).rotated(by: oneDegree * 45)
參考2.
*動畫(加在layer上)
動畫[到達終點]
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 5
.....Layer.add(animation, forKey: nil)重覆的動畫
animation.repeatCount = .greatestFiniteMagnitude清除線條的動畫效果[回到起點]
let animation = CABasicAnimation(keyPath: "strokeStart")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 5
.....Layer.add(animation, forKey: nil)
參考3.
*加入文字(使用mask)
本來想做個漸層文字,但有漸層,文字就跑掉,文字置中下方,就沒漸層
漸層與置中,不可兼得
import SwiftUI
struct DrawView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIView()
//circle
let circlepath = UIBezierPath(ovalIn: CGRect(x: 30, y: 160, width: 320, height: 320))
let circleLayer = CAShapeLayer()
circleLayer.path = circlepath.cgPath
circleLayer.fillColor=UIColor.systemPink.cgColor
circleLayer.strokeColor = CGColor(red: 220/255, green:100/255, blue: 100/255, alpha: 255)
circleLayer.lineWidth = 15
view.layer.addSublayer(circleLayer)
//love1
let love1view=UIView()
let love1path=UIBezierPath.init(roundedRect:CGRect(x: 340, y: -30, width: 100, height: 200),byRoundingCorners:[.topLeft,.topRight] ,cornerRadii: CGSize(width: 50, height: 0))
let love1Layer=CAShapeLayer()
love1Layer.path=love1path.cgPath
love1Layer.fillColor=UIColor.white.cgColor
love1view.layer.addSublayer(love1Layer)
let oneDegree = CGFloat.pi / 180
love1view.transform = CGAffineTransform(rotationAngle: oneDegree * 45)
//love2
let love2view=UIView()
let love2path=UIBezierPath.init(roundedRect:CGRect(x: -170, y: 240, width: 100, height: 200),byRoundingCorners:[.topLeft,.topRight] ,cornerRadii: CGSize(width: 50, height: 0))
let love2Layer=CAShapeLayer()
love2Layer.path=love2path.cgPath
love2Layer.fillColor=UIColor.white.cgColor
love2view.layer.addSublayer(love2Layer)
love2view.transform = CGAffineTransform(rotationAngle: oneDegree * -45)
view.addSubview(love1view)
view.addSubview(love2view)
//animation
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 5
animation.repeatCount = .greatestFiniteMagnitude
circleLayer.add(animation, forKey: nil)
//label
let lable=UILabel()
lable.text="iTalk"
lable.font=UIFont.systemFont(ofSize: 100)
lable.sizeToFit()
let lableview=UIView(frame:CGRect(x: 100, y: 500, width: 500, height: 500))
let gradientLayer=CAGradientLayer()
gradientLayer.frame=lableview.bounds
gradientLayer.colors=[UIColor.systemBlue.cgColor,UIColor.systemRed.cgColor]
lableview.layer.addSublayer(gradientLayer)
lableview.mask=lable
view.addSubview(lableview)
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
struct ContentView: View {
var body: some View {
DrawView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}