在撰寫本文時,我們還沒有一種直接的方法,可以在 SwiftUI 製作影片背景 (video background) 或影片播放器 (video player)。幸好,Apple 有提供 AVKit 和 AVFoundation,我們還是可以利用一個比較麻煩的方法來達到這個目的。
看完這篇教學後,你會得到以下的結果:
讓我們開始吧!
首先,打開你的專案,或是創建一個新的專案。為你的專案命名,並選擇 SwiftUI 為界面 (interface)。另外,我們還要指定一個以 com.<herecomesyourtext>
開頭的 Organization Identifier。
然後,你可以建立一個新的 Swift 檔案,或是打開一個現在的 Swift 檔案。在這個範例中,我們會使用以下這個已經設置好的 ContentView.swift
檔案。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
我們需要 import AVKit
和 AVFoundation
,來設置和播放影片。我們可以在基本的 import SwiftUI
下直接 import:
設置好之後,讓我們建立 UIViewRepresentable
型別的 PlayerView
:
struct PlayerView: UIViewRepresentable {
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
}
func makeUIView(context: Context) -> UIView {
return LoopingPlayerUIView(frame: .zero)
}
}
複製上面的程式碼到你的 ContentView
結構。
現在我們已經設置好 PlayerView
,接下來,我們要做的就是用影片「填滿」這個視圖,並重複播放!
在 PlayerView
結構下,讓我們創建 UIView
型別的 LoopingPlayerUIView
類型。以下是類別的完整程式碼:
class LoopingPlayerUIView: UIView {
private let playerLayer = AVPlayerLayer()
private var playerLooper: AVPlayerLooper?
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
// Load the resource -> h
let fileUrl = Bundle.main.url(forResource: "NAME OF VIDEO", withExtension: "TYPE OF VIDEO")!
let asset = AVAsset(url: fileUrl)
let item = AVPlayerItem(asset: asset)
// Setup the player
let player = AVQueuePlayer()
playerLayer.player = player
playerLayer.videoGravity = .resizeAspectFill
layer.addSublayer(playerLayer)
// Create a new player looper with the queue player and template item
playerLooper = AVPlayerLooper(player: player, templateItem: item)
// Start the movie
player.play()
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
}
在尋找及添加影片和影片的型別前,讓我們先把 PlayerView
添加到 ContentView
吧!
在 ContentView
中,刪走 Text(“Hello World”)
,並添加以下程式碼:
GeometryReader{ geo in
PlayerView()
.aspectRatio(contentMode: .fill)
.frame(width: geo.size.width, height: geo.size.height+100)
.edgesIgnoringSafeArea(.all)
.overlay(Color.black.opacity(0.2))
.blur(radius: 1)
.edgesIgnoringSafeArea(.all)
}
在上面的程式碼中,我們添加了一個 GeometryReader
,讓設定可以適用於不同裝置,並填滿螢幕。我們也為影片添加了一個 overlay 和模糊效果 (blur),讓使用者可以分辨影片和影片上的其他內容。
如你所見,我們在這裡用了 .edgesIgnoreSafeArea(.all)
修飾符 (modifier)。如果我們不用這個修飾符,影片的四邊就會留有 safe area。這樣可能是你想要的效果,但在這個範例中,我們想影片覆蓋整個螢幕。不過,你可以隨意試試 PlayerView()
的修飾符。
接下來,我們需要找一段影片作背景。在這個範例中,我在 Pexels 尋找縱向拍攝的視頻,選擇了這一段碰紅酒杯的影片來用於 App 內!
下載影片,然後拖放到我們的專案內,並設定 Add to targets:
留意影片的名稱和型別:
回到類別中尋找 fileUrl
,然後把 forResource
改成影片的名稱,withExtension
就改為影片的型別。以我們的範例來說,程式碼應該會是這樣:
let fileUrl = Bundle.main.url(forResource: "demoVideo", withExtension: "mp4")!
現在讓我們預覽內容,就可以看到我們的影片在播放,而且會自動重播!
如果你填錯了 fileUrl
,預覽就可能會出錯。如果是這樣,可以檢查影片的名稱和型別有沒有填錯,也要留意 Apple 是否支援影片的型別。
完成了!最後,我們可以把播放器添加到 ZStack
內。如此一來,就可以在播放器上加入其他內容:
struct ContentView: View {
var body: some View {
GeometryReader{ geo in
ZStack {
PlayerView()
.aspectRatio(contentMode: .fill)
.frame(width: geo.size.width, height: geo.size.height+100)
.overlay(Color.black.opacity(0.2))
.blur(radius: 1)
.edgesIgnoringSafeArea(.all)
VStack{
Text("Hello World")
.font(.title)
.foregroundColor(.white)
Spacer()
}
}
}
}
}
結果:
恭喜你完成了這篇教學!希望你可以利用新知識來建構更好的東西!
你可以在 GitHub 下載完整程式碼和專案。