Last active
March 3, 2017 03:01
-
-
Save mosluce/49629595c69ae08ccc40b100c6760524 to your computer and use it in GitHub Desktop.
仿 Youtube 試做
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// VideoViewController.swift | |
// SideMenuCALayerDemo | |
// | |
// Created by 默司 on 2017/3/1. | |
// Copyright © 2017年 默司. All rights reserved. | |
// | |
import UIKit | |
import AVFoundation | |
class VideoViewController: UIViewController { | |
@IBOutlet weak var videoRectView: UIView! // 拿來給 PlayerLayer 追蹤位置 | |
var touchStartPoint: CGPoint! // 紀錄拖拉的起始位置 | |
var maxOffset: CGFloat { // 最多可以拉多遠 | |
return UIScreen.main.bounds.size.height - minHeight | |
} | |
var minWidth: CGFloat { // 縮到最小後的寬度 | |
return UIScreen.main.bounds.size.width / 4 | |
} | |
var minHeight: CGFloat { // 縮到最小後的高度 | |
return minWidth / 16 * 9 | |
} | |
var maxWidth: CGFloat { // 原始寬度 | |
return UIScreen.main.bounds.size.width | |
} | |
var maxHeight: CGFloat { // 原始高度 | |
return UIScreen.main.bounds.size.height | |
} | |
// var aspectRatio: CGFloat { // 原始長寬比 (後來沒用到) | |
// return maxWidth / maxHeight | |
// } | |
var offset: CGFloat = 0 // 記錄目前當前移動量 | |
var startOffset: CGFloat = 0 // 開始拖拉時的移動量 | |
var tap: UITapGestureRecognizer! // Tap手勢,點一下回到最大 | |
var videoPlayer = AVPlayer() // 播放影片 | |
var videoLayer: CALayer! // VideoPlayer Layer | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// Do any additional setup after loading the view. | |
// 拖拉手勢 | |
self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(panHandler(_:)))) | |
// Tap 手勢初始化 | |
self.tap = UITapGestureRecognizer(target: self, action: #selector(tapHandler(_:))) | |
self.tap.isEnabled = false // 預設關閉 | |
self.view.addGestureRecognizer(tap) | |
// 建立 Layer (背景黑黑der) | |
self.videoLayer = AVPlayerLayer(player: videoPlayer) | |
self.videoLayer.backgroundColor = UIColor.black.cgColor | |
// Layer 加到最上面 | |
self.view.layer.addSublayer(videoLayer) | |
// 不知道哪裡找來的影片連結 | |
let url = URL(string: "https://content.jwplatform.com/manifests/vM7nH0Kl.m3u8") | |
let playerItem = AVPlayerItem(url: url!) | |
// 放到播放器裡面 | |
self.videoPlayer.replaceCurrentItem(with: playerItem) | |
} | |
override func viewDidAppear(_ animated: Bool) { | |
super.viewDidAppear(animated) | |
// 開始播放並設定好顯示範圍 | |
self.videoPlayer.play() | |
self.videoLayer.frame = self.videoRectView.frame | |
NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange(_:)), name: .UIDeviceOrientationDidChange, object: nil) | |
} | |
override func didReceiveMemoryWarning() { | |
super.didReceiveMemoryWarning() | |
// Dispose of any resources that can be recreated. | |
} | |
func deviceOrientationDidChange(_ notification: NSNotification) { | |
self.toMax() // 只要有轉向都先把縮小取消 (和 Youtube 行為相同) | |
switch UIDevice.current.orientation { | |
case .landscapeLeft: // HOME在左邊 | |
let bounds = UIScreen.main.bounds | |
self.videoLayer.transform = CATransform3DMakeRotation(CGFloat.pi / 2, 0, 0, 1) // 先轉 (CALayer 自動補間) | |
self.videoLayer.frame = bounds // 再設定 frame (CALayer 自動補間) | |
break | |
case .landscapeRight: | |
let bounds = UIScreen.main.bounds | |
self.videoLayer.transform = CATransform3DMakeRotation(CGFloat.pi / -2, 0, 0, 1) // 先轉 (CALayer 自動補間) | |
self.videoLayer.frame = bounds // 再設定 frame (CALayer 自動補間) | |
break | |
default: | |
self.videoLayer.transform = CATransform3DMakeRotation(0, 0, 0, 1) // 先轉 (CALayer 自動補間) | |
self.videoLayer.frame = self.videoRectView.frame // 再設定 frame (CALayer 自動補間) | |
break | |
} | |
} | |
func tapHandler(_ gesture: UITapGestureRecognizer) { | |
self.toMax() //點一下回去最大的狀態 | |
} | |
func panHandler(_ gesture: UIPanGestureRecognizer) { | |
switch gesture.state { | |
case .began: | |
self.touchStartPoint = gesture.location(in: self.view.superview) // 紀錄觸控起點 | |
break | |
case .changed: | |
let position = gesture.location(in: self.view.superview) // 拖拉中,目前的觸控點 | |
self.offset = position.y - touchStartPoint.y // 位移 | |
let y = min(startOffset + offset, maxOffset) // View 的新 y 座標 | |
var height = maxHeight - y // 用 y 座標算新高度 | |
if height > maxHeight { height = maxHeight } | |
if height < minHeight { height = minHeight } | |
var width = minWidth * (height / maxHeight) * 4 // 用高度算新寬度 | |
if width > maxWidth { width = maxWidth } | |
if width < minWidth { width = minWidth } | |
let x = maxWidth - width // 用寬度算新 x 座標 | |
self.view.frame = CGRect(origin: CGPoint(x: x, y: y), size: CGSize(width: width, height: height)) // 合體 | |
//self.videoLayer.frame = self.videoRectView.frame | |
CATransaction.begin() // 使用自動補間會跟不上拖拉速度 | |
CATransaction.setDisableActions(true) // 所以這邊要取消自動補間 | |
self.videoLayer.frame = self.videoRectView.frame | |
CATransaction.commit() // 自己設定新的參數後要 commit | |
break | |
case .ended: // 放開那個女孩...不對...那個 View 的時候,依照拖拉目前高度判斷要往最大還是最小發展 | |
if self.offset > maxHeight / 2 { | |
self.toMin() | |
} else { | |
self.toMax() | |
} | |
break | |
default: | |
break | |
} | |
} | |
func toMin() { | |
UIView.animate(withDuration: 0.2, animations: { | |
let size = CGSize(width: self.minWidth, height: self.minHeight) | |
self.view.frame = CGRect(origin: CGPoint(x: self.maxWidth - size.width, y: self.maxHeight - size.height), size: size) | |
self.view.layoutIfNeeded() // 沒有這行 subview 會直接抵達終點 | |
}) | |
self.startOffset = maxOffset | |
self.tap.isEnabled = true // 縮小後 Tap 啟用 | |
self.videoLayer.frame = self.videoRectView.frame // Layer跟上 (CALayer自動補間) | |
} | |
func toMax() { | |
UIView.animate(withDuration: 0.2, animations: { | |
self.view.frame = CGRect(origin: .zero, size: CGSize(width: self.maxWidth, height: self.maxHeight)) | |
self.view.layoutIfNeeded() // 沒有這行 subview 會直接抵達終點 | |
}) | |
self.startOffset = 0 | |
self.tap.isEnabled = false // 放大後 Tap 停用 | |
self.videoLayer.frame = self.videoRectView.frame // Layer跟上 (CALayer自動補間) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment