SwiftUI实现登录页背景循环播放视频失败求助
SwiftUI登录页背景循环视频解决方案
问题根源
- 类型不匹配:
Bundle.main.path(forResource:ofType:)返回的是字符串格式的文件路径,但AVPlayer(url:)要求传入URL类型参数,直接赋值会触发编译错误。 - 属性误用:
@State是SwiftUI的状态管理包装器,不能用在UIView子类(PlayerUIView)中,属于无效API使用。
修正后的完整代码
import SwiftUI import AVKit struct VideoPlayerView: UIViewRepresentable { func updateUIView(_ uiView: UIView, context: Context) {} func makeUIView(context: Context) -> UIView { return PlayerUIView(frame: .zero) } } class PlayerUIView: UIView { private let playerLayer = AVPlayerLayer() override init(frame: CGRect) { super.init(frame: frame) // 直接获取视频文件URL,避免字符串转URL的麻烦 guard let videoURL = Bundle.main.url(forResource: "splash", withExtension: "mp4") else { print("无法找到视频文件") return } let player = AVPlayer(url: videoURL) // 设置视频结束后不自动暂停,方便循环 player.actionAtItemEnd = .none player.play() playerLayer.player = player playerLayer.videoGravity = .resizeAspectFill layer.addSublayer(playerLayer) // 监听视频播放结束事件,实现循环 NotificationCenter.default.addObserver( self, selector: #selector(playerItemDidReachEnd), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem ) } @objc private func playerItemDidReachEnd(notification: Notification) { guard let playerItem = notification.object as? AVPlayerItem else { return } playerItem.seek(to: .zero) { [weak self] _ in self?.playerLayer.player?.play() } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() playerLayer.frame = bounds } // 销毁时移除通知监听,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } } struct VideoPlayerView_Previews: PreviewProvider { static var previews: some View { VideoPlayerView() } }
关键修改说明
- 资源加载优化:用
Bundle.main.url(forResource:withExtension:)直接获取URL,既解决类型问题,又比路径字符串更安全。 - 移除无效属性:删除
PlayerUIView中的@State属性,UIKit类无需SwiftUI状态管理。 - 循环逻辑完善:添加
player.actionAtItemEnd = .none,并在播放结束回调中调用seek(to:)后重新播放,实现无缝循环。 - 内存安全:添加
deinit移除通知监听,避免内存泄漏。
使用方式
在你的登录界面View中,将VideoPlayerView作为底层背景,叠加登录控件即可:
struct LoginView: View { var body: some View { ZStack { VideoPlayerView() .ignoresSafeArea() // 你的登录控件(输入框、按钮等) VStack { TextField("账号", text: .constant("")) .padding() .background(Color.white.opacity(0.8)) Button("登录") {} .padding() .background(Color.blue) .foregroundColor(.white) } } } }
内容的提问来源于stack exchange,提问作者Seb
相关产品推荐
相关产品推荐

