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

SwiftUI技术问题:如何将ContentView的selectedIndex传递给LoopingPlayerUIView类

问题分析与解决方案

你之前创建myView = ContentView()的方式完全无效,因为这个myView是全新的ContentView实例,和界面上正在显示的ContentView没有任何关联,它的selectedIndex永远是初始值0,自然无法响应真实的Tab切换操作。

下面是正确的实现方案:


步骤1:重构LoopingPlayerUIView,暴露播放控制接口

先把播放器改成实例属性,方便外部控制,同时添加专门的方法来根据selectedIndex更新播放状态:

import UIKit
import AVKit

class LoopingPlayerUIView: UIView {
    private let playerLayer = AVPlayerLayer()
    private var playerLooper: AVPlayerLooper?
    private var player: AVQueuePlayer? // 改为实例属性,方便外部访问
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupPlayerResources()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // 初始化播放器资源
    private func setupPlayerResources() {
        let storage = Storage.storage()
        let storageRef = storage.reference().child("User1/pexels-christopher-schultz-5147455-1080x1920-30fps (1).mp4")
        
        storageRef.downloadURL { [weak self] url, error in
            guard let self = self else { return }
            
            // 确定视频URL
            let targetURL: URL
            if let error = error {
                print(error)
                targetURL = URL(string: "https://i.imgur.com/U52l05s.mp4")!
            } else {
                guard let validURL = url else { return }
                targetURL = validURL
            }
            
            // 创建播放器项目
            let asset = AVAsset(url: targetURL)
            let item: AVPlayerItem = error != nil ? CachingPlayerItem(asset: asset) : AVPlayerItem(asset: asset)
            
            // 初始化播放器
            self.player = AVQueuePlayer()
            self.playerLayer.player = self.player
            self.playerLayer.videoGravity = .resizeAspectFill
            self.layer.addSublayer(self.playerLayer)
            
            // 设置循环播放
            self.playerLooper = AVPlayerLooper(player: self.player!, templateItem: item)
        }
    }
    
    // 外部调用:根据selectedIndex控制播放/暂停
    func updatePlayState(selectedIndex: Int) {
        guard let player = player else { return }
        
        if selectedIndex == 0 {
            player.play()
        } else {
            player.pause()
            print("pause")
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        playerLayer.frame = bounds
    }
}

步骤2:创建SwiftUI与UIKit的桥接器

通过UIViewRepresentable把UIKit的LoopingPlayerUIView包装成SwiftUI可用的视图,同时绑定selectedIndex:

struct LoopingPlayerView: UIViewRepresentable {
    @Binding var selectedIndex: Int
    
    func makeUIView(context: Context) -> LoopingPlayerUIView {
        let playerView = LoopingPlayerUIView()
        // 设置初始播放状态
        playerView.updatePlayState(selectedIndex: selectedIndex)
        return playerView
    }
    
    // 当selectedIndex变化时自动触发,更新播放状态
    func updateUIView(_ uiView: LoopingPlayerUIView, context: Context) {
        uiView.updatePlayState(selectedIndex: selectedIndex)
    }
}

步骤3:在ContentView中使用包装后的视图

直接把绑定的selectedIndex传递给播放器视图,Tab切换时自动同步状态:

struct ContentView: View {
    @State private var selectedIndex: Int = 0
    
    var body: some View {
        TabView(selection: $selectedIndex) {
            // 第一个Tab:视频播放器
            LoopingPlayerView(selectedIndex: $selectedIndex)
                .tabItem {
                    Image(systemName: "play.rectangle")
                    Text("视频")
                }
                .tag(0)
            
            // 其他Tab示例
            Text("第二个页面")
                .tabItem {
                    Image(systemName: "square")
                    Text("页面2")
                }
                .tag(1)
        }
    }
}

内容的提问来源于stack exchange,提问作者user22030043

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 17:18:14