我們目前正進行一個新系列的教學,主要回答一些常見問題,從簡單的初學者問題、到複雜的進階問題亦會覆蓋到。今天我們的問題是:
我知道如何在視圖 (View) 或按鈕 (Button) 上設定圓角 (Rounded Corners)。但如果我只想設定某一角為圓角,並非所有角都設定為圓角,要如何在 Swift 實現呢?
好的,先回看一下如何在視圖設定圓角,Apple 簡化了建立圓角視圖的步驟,你所需要做的就只是設定視圖圖層 (Layer) 中 cornerRadius 的屬性,並將 clipsToBounds 設為 true。請參考以下的程式碼:
self.view.layer.cornerRadius = 20.0 self.view.clipToBounds = true
為了看到實作的結果,你可以建立一個 Playgrounds 專案,並輸入下列程式碼:
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
var cardView: UIView!
override func loadView() {
let view = UIView()
view.backgroundColor = .black
cardView = UIView()
view.addSubview(cardView)
cardView.translatesAutoresizingMaskIntoConstraints = false
cardView.widthAnchor.constraint(equalToConstant: 200).isActive = true
cardView.heightAnchor.constraint(equalToConstant: 200).isActive = true
cardView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
cardView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
cardView.backgroundColor = UIColor(red: 1.0, green: 0.784, blue: 0.2, alpha: 1.0)
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
cardView.roundCorners(cornerRadius: 20.0)
}
}
extension UIView {
func roundCorners(cornerRadius: Double) {
self.layer.cornerRadius = CGFloat(cornerRadius)
self.clipsToBounds = true
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
切換到 Asssistant Editor 模式,你應該可以看到視圖如下圖一樣,是一個有圓角的黃色視圖。

很簡單吧!但這個視圖所有角都是圓角,如果你並不想把所有角都設定成圓角呢?譬如說,你只想把上方兩個角設定成圓角,要怎樣做呢?
在 iOS 11 使用 maskedCorners
在 iOS 11,Apple 為 Core Animation Layer (CALayer) 推出了一個新的屬性 maskedCorners,這個屬性屬於 CACornerMask 型別,並包含 4 個屬性值:
layerMaxXMaxYCorner– 右下角layerMaxXMinYCorner– 右上角layerMinXMaxYCorner– 左下角layerMinXMinYCorner– 左上角
maskedCorners 的默認屬性為顯示全部四個角,現在如果你只想設定上面兩個角為圓角,你可以這麼設定 maskedCorners:
self.view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
如果你依照下文修改了 roundCorners 方法,就可以只把黃色視圖上方兩個角設定成圓角。
func roundCorners(cornerRadius: Double) {
self.layer.cornerRadius = CGFloat(cornerRadius)
self.clipsToBounds = true
self.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
}
在 iOS 10 或以下的版本使用 Bezier 路徑
剛討論的方法目前僅能支援 iOS 11 以上的版本,如果你的 App 需要支援之前的 iOS 版本,就不能使用 maskedCorners 屬性。
這裡來介紹另一種方式來替代 maskedCorners。我們可以使用 UIBezierPath 來建立圓角矩形路徑,這樣初始化 UIBezierPath,我們就可以設定某個特定的角為圓角:
let path = UIBezierPath(roundedRect: view.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 10.0, height: 10.0))
依著路徑,我們可以來建立一個形狀圖層作為 Mask,請依下文更新 roundCorners 的方法:
func roundCorners(cornerRadius: Double) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: cornerRadius, height: cornerRadius))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = path.cgPath
self.layer.mask = maskLayer
}
我們建立了一個上方兩個角為圓角的 Mask,然後設定了視圖圖層的 mask 屬性來覆蓋內容。這樣我們就可以在 iOS 10 或以下的版本,來設定視圖與按鈕特定一個角為圓角了。
請留意當視圖出現時,可能出現的 Rendering(渲染)現象。你需要在 viewDidAppear() 或 viewDidLayoutSubviews() 內呼叫 roundCorners 方法:
override func viewDidLayoutSubviews() {
cardView.roundCorners(cornerRadius: 20.0)
}
成果應如下圖所顯示:

利用動畫展示角的變化
有些讀者可能會想知道如何利用動畫展示角的變化,你可以使用 UIView 動畫或是新的 UIViewPropertyAnimator 來製作。
譬如說,你想製作一個動畫,當使用者點擊方形視圖時,角就會有變化。首先,你需要在 viewDidLoad() 登記一個點擊辨識:
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(animateCornerChange(recognizer:))) cardView.addGestureRecognizer(tapRecognizer)
接著,如此建立一個 animateCornerChange 方法:
@objc func animateCornerChange(recognizer: UITapGestureRecognizer) {
let targetRadius: CGFloat = (cardView.layer.cornerRadius == 0.0) ? 100.0 : 0.0
UIViewPropertyAnimator(duration: 1.0, curve: .easeInOut) {
self.cardView.layer.cornerRadius = targetRadius
}.startAnimation()
}
在以上的程式碼,我們使用 UIViewPropertyAnimator 來建立動畫;你亦可以使用標準 UIView 動畫來展示角的變化:
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveEaseInOut, animations: {
self.cardView.layer.cornerRadius = targetRadius
}, completion: nil)
如果你已經在 Playground 專案更新程式碼,點擊視圖後會啟動動畫。

本次的教學就到這裡。請密切留意我們的專頁,我們會陸續更新文章。歡迎你就這個新系列留言提出想法。
原文:How to Create Top/Bottom Rounded Corners for Views and Buttons