#9 Xcode — 使用圖片/文字/emoji,加入邊框 & 圓角製作漂亮卡片
目錄
⦿ 去背
⦿ scaleAspectFit
⦿ 加入美美的畫面
⦿ Emoji
⦿ 不演了
去背
在 MAC 的預覽程式中,我們可以點擊右上角的 show Markup toolbar,再透過左上角的魔術棒去幫圖片去背:
在 Playground 中,生成 ImageView,將圖片放進去後會呈現如下:
當維尼
被加入歐巴馬
後,我們可以看到圖片呈現青色,但維尼卻不見了,這不代表維尼沒有被加進去,是加進去了,但呈現的範圍不正確,調整如下:
bearImageView.frame = obamaImageView.frame
如此一來,維尼就正常出現如下:
但由於寬度比例不一樣,維尼是比較瘦高的比例,所以此時歐巴馬的骨架更顯瘦了,我們試著切換兩張圖片的層級,跳出錯誤如下:
你總不能以你泥中有我,我泥中有你的概念來去改變圖片的 hierarchy,就好比 memory leak
是發生在 ARC 下,當兩個變數互相參考,即便釋放掉,最後記憶體也沒有空出來,造成記憶體空間越來越小。
不過在你正確把歐巴馬加到維尼身上後,沒去背的歐巴馬會完全擋住維尼。
scaleAspectFit
若希望歐巴馬正常顯示,會操作如下:
希望圖片的 scale 是維持它本來的比例,我們設定 Image View 的 contentMode 為 scaleAspectFit。
繼續閱讀|回目錄
加入美美的畫面
接著到專案裡,將圖片的大小設定為略小於螢幕寬度,並讓圖片置中。
右邊的預覽圖是在 UIKit 中,使用 UIViewControllerRepresentable,並實作兩個 function:makeUIViewController、updateUIViewController,接著就可以加入 ViewControllerView 來進行預覽了:
struct ViewControllerView_Previews: PreviewProvider {
static var previews: some View {
ViewControllerView()
.previewDevice("iPhone 11 Pro")
}
}
不過預覽的這個置中看起來不科學,等到 build 時看到如下:
正常了!幫這張照片加入方框讓它變成像框,不過顏色這時就很重要了,一不小心可能會像遺照。
接著調整透明度 .alpha 為 0.7,以免將來加入的 Emoji 不明顯,好了!前置作業完成。
繼續閱讀|回目錄
Emoji
var someLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
someLabel.font = UIFont.systemFont(ofSize: 50)
someLabel.text = "🇨🇳"
參考下面文章。
要讓 Emoji 位移跟縮放,最後圍繞在照片四周,我們會用到 CGAffineTransform
如下:
someLabel.transform =
CGAffineTransform(translationX: 10, y: 20) someLabel.transform = CGAffineTransform.identity.translatedBy(x: 10, y: 20).scaledBy(x: 1.5, y: 1.5) someLabel.transform =
CGAffineTransform(rotationAngle: someDegree * 45)
someLabel.transform = CGAffineTransform.identity.rotated(by: someDegree * 90).scaledBy(x: 1.5, y: 1.5)
someLabel.transform = CGAffineTransform.identity.scaledBy(x: 1.5, y: 1.5).translatedBy(x: 10, y: 20)
Affine Transform,仿射變換
,是在幾何中對圖像做各種移動,放大、縮小的處理,原理應是線性代數所謂的特徵值(Eigen Value)。
呼叫 CGAffineTranform
,更改裡面的參數,此時只能做到位移、旋轉在同一行的處理,若想一起處理的話會這樣操作:CGAffineTransform.identity.translatedBy(x:y:).scaleBy(x:y:).rotated(by: someDegree * 90)
一般來說,先位移、縮放,再去做旋轉的動作,比較容易做 rendering 的追蹤、管控。
當我們將 Emoji 做為素材,就可用跑迴圈的方式去做到仿射變換
,複製多個 Emoji 素材,讓它最終環繞在像框四周,如下:
雖然可以透過 CGAffineTransform.identity 去做仿射變換
的連續處理,但這樣一來程式碼就會變得不太容易讀,我們透過 extension UIView 增加一些 function 如下:
extension UIView {
func translatedBy(x: CGFloat, y: CGFloat) {
self.transform = self.transform.translatedBy(x: x, y: y)
}
func scaledBy(x: CGFloat, y: CGFloat) {
self.transform = self.transform.scaledBy(x: x, y: y)
}
func rotated(by angle: CGFloat) {
self.transform = self.transform.rotated(by: angle)
}
}
接著程式碼就可以進一步優化為:
let aDegree = CGFloat.pi / 180
var count = 0
for i in 1...5 {
for j in 1...5 {
if i == 1 || i == 5 || j == 1 || j == 5 {
count = count + 4
emojiLabel = UILabel(frame: CGRect(x: -50,
y: -60,
width: 30,
height: 30))
emojiLabel.text = "🇨🇳"
obamaImgView.addSubview(emojiLabel)
emojiLabel.translatedBy(
x: (obamaImgView.bounds.width / 5) * CGFloat(i),
y: (obamaImgView.bounds.height / 5) * CGFloat(j)
)
emojiLabel.scaledBy(x: 1.5, y: 1.5)
emojiLabel.rotated(by: (aDegree * 11.25 * CGFloat(count)))
}
}
}
成果如下:
如果要說初衷是仿製賈伯斯在時代雜誌的封面的話,是否有點說不過去呀?還是我真沒有什麼美術天份。