筆記:運用 UIBezierPath、CAShapeLayer繪製簡易圖形

目標

  • 藉由SwiftUI 來繪製簡易圖形。
  • 理解UIBezierPath路徑的繪製、CAShapeLayer 的運用。
  • 總覺得要使自己的App好看一些的話,這個UIBezierPath、CAShapeLayer的運用還是蠻重要的,藉由這個筆記來梳理自己的觀念。
  • shadowRadius 陰影添加 (新增補充)

繪製形狀三步驟:

  • UIBezierPath 繪製形狀的路徑。
  • 運用 CAShapeLayer,使 UIBezierPath 的路徑形狀顯示出來。
  • 利用 addSublayer 加入 CAShapeLayer。

UIKit和Core Graphics中的座標系統的不同

  • 因為 UIBezierPath (Core Graphics的座標系統)以左下為原點 (0,0),x & y 愈向右和愈向上愈大。
  • 但 iOS App 的 View 元件則以左上為原點,x & y 愈向右和愈向下愈大。
  • 可以使用CAShapeLayer或UIView來渲染UIBezierPath,並且需要在進行渲染之前進行坐標系統轉換,以將座標系統從Core Graphics轉換為UIKit。到時候呈現的結果將變成以左上為原點繪製。

練習UIBezierPath:三角形

  • UIBezierPath是一個Core Graphics類別,它提供了一個簡單的方式來創建和管理向量圖形,例如線條、曲線、多邊形和矩形等等。並可以設置繪圖筆刷的屬性,例如線條寬度、顏色、填充顏色等等。
  • 使用UIBezierPath可以創建複雜的形狀,並且可以隨時修改形狀。例如,您可以創建一個簡單的圓形,然後在它的周圍畫一些曲線和線條,最後使用填充顏色來填充整個形狀。同時還提供了一些其他功能,例如裁剪形狀、擦除形狀、渲染形狀等等。
  • 總之,UIBezierPath是一個用於創建和管理向量圖形的類別,它可以用來創建複雜的形狀,並可以隨時修改形狀。當您創建好一個形狀後,可以使用CAShapeLayerUIView來顯示它。
三角形UIBezierPath以及CAShapeLayer的運用
  • 生成UIBezierPath()
  • 設定要下筆的起始點(這邊以(0,0)爲原點),接著運用.move 移動到該位置。
  • 接著再標定下一個點(150,0) 在透過.addLine(0,0)畫到(150,0)的位置。
  • 最後由.close 即可返回起始點,達到封閉型態的三角形。
  • 另一個方式,運用 move & addLine 的 ( ) 裡直接生成 CGPoint。
// 練習1
let trianglePath = UIBezierPath()
var trianglePoint = CGPoint(x: 0, y: 0)
trianglePath.move(to: trianglePoint)
trianglePoint = CGPoint(x: 150, y: 0)
trianglePath.addLine(to: trianglePoint)
trianglePoint = CGPoint(x: 150, y: 150)
trianglePath.addLine(to: trianglePoint)
trianglePath.close()

// 練習2
let trianglePath = UIBezierPath()
trianglePath.move(to: CGPoint(x: 0, y: 0))
trianglePath.addLine(to: CGPoint(x: 150, y: 0))
trianglePath.addLine(to: CGPoint(x: 150, y: 150))
trianglePath.close()

練習CAShapeLayer()

  • CAShapeLayer是一個Core Animation類別,它可以用來顯示和管理簡單的形狀,如線條、矩形、橢圓、多邊形和曲線等。
  • CAShapeLayer使用一個CGPath對象來描述形狀,而這個CGPath對象可以使用UIBezierPath創建。
  • 因此,當您使用UIBezierPath繪製一個形狀後,可以使用CAShapeLayer來顯示這個形狀,而且CAShapeLayer可以自動處理座標系統轉換,以確保在UIKit中正確顯示形狀。
  • CAShapeLayer還提供了一些其他的功能,如線條端點和線條連接處的樣式、線條寬度、填充顏色等等。
  • 可以自動處理座標系統轉換,使形狀在UIKit中正確顯示。
fillColor填滿色彩
  • UIBezierPath() 模擬出路徑形狀之後,在透過 CAShapeLayer() 來賦予形狀的產生。
  • 讓trianglePath有一個cgPath屬性,使其讀取 CGPath 型別的三角形路徑後再存入 triangleSharpLayer.path。
  • 運用fillColor 給形狀填滿色彩,fillColorCGColor 型別。
  • 最後將 CAShapeLayer 加到 view 上。

let trianglePath = UIBezierPath()
trianglePath.move(to: CGPoint(x: 0, y: 0))
trianglePath.addLine(to: CGPoint(x: 150, y: 0))
trianglePath.addLine(to: CGPoint(x: 150, y: 150))
trianglePath.close()

// CAShapeLayer、fillColor
let triangleSharpLayer = CAShapeLayer()
triangleSharpLayer.path = trianglePath.cgPath
triangleSharpLayer.fillColor = CGColor(red: 1, green: 0, blue: 0, alpha: 1)
view.layer.addSublayer(triangleSharpLayer)

CAShapeLayer()線條繪製(strokeColor、lineWidth)

  • strokeColor:用於設置形狀的輪廓線(stroke)的顏色。輪廓線是形狀的邊緣線,可以通過調整線條寬度、顏色和繪製方式等屬性來定制形狀的輪廓線樣式。
  • lineWidth:預設是1.0,爲了讓strokeColor更粗,所以這邊在設置其粗度5.0。
        let triangleSharpLayer = CAShapeLayer()
triangleSharpLayer.path = trianglePath.cgPath
triangleSharpLayer.strokeColor = CGColor(red: 0, green: 1, blue: 0, alpha: 1)
triangleSharpLayer.lineWidth = 5
view.layer.addSublayer(triangleSharpLayer)
  • 如上圖三角形的填充色是黑色的,因為 CAShapeLayer 預設會填滿黑色。
  • 只有線條:將 fillColor 設為代表透明的 clear color 使填充色移除。
        let triangleSharpLayer = CAShapeLayer()
triangleSharpLayer.path = trianglePath.cgPath
triangleSharpLayer.fillColor = UIColor.clear.cgColor
triangleSharpLayer.strokeColor = CGColor(red: 0, green: 1, blue: 0, alpha: 1)
triangleSharpLayer.lineWidth = 5
view.layer.addSublayer(triangleSharpLayer)
  • 單純線條繪製:不要使繪製路徑close。並將fillColor的色彩去除掉。
// 單純線條繪製
let trianglePath = UIBezierPath()
trianglePath.move(to: CGPoint(x: 30, y: 30))
trianglePath.addLine(to: CGPoint(x: 150, y: 30))
trianglePath.addLine(to: CGPoint(x: 150, y: 150))

let triangleSharpLayer = CAShapeLayer()
triangleSharpLayer.path = trianglePath.cgPath
triangleSharpLayer.fillColor = UIColor.clear.cgColor
triangleSharpLayer.strokeColor = CGColor(red: 0, green: 1, blue: 0, alpha: 1)
triangleSharpLayer.lineWidth = 5
view.layer.addSublayer(triangleSharpLayer)

UIView 以及 CAShapeLayer

  • 都是iOS中常用的視圖元件,但它們具有不同的功能和特點。
  • UIView:用於構建界面和處理用戶交互事件,可以容納其他視圖元件。例如UILabel,UIButton等等,並且可以通過代碼或Storyboard進行設置和排版。
  • UIView還可以繼承並定義自己的子類別,以實現自定義的UI元素。與CAShapeLayer不同,UIView並不是專門用來顯示形狀的,但是它可以用來顯示UIBezierPath創建的形狀。
  • UIView上顯示UIBezierPath時,需要使用Core Graphics庫中的方法進行座標系統轉換,以確保在UIKit中正確顯示形狀。
  • UIView更適合用來顯示較複雜的UI元素,例如按鈕、文本框、圖像等等。
  • CAShapeLayerCALayer的一種子類,用於繪製2D圖形。CAShapeLayer可以用於繪製任何形狀,包括矩形、圓形、多邊形、曲線等等。使用CAShapeLayer可以創建矢量圖形,它們可以縮放而不會失去清晰度,因此非常適合用於繪製高品質的圖形。
  • 總體而言,UIView用於構建界面和處理用戶交互事件,而CAShapeLayer用於繪製2D圖形,包括自定義形狀和輪廓線。
分別添加CAShapeLayer以及UIView
  • 依序使用CAShapeLayer 添加綠色三角形、藍色四方形,以及UIView 添加黃色四方形,越後面添加的就會處於畫面的越上層的位置,也因此黃色四方形的UIView的程式碼處於最下方。
  • CAShapeLayer 運用 addSublayer 來使其圖型添加到畫面上。
  • UIView 則是 addSubview 的運用來添加到畫面上。
        // 三角形
let trianglePath = UIBezierPath()
trianglePath.move(to: CGPoint(x: 0, y: 0))
trianglePath.addLine(to: CGPoint(x: 150, y: 0))
trianglePath.addLine(to: CGPoint(x: 150, y: 150))
trianglePath.close()

let triangleSharpLayer = CAShapeLayer()
triangleSharpLayer.path = trianglePath.cgPath
triangleSharpLayer.fillColor = UIColor.clear.cgColor
triangleSharpLayer.strokeColor = CGColor(red: 0, green: 1, blue: 0, alpha: 1)
triangleSharpLayer.lineWidth = 10
view.layer.addSublayer(triangleSharpLayer)

// 四方形
let squarePath = UIBezierPath()
squarePath.move(to: CGPoint(x: 80, y: 80))
squarePath.addLine(to: CGPoint(x: 170, y: 80))
squarePath.addLine(to: CGPoint(x: 170, y: 170))
squarePath.addLine(to: CGPoint(x: 80, y: 170))
squarePath.close()

let squareSharpLayer = CAShapeLayer()
squareSharpLayer.path = squarePath.cgPath
squareSharpLayer.fillColor = CGColor(red: 0, green: 1, blue: 1, alpha: 1)
view.layer.addSublayer(squareSharpLayer)

// 黃色UIView
let yellowView = UIView(frame: CGRect(x: 100, y: 50, width: 100, height: 100))
yellowView.backgroundColor = UIColor.yellow
view.addSubview(yellowView)

繪製彎曲的曲線

  • 在繪製貝塞爾曲線時,需要指定曲線的起點、終點和控制點。二次貝塞爾曲線有一個控制點,它通過控制點來調整曲線的形狀。
  • 它會在當前路徑的最後一個點和指定終點之間繪製一條二次貝塞爾曲線,曲線的形狀可以通過控制點來調整。
  • addQuadCurve(to:controlPoint:)方法接受兩個參數,分別是 endPoint(終點)和controlPoint(控制點)。
左圖:controlPoint: CGPoint(x: 200, y: 100) / 右圖:controlPoint: CGPoint(x: 100, y: 100)
  • 在相同的起點、終點之下,controlPoint的位置,控制曲線的弧度的差異展示。
// 左圖
let curvePath = UIBezierPath()
curvePath.move(to: CGPoint(x: 50, y: 50))
curvePath.addQuadCurve(to: CGPoint(x: 50, y: 150), controlPoint: CGPoint(x: 200, y: 100))

// 右圖
let curvePath = UIBezierPath()
curvePath.move(to: CGPoint(x: 50, y: 50))
curvePath.addQuadCurve(to: CGPoint(x: 50, y: 150), controlPoint: CGPoint(x: 100, y: 100))

以下為繪製完成的曲線:

  • 左圖:未將fillColor的填充色給清除掉(UIColor.clear.cgColor)
  • 右圖:運用clear之後,線條即可完成顯示。
       // 曲線繪製
let curvePath = UIBezierPath()
curvePath.move(to: CGPoint(x: 50, y: 50))
curvePath.addQuadCurve(to: CGPoint(x: 50, y: 150), controlPoint: CGPoint(x: 100, y: 100))

let curveSharpLayer = CAShapeLayer()
curveSharpLayer.path = curvePath.cgPath
curveSharpLayer.strokeColor = UIColor.black.cgColor
curveSharpLayer.lineWidth = 5
curveSharpLayer.fillColor = UIColor.clear.cgColor
view.layer.addSublayer(curveSharpLayer)

三次貝塞爾曲線 addCurve(to:controlPoint1:controlPoint2:)

對於這個曲線真的頭超痛的XD

  • addCurve(to:controlPoint1:controlPoint2:)方法接受三個參數,分別是終點和兩個控制點。
  • 它會在當前路徑的最後一個點和指定終點之間繪製一條三次貝塞爾曲線,兩個控制點則用來調整曲線的形狀。
  • 簡單來說,使用addCurve(to:controlPoint1:controlPoint2:)方法可以在UIBezierPath中繪製一條曲線,曲線的形狀可以通過兩個控制點來調整。
由兩個 controlPoint 控制

詢問ChatGPT繪製這個曲線時有什麼思考方式:

  • 通常,我們會先畫出曲線的起點和終點,再決定控制點的位置和數量,最後再用程式碼實現。
  • 需要注意的是,曲線的控制點和終點的座標值都是相對於曲線起點的坐標值,因此在設定控制點和終點的座標時,需要加上曲線起點的坐標。
  • 總結來說,對於 addCurve(to:controlPoint1:controlPoint2:) 的曲線繪製思考邏輯,建議可以先畫出曲線的草圖,決定需要幾個控制點,再根據草圖上的特徵和曲線走向,決定控制點的位置和數量,最後用程式碼實現。
先透過這次的練習來初步了解兩個控制點怎麼抓
        // 三次貝塞爾曲線
let cubicBezierCurvePath = UIBezierPath()
cubicBezierCurvePath.move(to: CGPoint(x: 100, y: 100))
cubicBezierCurvePath.addCurve(to: CGPoint(x: 100, y: 300), controlPoint1: CGPoint(x: 50, y: 200), controlPoint2: CGPoint(x: 200, y: 200))

let cubicBezierCurveSharpLayer = CAShapeLayer()
cubicBezierCurveSharpLayer.path = cubicBezierCurvePath.cgPath
cubicBezierCurveSharpLayer.strokeColor = UIColor.black.cgColor
cubicBezierCurveSharpLayer.lineWidth = 3
cubicBezierCurveSharpLayer.fillColor = UIColor.clear.cgColor
view.layer.addSublayer(cubicBezierCurveSharpLayer)

繪製剛好在圓上的圓弧

  • 這個方法不是直接繪製一個完整的圓形,而是在圓周上繪製一個弧形。透過指定圓心、半徑、起始角度、結束角度以及是否為順時針方向繪製弧形。可以利用這個方法繪製圓形、圓弧等圖形。
  • init(arcCenter:radius:startAngle:endAngle:clockwise:)UIBezierPath 的一個初始化方法,用來創建一個圓弧路径。

它的參數分別為:

  • arcCenter:圓弧所在圓的圓心位置。
  • radius:圓弧所在圓的半徑。
  • startAngle:起始角度,以弧度表示,值域為 0 到 2π。
  • endAngle:結束角度,以弧度表示,值域為 0 到 2π。
  • clockwise:是否為順時針方向,true 表示順時針,false 表示逆時針。
  • 使用此方法,可以在 UIBezierPath 中創建一個圓弧的路径,然後可以將其用於繪製或裁剪等操作。
startAngle: 0endAngle: CGFloat.pi 、順時針繪製
  • 透過將 startAngle: 0endAngle: CGFloat.pi 來繪製半圓。
  • 這邊設置 clockwisetrue是順時針方向,如果今天是逆時針的話則半圓會位於上半部。
        let drawArcFromCirclePath = UIBezierPath(arcCenter: CGPoint(x: 200, y: 200), radius: 60, startAngle: 0, endAngle: CGFloat.pi, clockwise: true)

let drawArcFromCircleSharpLayer = CAShapeLayer()
drawArcFromCircleSharpLayer.path = drawArcFromCirclePath.cgPath
view.layer.addSublayer(drawArcFromCircleSharpLayer)

ChatGPT解釋:startAngle 和 endAngle

  • init(arcCenter:radius:startAngle:endAngle:clockwise:) 方法中的兩個參數,它們用來指定弧線的起始角度和結束角度,單位都是弧度。弧度是一種角度單位,表示從圓心到圓周上的一點的弧長與圓的半徑之比。
  • init(arcCenter:radius:startAngle:endAngle:clockwise:) 方法中,startAngleendAngle 的值範圍都是 0 到 2π,其中 0 表示圓周的最右側,π 表示圓周的最左側。
  • clockwise 參數用於指定畫圓的方向,true 表示順時針方向,false 表示逆時針方向。因此,可以使用這個方法來繪製一個圓弧或扇形,也可以使用 close() 方法來將其封閉並繪製出一個完整的圓形。

繪製特定角度的圓弧以及形狀

  • 此方法是形狀填滿顏色時將以圓弧和圓弧兩端點連線包含的區塊,並非從圓心出發。
  • 先設置一個常數let aDegree = CGFloat.pi / 180 取得1度的值比較方便
  • 左圖:逆時針繪製一個起始角度0到130度的圓弧。
  • 右圖:順時針繪製一個起始角度0到130度的圓弧。
        let aDegree = CGFloat.pi / 180
let drawArcFromCirclePath = UIBezierPath(arcCenter: CGPoint(x: 200, y: 200), radius: 80, startAngle: 0, endAngle: aDegree * 130, clockwise: false)

let drawArcFromCircleSharpLayer = CAShapeLayer()
drawArcFromCircleSharpLayer.path = drawArcFromCirclePath.cgPath
view.layer.addSublayer(drawArcFromCircleSharpLayer)

從圓心連到圓弧兩端點的扇形addArc(withCenter:radius:startAngle:endAngle:clockwise:)

若想畫出從圓心連到圓弧兩端點的扇形,則須先用 move 移動到圓心,然後再呼叫 addArc(withCenter:radius:startAngle:endAngle:clockwise:) 加入圓弧。

  • withCenter:弧形的圓心位置,是一個 CGPoint 類型的值。
  • radius:弧形的半徑長度,是一個 CGFloat 類型的值。
  • startAngle:弧形的起始角度,以弧度表示,值域為 0 到 2π。其中,0 表示圓周的最右側,π/2 表示圓周的最上方,π 表示圓周的最左側,3π/2 表示圓周的最下方。
  • endAngle:弧形的結束角度,以弧度表示,值域為 0 到 2π。同樣地,0 表示圓周的最右側,π/2 表示圓周的最上方,π 表示圓周的最左側,3π/2 表示圓周的最下方。
  • clockwise:指定繪製圓弧時的方向,true 表示順時針方向,false 表示逆時針方向。
左:逆時針 / 右:順時針
  • 記得先設置move 將筆給移到中心點,才可以開始設置.addArc 來進行繪製
        // 從圓心連到圓弧兩端點的扇形        
let aDegree = CGFloat.pi / 180
let centerOfcrclePath = UIBezierPath()
centerOfcrclePath.move(to: CGPoint(x: 200, y: 200))
centerOfcrclePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 60, startAngle: 0, endAngle: aDegree * 130, clockwise: false)

let centerOfcrcleSharpLayer = CAShapeLayer()
centerOfcrcleSharpLayer.path = centerOfcrclePath.cgPath
view.layer.addSublayer(centerOfcrcleSharpLayer)
  • 以下為設置close,同時將其fillColor給clear。這樣的狀態下可以更好理解其繪製路徑的產生,是由圓心開始出發繪製endAngle 接著到 endAngle
  • 沒有從圓心繪製時也是一樣,如果想要封閉必須要在添加close,只是它是直接由圓弧的兩個點startAngle 繪線至 endAngle
左:沒有close / 右: close
        let aDegree = CGFloat.pi / 180
let centerOfcrclePath = UIBezierPath()
centerOfcrclePath.move(to: CGPoint(x: 200, y: 200))
centerOfcrclePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 60, startAngle: 0, endAngle: aDegree * 130, clockwise: false)
centerOfcrclePath.close()

let centerOfcrcleSharpLayer = CAShapeLayer()
centerOfcrcleSharpLayer.path = centerOfcrclePath.cgPath
centerOfcrcleSharpLayer.strokeColor = UIColor.red.cgColor
centerOfcrcleSharpLayer.lineWidth = 2
centerOfcrcleSharpLayer.fillColor = UIColor.clear.cgColor
view.layer.addSublayer(centerOfcrcleSharpLayer)

馬蹄形練習

  • 在添加兩個圓弧時,如果起始角度和結束角度相同,且兩個圓弧的方向相同,則它們將相互抵消,無法形成弧線,最終得到的是兩條直線。
  • 因此,為了形成馬蹄形,需要使內部圓弧的方向與外部圓弧的方向相反。這樣兩個圓弧就不會相互抵消,而是能夠形成一個圓弧和一個彎曲的形狀,從而呈現出馬蹄形的形狀。
  • startAngleendAngleclockwise的設定,會使繪製出來的圖型產生不同結果
  • 左:大圓與小圓的起始角度、結束角度、繪製起始方向,完全相反因此可以得到一個馬蹄形。
  • 右:大圓與小圓的起始角度、結束角度相相反,但兩個都是逆時針去繪製導致open醬的出現XD
        //練習馬蹄形,要繪製馬蹄形的話,圓心位置是相同的,只是半徑大小不同而已
let aDegree = CGFloat.pi / 180
let horseShoePath = UIBezierPath()
// 繪製比較大的外圓弧,從 (120, 200) 到 (280, 200)
horseShoePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 80, startAngle: 0, endAngle: aDegree * 180, clockwise: false)
// 繪製比較小的內圓弧,從 (160, 200) 到 (240, 200)
horseShoePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 40, startAngle: aDegree * 180, endAngle: 0, clockwise: true)
horseShoePath.close()

let horseShoeSharpLayer = CAShapeLayer()
horseShoeSharpLayer.path = horseShoePath.cgPath
horseShoeSharpLayer.strokeColor = UIColor.black.cgColor
horseShoeSharpLayer.fillColor = UIColor.red.cgColor
view.layer.addSublayer(horseShoeSharpLayer)
  • 左圖:大圓、小圓起始以及結束角度,都是一模一樣,只有繪製方向不同。
  • 右圖:兩圓的起始、結束、繪製方向完全一樣,因此無法做到半空心的馬蹄形。

// 左圖
let aDegree = CGFloat.pi / 180
let horseShoePath = UIBezierPath()
// 繪製比較大的外圓弧,從 (120, 200) 到 (280, 200)
horseShoePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 80, startAngle: 0, endAngle: aDegree * 180, clockwise: false)
// 繪製比較小的內圓弧,從 (160, 200) 到 (240, 200)
horseShoePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 40, startAngle: 0, endAngle: aDegree * 180, clockwise: true)
horseShoePath.close()



// 右圖
let aDegree = CGFloat.pi / 180
let horseShoePath = UIBezierPath()
// 繪製比較大的外圓弧,從 (120, 200) 到 (280, 200)
horseShoePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 80, startAngle: 0, endAngle: aDegree * 180, clockwise: false)
// 繪製比較小的內圓弧,從 (160, 200) 到 (240, 200)
horseShoePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 40, startAngle: 0, endAngle: aDegree * 180, clockwise: false)
horseShoePath.close()

合併 path 繪製多個形狀

  • 想繪製的多個形狀是同一個樣式,也可以用一個 UIBezierPath & CAShapeLayer 繪製,而不用分成多個。
  • 實現多個形狀共用同一個圖層的效果,減少了圖層的數量,也方便管理和修改。

使用一個 UIBezierPathCAShapeLayer 繪製多個形狀的優點在於:

  • 減少了代碼量:使用同一個 UIBezierPath 可以減少重複的代碼,減少了代碼量,提高了代碼的可讀性。
  • 更好的性能:使用同一個 CAShapeLayer 繪製多個形狀,可以減少 UIView 的子視圖數量,減少內存佔用,提高了性能。
  • 更好的動畫效果:使用同一個 CAShapeLayer 可以讓動畫更加流暢,因為只有一個圖層需要被更新。

缺點在於:

  • 無法單獨控制每個形狀:因為使用的是同一個 UIBezierPathCAShapeLayer,所以無法單獨控制每個形狀的樣式和位置,一旦需要修改其中一個形狀,就需要重新繪製所有的形狀。
  • 設置起來可能較複雜:使用這種方法需要在 UIBezierPath 上設置多個子路徑,需要在添加新的形狀時注意畫筆的起始位置,可能較複雜。
        // 共用圖層
// 三角形1
let trianglePath = UIBezierPath()
trianglePath.move(to: CGPoint(x: 30, y: 30))
trianglePath.addLine(to: CGPoint(x: 150, y: 30))
trianglePath.addLine(to: CGPoint(x: 150, y: 150))
trianglePath.close()

// 三角形2
trianglePath.move(to: CGPoint(x: 20, y: 40))
trianglePath.addLine(to: CGPoint(x: 170, y: 40))
trianglePath.addLine(to: CGPoint(x: 170, y: 170))
trianglePath.close()

// 三角形3
trianglePath.move(to: CGPoint(x: 70, y: 70))
trianglePath.addLine(to: CGPoint(x: 0, y: 140))
trianglePath.addLine(to: CGPoint(x: 70, y: 140))
trianglePath.close()

let triangleSharpLayer = CAShapeLayer()
triangleSharpLayer.path = trianglePath.cgPath
triangleSharpLayer.fillColor = UIColor.clear.cgColor
triangleSharpLayer.strokeColor = CGColor(red: 0, green: 1, blue: 0, alpha: 1)
triangleSharpLayer.lineWidth = 5
view.layer.addSublayer(triangleSharpLayer)

shadowRadius 陰影

添加陰影
  • shadowOpacity: 設置陰影的不透明度,取值範圍為 0.0 到 1.0。shadowColor: 設置陰影的顏色。它是 CGColor 類型的對象。設置為 UIColor.black.cgColor,表示陰影的顏色為黑色。
  • shadowRadius: 設置陰影的模糊半徑。值越大,陰影就越模糊,值越小,陰影就越清晰。

這些屬性的設置使得 CAShapeLayer 上的馬蹄形圖形具有陰影效果。陰影會以圖形的外部形狀為基礎,根據設置的屬性值呈現出對應的陰影效果。

        //練習馬蹄形,要繪製馬蹄形的話,圓心位置是相同的,只是半徑大小不同而已
let aDegree = CGFloat.pi / 180
let horseShoePath = UIBezierPath()
// 繪製比較大的外圓弧,從 (120, 200) 到 (280, 200)
horseShoePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 80, startAngle: 0, endAngle: aDegree * 180, clockwise: false)
// 繪製比較小的內圓弧,從 (160, 200) 到 (240, 200)
horseShoePath.addArc(withCenter: CGPoint(x: 200, y: 200), radius: 40, startAngle: aDegree * 180, endAngle: 0, clockwise: true)
horseShoePath.close()

// 創建 CAShapeLayer
let horseShoeSharpLayer = CAShapeLayer()
horseShoeSharpLayer.path = horseShoePath.cgPath
horseShoeSharpLayer.strokeColor = UIColor.black.cgColor
horseShoeSharpLayer.fillColor = UIColor.red.cgColor

// 添加陰影效果
horseShoeSharpLayer.shadowOpacity = 0.5
horseShoeSharpLayer.shadowColor = UIColor.black.cgColor
horseShoeSharpLayer.shadowRadius = 10

view.layer.addSublayer(horseShoeSharpLayer)

參考

--

--

wei Tsao 學習紀錄
彼得潘的 Swift iOS / Flutter App 開發教室

Hi ! 我是wei , 先前未接觸過程式開發設計,想藉此來記錄自己的學習歷程,以利培養自己的程式邏輯 :)