You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI实现登录页背景循环播放视频失败求助

SwiftUI登录页背景循环视频解决方案

问题根源

  1. 类型不匹配:Bundle.main.path(forResource:ofType:)返回的是字符串格式的文件路径,但AVPlayer(url:)要求传入URL类型参数,直接赋值会触发编译错误。
  2. 属性误用:@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 16:57:30