Login required for access
In order to watch this lesson, you'll need to login to the website.
How to Seek and Scrub through Video with UISlider
YouTube
Happy Sunday everyone. Let's continue building out our video player by introducing a video duration label and a UISlider component that allows us to jump to different portions of our clip. First, we look at how to figure out the duration by inspecting AVPlayer currentItem's duration property. Converting this value into seconds is somewhat tricky so I'll go through step by step how to do this. Next we'll take a look at using a UISlider component to seek and scrub through our video. By utilizing the zero to one value of our slider and video duration, we can use seekToTime on AVPlayer to bounce from point to point very easily. Have fun and enjoy.
!codebreak <div class='filename'>VideoPlayerView</div> !codebreak !syntax-highlight class VideoPlayerView: UIView { //... let videoLengthLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.text = "00:00" label.textColor = .whiteColor() label.font = UIFont.boldSystemFontOfSize(14) label.textAlignment = .Right return label }() lazy var videoSlider: UISlider = { let slider = UISlider() slider.translatesAutoresizingMaskIntoConstraints = false slider.minimumTrackTintColor = .redColor() slider.maximumTrackTintColor = .whiteColor() slider.setThumbImage(UIImage(named: "thumb"), forState: .Normal) slider.addTarget(self, action: #selector(handleSliderChange), forControlEvents: .ValueChanged) return slider }() func handleSliderChange() { print(videoSlider.value) if let duration = player?.currentItem?.duration { let totalSeconds = CMTimeGetSeconds(duration) let value = Float64(videoSlider.value) * totalSeconds let seekTime = CMTime(value: Int64(value), timescale: 1) player?.seekToTime(seekTime, completionHandler: { (completedSeek) in //perhaps do something later here }) } } override init(frame: CGRect) { //... controlsContainerView.addSubview(videoLengthLabel) videoLengthLabel.rightAnchor.constraintEqualToAnchor(rightAnchor, constant: -8).active = true videoLengthLabel.bottomAnchor.constraintEqualToAnchor(bottomAnchor).active = true videoLengthLabel.widthAnchor.constraintEqualToConstant(60).active = true videoLengthLabel.heightAnchor.constraintEqualToConstant(24).active = true controlsContainerView.addSubview(videoSlider) videoSlider.rightAnchor.constraintEqualToAnchor(videoLengthLabel.leftAnchor).active = true videoSlider.bottomAnchor.constraintEqualToAnchor(bottomAnchor).active = true videoSlider.leftAnchor.constraintEqualToAnchor(leftAnchor).active = true videoSlider.heightAnchor.constraintEqualToConstant(30).active = true //... } override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { //this is when the player is ready and rendering frames if keyPath == "currentItem.loadedTimeRanges" { //... if let duration = player?.currentItem?.duration { let seconds = CMTimeGetSeconds(duration) let secondsText = Int(seconds) % 60 let minutesText = String(format: "%02d", Int(seconds) / 60) videoLengthLabel.text = "\(minutesText):\(secondsText)" } } } //... }

Comments (4)
5 years ago
6 years ago
8 years ago
8 years ago
HELP & SUPPORT