我們目前正進行一個新系列的教學,主要回答一些常見問題,從簡單的初學者問題、到複雜的進階問題亦會覆蓋到。今天我們的問題是:
我知道如何在視圖 (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