동영상 피드 스크롤 시 중앙의 비디오만 재생되는 기능

2023. 3. 29. 17:24iOS/이슈

 

유튜브, 인스타, 트위터 등 앱들을 사용할 때는 몰랐는데 생각보다 셀에서 영상이 재생되는 예제를 찾기 힘들었다. 상태 관리가 힘들어서 그런 것 같다.

 

그러던 중 아래와 같은 요구 사항이 추가되었다

피드 리스트에서 스크롤 시 중앙에 있는 비디오만 재생해주세요

구현 아이디어 1

[참고1] 테이블 뷰의 center 좌표를 구하고 헤당 좌표에 있는 셀의 비디오를 재생

재생 상태 관리는 이전에 재생한 cell을 변수로 저장

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    let point = self.convert(tableView.center, to: tableView)
    
    guard let indexPath = tableView.indexPathForRow(at: point) else { return }
    
    guard let capturedCell = tableView.cellForRow(at: indexPath) as? FeedCell else { return }
    
    if savedCell?.feed.id != capturedCell.feed.id {
      savedCell?.pause()
      savedCell = capturedCell
      savedCell?.play()
    }
  }

1. decelerate를 고려하지 않아 불필요한 호출이 생김

2. pause()가 되지 않는 예외 케이스가 생김

모든 케이스를 다 처리하지 못하는 상황 발생

GSPlayer의 feed example을 참고 함 해당 예제는 셀 하나가 화면 전체 크기인 유튜브 숏츠 형식이라 딱 알맞지는 않았다.

구현 아이디어 2

[참고2] visibleCell이 아니면 pause(), decelerate에 대한 분기를 나눠 play() 처리

play() 전 모든 visibleCell pause() 처리

실행 로직은 현재 셀의 절반 이상이 visible  영역에 놓이면 실행한다.

func checkPlay() {
    let visibleCells = tableView.visibleCells.compactMap { $0 as? FeedCell }

    guard visibleCells.count > 0 else { return }
    visibleCells.forEach { $0.pause() }

    let visibleFrame = CGRect(x: 0, y: tableView.contentOffset.y, width: tableView.bounds.width, height: tableView.bounds.height)

	// 절반 이상 보일 경우에 재생
    let visibleCell = visibleCells
        .filter { visibleFrame.intersection($0.frame).height >= $0.frame.height / 2 }
        .first
    visibleCell?.play()
}

아이디어 2 보완

요구사항 1: 화면이 처음 로드 될 시 첫번째 비디오 피드가 화면에 보일 경우 재생

요구사항 2: 비디오 피드가 리스트의 마지막일 경우 스크롤 중앙에 오지 않아도 재생

요구사항 3: 리스트 화면에서 벗어날 경우 모든 비디오 pause()

checkPlay() 대신 centerCellStrategy() 메소드를 만듦

private func centerCellPlayStrategy() {
    let visibleVideoCells = fetchVisibleVideoCells()
    guard visibleVideoCells.count > 0 else { return }
    
    pauseAllVideos()
    
    // edge case) 요구사항 2 마지막 비디오 피드 재생
    // 컨텐츠 오프셋이 끝에 가까운 경우를 체크
    if tableView.contentOffset.y > tableView.contentSize.height - 100 {
      visibleVideoCells.last?.play()
      return
    }
    
    let center = CGPoint(x: tableView.center.x, y: tableView.center.y)
    let point = self.convert(center, to: tableView)
    
    guard
      let indexPath = tableView.indexPathForRow(at: point),
      let capturedCell = tableView.cellForRow(at: indexPath) as? VideoFeedCell
    else {
      isEnoughShownToPlay(visibleVideoCells.last!)
      return
    }
    isEnoughShownToPlay(capturedCell)
  }
  
// 요구사항 1: 피드리스트의 ViewWillAppear() 트리거에서 
visibleVideoCells.first?.play() 실행
    
// 요구사항 3: 피드리스트의 VIewWillDisAppear() 트리거에서
visibleVIdeoCells.forEach { $0.pause() } 실행

 

 

포스팅할 항목 - 비디오 피드 구현 중 이슈들

Time observer & deinit

재생 전 깜빡거림

썸네일 자체, 썸네일 제대로 안 나옴, 썸네일 추출

의도치 않은 영상 재생

회전

 

참고 1 중앙 셀 값 얻기

 

How to get cell at center during scroll in UICollectionView

Issue #311 See Omnia https://github.com/onmyway133/Omnia/blob/master/Sources/iOS/UICollectionView.swift#L30 extension HorizontalUsersViewController: UIScrollViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { let point = view.con

onmyway133.com

참고 2 GSPlayer Shorts Play Logic

 

GitHub - wxxsw/GSPlayer: ⏯ Video player, support for caching, preload, fullscreen transition and custom control view. 视频

⏯ Video player, support for caching, preload, fullscreen transition and custom control view. 视频播放器,支持边下边播、预加载、全屏转场和自定义控制层 - GitHub - wxxsw/GSPlayer: ⏯ Video player, support for caching, preload, f

github.com

참고 3 ScrollView Delgate들

 

UITableView에서 주로 사용되는 UIScrollViewDelegate를 알아보자 ! - 야곰닷넷

UIScrollViewDelegate @available(iOS 2.0, *) optional func scrollViewDidScroll(_ scrollView: UIScrollView) // any offset changes @available(iOS 3.2, […]

yagom.net

참고 4 동영상 피드 리스트 예제

 

GitHub - alexpaul/AVFoundation-MediaFeed: A demo app that illustrated creating and persisting videos using AVFoundation and AVKi

A demo app that illustrated creating and persisting videos using AVFoundation and AVKit. Video playback. - GitHub - alexpaul/AVFoundation-MediaFeed: A demo app that illustrated creating and persis...

github.com