如何实现UIView中视频切换及滑动触发下一个视频播放?
Great job getting your first video playing without controls! Adding swipe-to-switch functionality is a common next step, and using a UICollectionView is the cleanest approach here—it natively supports horizontal scrolling and cell reuse, which is perfect for managing multiple videos efficiently.
Let’s break down how to implement this step by step, building on your existing code:
1. Prepare Your Video Data Source
First, create an array to hold your video filenames (this makes it easy to add/remove videos later):
let videoFiles = ["jordanreel", "summer_vacation", "workout_clips"] // Replace with your actual video names
2. Set Up UICollectionView for Horizontal Scrolling
Add a UICollectionView to your storyboard (instead of the single videoView), then link it to an IBOutlet in your view controller:
@IBOutlet weak var videoCollectionView: UICollectionView!
In viewDidLoad, configure the collection view for full-screen, paged horizontal scrolling:
override func viewDidLoad() { super.viewDidLoad() // Configure horizontal layout let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal layout.itemSize = view.bounds.size // Each cell fills the screen layout.minimumLineSpacing = 0 videoCollectionView.collectionViewLayout = layout videoCollectionView.dataSource = self videoCollectionView.delegate = self videoCollectionView.isPagingEnabled = true // Smooth page-by-page swipes }
3. Create a Reusable Video Player Cell
Make a custom UICollectionViewCell to encapsulate video playback logic—this ensures proper reuse and avoids memory leaks:
import UIKit import AVKit class VideoPlayerCell: UICollectionViewCell { var player: AVPlayer? private var playerController: AVPlayerViewController! override init(frame: CGRect) { super.init(frame: frame) setupPlayerController() } required init?(coder: NSCoder) { super.init(coder: coder) setupPlayerController() } private func setupPlayerController() { playerController = AVPlayerViewController() playerController.showsPlaybackControls = false playerController.view.frame = bounds addSubview(playerController.view) // Listen for video finish events (if you want auto-switch after playback) NotificationCenter.default.addObserver( self, selector: #selector(videoDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: nil ) } // Configure cell with a video file func configure(with videoName: String) { guard let filePath = Bundle.main.path(forResource: videoName, ofType: "mp4"), let fileURL = URL(fileURLWithPath: filePath) else { return } player = AVPlayer(url: fileURL) playerController.player = player player?.play() } // Pause playback (for when cell is off-screen) func pausePlayback() { player?.pause() } // Resume playback (for when cell comes on-screen) func resumePlayback() { player?.play() } @objc private func videoDidFinishPlaying() { // Notify parent view controller to switch to next video NotificationCenter.default.post(name: .videoPlaybackCompleted, object: self) } override func prepareForReuse() { super.prepareForReuse() player?.pause() player = nil playerController.player = nil } deinit { NotificationCenter.default.removeObserver(self) } } // Custom notification name for video finish extension Notification.Name { static let videoPlaybackCompleted = Notification.Name("VideoPlaybackCompleted") }
4. Implement Collection View DataSource & Delegate
Add these extensions to your view controller to populate the collection view and handle state changes when swiping:
extension ViewController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return videoFiles.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VideoPlayerCell", for: indexPath) as! VideoPlayerCell cell.configure(with: videoFiles[indexPath.item]) return cell } } extension ViewController: UICollectionViewDelegate { // Handle playback state when swiping stops func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { let currentIndex = Int(videoCollectionView.contentOffset.x / videoCollectionView.bounds.width) // Only play the currently visible cell's video for cell in videoCollectionView.visibleCells as! [VideoPlayerCell] { if let indexPath = videoCollectionView.indexPath(for: cell), indexPath.item == currentIndex { cell.resumePlayback() } else { cell.pausePlayback() } } } }
5. Add Auto-Switch on Video Finish (Optional)
If you want the app to automatically swipe to the next video when playback ends, add this to your view controller's viewDidLoad:
NotificationCenter.default.addObserver( self, selector: #selector(handleVideoFinish), name: .videoPlaybackCompleted, object: nil )
Then implement the handler:
@objc private func handleVideoFinish() { let currentIndex = Int(videoCollectionView.contentOffset.x / videoCollectionView.bounds.width) let nextIndex = currentIndex + 1 // Loop back to first video if we're at the end let targetIndex = nextIndex < videoFiles.count ? nextIndex : 0 let targetPath = IndexPath(item: targetIndex, section: 0) videoCollectionView.scrollToItem(at: targetPath, at: .centeredHorizontally, animated: true) } deinit { NotificationCenter.default.removeObserver(self) }
Quick Setup Notes
- Don’t forget to set your custom cell’s reuse identifier to
VideoPlayerCellin the storyboard. - Test for edge cases: what if a video file is missing? Add error handling in the
configuremethod to avoid crashes. - For better performance, consider pausing off-screen videos immediately (the code above does this, but you can refine it further).
内容的提问来源于stack exchange,提问作者SuperTechy123

