播放器开发完成

This commit is contained in:
2025-04-23 11:33:46 +08:00
parent eaf21f656e
commit 5bfc5c725a
42 changed files with 575 additions and 131 deletions

View File

@ -160,5 +160,17 @@ extension UIColor {
static func color5A5C67(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x5A5C67, alpha: alpha)
}
static func color3D4556(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x3D4556, alpha: alpha)
}
static func color1C1C1E(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x1C1C1E, alpha: alpha)
}
static func colorEC3324(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xEC3324, alpha: alpha)
}
}

View File

@ -104,6 +104,17 @@ class SPVideoAPI: NSObject {
}
}
///
static func requestShortCategoryList() {
var param = SPNetworkParameters(path: "/getCategories")
param.method = .get
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPListModel<SPShortModel>>) in
// completer?(response.data)
}
}
}
extension SPVideoAPI {

View File

@ -0,0 +1,27 @@
//
// SPAllShortViewController.swift
// Thimra
//
// Created by Overseas on 2025/4/23.
//
import UIKit
class SPAllShortViewController: SPViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .clear
SPVideoAPI.requestShortCategoryList()
}
override func setBgImageView() {
}
}
extension SPAllShortViewController {
}

View File

@ -11,10 +11,16 @@ import UIKit
class SPExplorePageController: SPViewController {
private lazy var titles: [String] = {
let arr = ["Shorts".localized, "Featured".localized, "All".localized]
let arr = ["Shorts".localized, "All".localized]
return arr
}()
private lazy var viewControllers: [SPViewController] = {
let vc1 = SPExploreViewController()
let vc2 = SPAllShortViewController()
return [vc1, vc2]
}()
private lazy var itemWidthArr: [NSNumber] = {
var arr: [NSNumber] = []
self.titles.forEach {
@ -129,7 +135,7 @@ extension SPExplorePageController: WMPageControllerDelegate, WMPageControllerDat
}
func pageController(_ pageController: WMPageController, viewControllerAt index: Int) -> UIViewController {
return SPExploreViewController()
return viewControllers[index]
}

View File

@ -15,7 +15,7 @@ class SPExploreViewController: SPPlayerListViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.autoNextEpisode = true
requestDataArr(page: 1)
self.delegate = self
@ -53,6 +53,7 @@ extension SPExploreViewController: SPPlayerListViewControllerDataSource {
cell.shortModel = model
cell.videoInfo = model.video_info
}
cell.isLoop = false
}
return oldCell
}
@ -70,8 +71,9 @@ extension SPExploreViewController {
guard let self = self else { return }
if let listModel = listModel, let list = listModel.list {
if page == 1 {
self.setDataArr(dataArr: list)
self.play()
self.setDataArr(dataArr: list) { [weak self] in
self?.play()
}
} else {
self.addDataArr(dataArr: list)
}

View File

@ -12,27 +12,59 @@ class SPExplorePlayerControlView: SPPlayerControlView {
override var shortModel: SPShortModel? {
didSet {
desLabel.text = shortModel?.sp_description
// desLabel.text = shortModel?.sp_description
videoInfoView.shortModel = shortModel
// shortModel?.episode_total
updateEpisodeLabel()
}
}
private lazy var desLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorD2D2D2()
label.numberOfLines = 2
return label
}()
override var videoInfo: SPVideoInfoModel? {
didSet {
updateEpisodeLabel()
}
}
// private lazy var desLabel: UILabel = {
// let label = UILabel()
// label.font = .fontRegular(ofSize: 12)
// label.textColor = .colorD2D2D2()
// label.numberOfLines = 2
// return label
// }()
private lazy var videoInfoView: SPVideoPlayerInfoView = {
let view = SPVideoPlayerInfoView()
return view
}()
private lazy var episodeIconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "episode_icon_01"))
return imageView
}()
private lazy var episodeLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
return label
}()
private lazy var allEpisodeButton: UIButton = {
let button = JXButton(type: .custom)
button.setTitle("Full Episodes".localized, for: .normal)
button.setTitleColor(.colorEC3324(), for: .normal)
button.setImage(UIImage(named: "arrow_right_icon_01"), for: .normal)
button.jx_font = .fontMedium(ofSize: 12)
button.titleDirection = .left
button.space = 4
button.addTarget(self, action: #selector(handleAllEpisodeButton), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.progressView.isHidden = true
// self.progressView.isHidden = true
_setupUI()
}
@ -41,23 +73,67 @@ class SPExplorePlayerControlView: SPPlayerControlView {
fatalError("init(coder:) has not been implemented")
}
private func updateEpisodeLabel() {
let totalEpisode = String(format: "EP%@".localized, "\(self.shortModel?.episode_total ?? 0)")
let currentEpisode = String(format: "EP%@".localized, self.videoInfo?.episode ?? "0")
let episodeStr = "\(currentEpisode)/\(totalEpisode)"
let range = NSRange(location: episodeStr.length() - totalEpisode.length(), length: totalEpisode.length())
let string = NSMutableAttributedString(string: episodeStr)
string.color = .colorEC3324()
string.setColor(.colorFFFFFF(), range: range)
episodeLabel.attributedText = string
}
}
extension SPExplorePlayerControlView {
@objc private func handleAllEpisodeButton() {
let vc = SPPlayerDetailViewController()
vc.shortPlayId = self.shortModel?.short_play_id
self.viewController?.navigationController?.pushViewController(vc, animated: true)
}
}
extension SPExplorePlayerControlView {
private func _setupUI() {
addSubview(desLabel)
// addSubview(desLabel)
addSubview(videoInfoView)
toolView.addSubview(episodeIconImageView)
toolView.addSubview(episodeLabel)
toolView.addSubview(allEpisodeButton)
desLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.right.lessThanOrEqualToSuperview().offset(-30)
make.bottom.equalToSuperview().offset(-15)
}
// desLabel.snp.makeConstraints { make in
// make.left.equalToSuperview().offset(15)
// make.right.lessThanOrEqualToSuperview().offset(-30)
// make.bottom.equalToSuperview().offset(-15)
// }
videoInfoView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.bottom.equalTo(desLabel.snp.top).offset(-10)
// make.bottom.equalTo(desLabel.snp.top).offset(-10)
make.bottom.equalToSuperview().offset(-54)
}
episodeIconImageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(14)
}
episodeLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.left.equalTo(episodeIconImageView.snp.right).offset(4)
}
allEpisodeButton.snp.makeConstraints { make in
make.top.bottom.equalToSuperview()
make.right.equalToSuperview().offset(-14)
}
}
}

View File

@ -13,47 +13,36 @@ class SPVideoPlayerInfoView: UIView {
didSet {
coverImageView.sp_setImage(url: shortModel?.image_url)
titleLabel.text = shortModel?.name
desLabel.text = shortModel?.sp_description
}
}
//MARK: UI
private lazy var bgView: UIView = {
let view = UIView()
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
view.backgroundColor = .color000000(alpha: 0.27)
return view
}()
override var intrinsicContentSize: CGSize {
return CGSize(width: 200, height: 68)
}
//MARK: UI
private lazy var coverImageView: SPImageView = {
let imageView = SPImageView()
imageView.layer.cornerRadius = 5
imageView.layer.cornerRadius = 4
imageView.layer.masksToBounds = true
imageView.layer.borderWidth = 1
imageView.layer.borderColor = UIColor.colorFFFFFF(alpha: 0.26).cgColor
return imageView
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 13)
label.font = .fontMedium(ofSize: 14)
label.textColor = .colorFFFFFF()
return label
}()
private lazy var moreButton: JXButton = {
let button = JXButton(type: .custom)
button.colors = [UIColor.colorF56490().cgColor, UIColor.colorD568D2().cgColor]
button.startPoint = .init(x: 0, y: 0.5)
button.endPoint = .init(x: 1, y: 0.5)
button.locations = [0, 1]
button.setImage(UIImage(named: "play_icon_02"), for: .normal)
button.setTitle("Series".localized, for: .normal)
button.setTitleColor(.colorFFFFFF(), for: .normal)
button.jx_font = .fontRegular(ofSize: 11)
button.layer.cornerRadius = 10.5
button.layer.masksToBounds = true
button.space = 2
button.addTarget(self, action: #selector(handleMoreButton), for: .touchUpInside)
return button
private lazy var desLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorA8A5AA()
return label
}()
override init(frame: CGRect) {
@ -76,34 +65,30 @@ class SPVideoPlayerInfoView: UIView {
extension SPVideoPlayerInfoView {
private func _setupUI() {
addSubview(bgView)
addSubview(coverImageView)
addSubview(titleLabel)
addSubview(moreButton)
addSubview(desLabel)
bgView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.width.equalTo(240)
make.height.equalTo(54)
}
coverImageView.snp.makeConstraints { make in
make.left.bottom.top.equalToSuperview()
make.width.equalTo(49)
make.height.equalTo(66)
make.left.top.bottom.equalToSuperview()
make.width.equalTo(46)
make.height.equalTo(68)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(coverImageView.snp.right).offset(10)
make.top.equalTo(bgView).offset(5)
make.right.lessThanOrEqualToSuperview().offset(-18)
make.top.equalToSuperview().offset(16)
make.right.lessThanOrEqualToSuperview()
make.width.lessThanOrEqualTo(145)
}
moreButton.snp.makeConstraints { make in
make.left.equalTo(coverImageView.snp.right).offset(10)
make.bottom.equalToSuperview().offset(-5)
make.width.equalTo(59)
make.height.equalTo(21)
desLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(8)
make.right.lessThanOrEqualToSuperview()
make.width.lessThanOrEqualTo(145)
}

View File

@ -14,7 +14,7 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
}
override var contentSize: CGSize {
return CGSize(width: kSPScreenWidth, height: kSPScreenHeight)
return CGSize(width: kSPScreenWidth, height: kSPScreenHeight - kSPTabbarSafeBottomMargin - 35)
}
@ -37,11 +37,24 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontLight(ofSize: 15)
label.textColor = .colorFFFFFF(alpha: 0.9)
label.font = .fontBold(ofSize: 18)
label.textColor = .colorFFFFFF()
return label
}()
private lazy var episodeLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 18)
label.textColor = .colorFFFFFF(alpha: 0.4)
return label
}()
private lazy var bottomView: UIView = {
let view = UIView()
view.backgroundColor = .color1C1C1E()
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
self.autoNextEpisode = true
@ -78,6 +91,8 @@ extension SPPlayerDetailViewController {
private func _setupUI() {
view.addSubview(backButton)
view.addSubview(titleLabel)
view.addSubview(episodeLabel)
view.addSubview(bottomView)
backButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(5)
@ -88,7 +103,18 @@ extension SPPlayerDetailViewController {
titleLabel.snp.makeConstraints { make in
make.left.equalTo(backButton.snp.right)
make.centerY.equalTo(backButton)
make.right.equalToSuperview().offset(-15)
// make.right.equalToSuperview().offset(-15)
make.width.lessThanOrEqualTo(kSPScreenWidth - 130)
}
episodeLabel.snp.makeConstraints { make in
make.centerY.equalTo(titleLabel)
make.left.equalTo(titleLabel.snp.right).offset(16)
}
bottomView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.top.equalTo(self.collectionView.snp.bottom)
}
}
@ -136,7 +162,9 @@ extension SPPlayerDetailViewController: SPPlayerListViewControllerDataSource, SP
self.episodeView?.currentIndex = indexPath.row
let videoInfo = detailModel?.episodeList?[indexPath.row]
titleLabel.text = String(format: "kPlayerDetailTitleString".localized, "\(videoInfo?.episode ?? "0")", self.detailModel?.shortPlayInfo?.name ?? "")
// titleLabel.text = String(format: "kPlayerDetailTitleString".localized, "\(videoInfo?.episode ?? "0")", self.detailModel?.shortPlayInfo?.name ?? "")
titleLabel.text = detailModel?.shortPlayInfo?.name
episodeLabel.text = "\(videoInfo?.episode ?? "0")/\(detailModel?.shortPlayInfo?.episode_total ?? 0)"
}
}

View File

@ -121,9 +121,9 @@ class SPPlayerListViewController: SPViewController {
}
func setDataArr(dataArr: [Any]) {
func setDataArr(dataArr: [Any], completer: (() -> Void)?) {
self.dataArr = dataArr
reloadData()
reloadData(completion: completer)
}
func addDataArr(dataArr: [Any]) {
@ -260,7 +260,7 @@ extension SPPlayerListViewController {
var contentOffset = self.collectionView.contentOffset
if hasNextEpisode() {
contentOffset.y = contentOffset.y + self.contentSize.height
contentOffset.y = floor(contentOffset.y + self.contentSize.height)
self.collectionView.setContentOffset(contentOffset, animated: true)
} else {
self.viewModel.currentPlayer?.replay()

View File

@ -17,6 +17,12 @@ protocol SPPlayerProtocol: NSObjectProtocol {
var isCurrent: Bool { get set }
///
var duration: Int { get }
///
var currentPosition: Int { get }
var rate: Float { get set }
///
@ -31,4 +37,6 @@ protocol SPPlayerProtocol: NSObjectProtocol {
///
func replay()
///
func seekToTime(toTime: Int)
}

View File

@ -169,7 +169,7 @@ class SPEpisodeView: HWPanModalContentView {
override func backgroundConfig() -> HWBackgroundConfig {
let config = HWBackgroundConfig()
config.backgroundAlpha = 0.4
config.backgroundAlpha = 0.6
return config
}

View File

@ -78,11 +78,18 @@ class SPPlayerControlView: UIView {
return view
}()
private lazy var playImageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .red
imageView.isHidden = true
return imageView
private(set) lazy var toolView: UIView = {
let view = UIView()
view.backgroundColor = .color1C1C1E()
return view
}()
private(set) lazy var playImageView: UIButton = {
let button = UIButton(type: .custom)
button.isHidden = true
button.setImage(UIImage(named: "play_icon_01"), for: .normal)
button.isUserInteractionEnabled = false
return button
}()
///
@ -110,7 +117,7 @@ class SPPlayerControlView: UIView {
NotificationCenter.default.addObserver(self, selector: #selector(updateShortCollectStateNotification), name: SPVideoAPI.updateShortCollectStateNotification, object: nil)
let tap = UITapGestureRecognizer(target: self, action: #selector(hadlePlayAndOrPaused))
let tap = UITapGestureRecognizer(target: self, action: #selector(handleScreen))
tap.delegate = self
self.addGestureRecognizer(tap)
@ -139,12 +146,24 @@ class SPPlayerControlView: UIView {
button.setTitle(title, for: .normal);
button.setTitle(selectedTitle, for: .selected);
button.setTitle(selectedTitle, for: [.selected, .highlighted])
button.setTitleColor(.colorFFFFFF(alpha: 0.9), for: .normal)
button.setTitleColor(.colorF564B6(), for: .selected)
button.jx_font = .fontLight(ofSize: 11);
button.setTitleColor(.colorFFFFFF(), for: .normal)
// button.setTitleColor(.colorF564B6(), for: .selected)
button.jx_font = .fontMedium(ofSize: 12)
return button
}
@objc func handleScreen() {
self.hadlePlayAndOrPaused()
}
func updatePlayIconState() {
let isPlaying = self.viewModel?.isPlaying ?? false
if isCurrent {
playImageView.isHidden = isPlaying
} else {
playImageView.isHidden = true
}
}
}
@ -153,6 +172,7 @@ extension SPPlayerControlView {
private func sp_setupUI() {
addSubview(bottomGradientView)
addSubview(progressView)
progressView.addSubview(toolView)
addSubview(playImageView)
addSubview(rightFeatureView)
@ -162,15 +182,17 @@ extension SPPlayerControlView {
}
progressView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(10)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-20)
make.height.equalTo(30)
make.left.right.bottom.equalToSuperview()
make.height.equalTo(40)
}
toolView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.bottom.equalToSuperview().offset(-2)
}
playImageView.snp.makeConstraints { make in
make.center.equalToSuperview()
make.width.height.equalTo(100)
}
rightFeatureView.snp.makeConstraints { make in
@ -182,15 +204,6 @@ extension SPPlayerControlView {
extension SPPlayerControlView {
private func updatePlayIconState() {
let isPlaying = self.viewModel?.isPlaying ?? false
if isCurrent {
playImageView.isHidden = isPlaying
} else {
playImageView.isHidden = true
}
}
@objc private func hadlePlayAndOrPaused() {
self.viewModel?.handlePauseOrPlay?()

View File

@ -8,6 +8,15 @@
import UIKit
class SPPlayerDetailControlView: SPPlayerControlView {
///
enum PauseState {
///
case hidden
///
case showPause
///
case showPlay
}
override var durationTime: Int {
@ -33,22 +42,50 @@ class SPPlayerDetailControlView: SPPlayerControlView {
didSet {
if isCurrent {
showSpeedSelectedView(isShow: false)
} else {
self.timer?.invalidate()
self.timer = nil
self.pauseState = .hidden
}
}
}
///
private lazy var pauseState = PauseState.hidden {
didSet {
switch pauseState {
case .hidden:
self.playImageView.isHidden = true
self.retreatButton.isHidden = true
self.advanceButton.isHidden = true
case .showPause:
self.playImageView.isHidden = false
self.retreatButton.isHidden = false
self.advanceButton.isHidden = false
self.playImageView.setImage(UIImage(named: "pause_icon_01"), for: .normal)
case .showPlay:
self.playImageView.isHidden = false
self.retreatButton.isHidden = false
self.advanceButton.isHidden = false
self.playImageView.setImage(UIImage(named: "play_icon_01"), for: .normal)
}
}
}
///
private var timer: Timer?
//MARK: UI
private lazy var episodeButton: UIButton = {
let button = createFeatureButton(title: "Episodes".localized, image: UIImage(named: "episodes_icon_01"))
let button = createFeatureButton(title: "Episodes".localized, image: UIImage(named: "episode_icon_02"))
button.addTarget(self, action: #selector(handleEpisodeButton), for: .touchUpInside)
return button
}()
private lazy var progressTimeLabel: UILabel = {
let label = UILabel()
label.font = .fontLight(ofSize: 12)
label.textColor = .colorFFFFFF(alpha: 0.9)
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorFFFFFF()
return label
}()
@ -74,12 +111,32 @@ class SPPlayerDetailControlView: SPPlayerControlView {
return view
}()
///退
private lazy var retreatButton: UIButton = {
let button = UIButton(type: .custom)
button.isHidden = true
button.setImage(UIImage(named: "speed_icon_01"), for: .normal)
button.addTarget(self, action: #selector(handleRetreatButton), for: .touchUpInside)
return button
}()
///
private lazy var advanceButton: UIButton = {
let button = UIButton(type: .custom)
button.isHidden = true
button.setImage(UIImage(named: "speed_icon_02"), for: .normal)
button.addTarget(self, action: #selector(handleAdvanceButton), for: .touchUpInside)
return button
}()
deinit {
self.viewModel?.removeObserver(self, forKeyPath: "speedModel")
}
override init(frame: CGRect) {
super.init(frame: frame)
self.playImageView.isUserInteractionEnabled = true
self.playImageView.addTarget(self, action: #selector(handlePlayImageView), for: .touchUpInside)
_setupUI()
}
@ -107,6 +164,51 @@ class SPPlayerDetailControlView: SPPlayerControlView {
private func updateSpeedButton() {
self.speedButton.setTitle(self.viewModel?.speedModel.formatString(), for: .normal)
}
///
override func handleScreen() {
if self.pauseState == .hidden {
self.pauseState = .showPause
resetTimer()
} else if self.pauseState == .showPause {
self.pauseState = .hidden
self.cleanTimer()
}
}
override func updatePlayIconState() {
guard isCurrent else { return }
guard self.pauseState != .hidden else { return }
if self.viewModel?.isPlaying == true {
self.pauseState = .showPause
self.resetTimer()
} else {
self.pauseState = .showPlay
self.cleanTimer()
}
}
@objc private func handleHiddenTimer() {
self.pauseState = .hidden
}
///
private func cleanTimer() {
self.timer?.invalidate()
self.timer = nil
}
///
private func resetTimer() {
cleanTimer()
self.timer = Timer.scheduledTimer(timeInterval: 5, target: YYWeakProxy(target: self), selector: #selector(handleHiddenTimer), userInfo: nil, repeats: false)
}
}
extension SPPlayerDetailControlView {
@ -114,34 +216,48 @@ extension SPPlayerDetailControlView {
private func _setupUI() {
self.rightFeatureView.addArrangedSubview(episodeButton)
addSubview(progressTimeLabel)
addSubview(speedButton)
addSubview(speedSelectedView)
toolView.addSubview(progressTimeLabel)
addSubview(retreatButton)
addSubview(advanceButton)
// addSubview(speedButton)
// addSubview(speedSelectedView)
self.progressView.snp.remakeConstraints { make in
make.left.equalToSuperview().offset(15)
make.centerX.equalToSuperview()
make.height.equalTo(30)
make.bottom.equalToSuperview().offset(-(kSPTabbarSafeBottomMargin + 10))
}
// self.progressView.snp.remakeConstraints { make in
// make.left.equalToSuperview().offset(15)
// make.centerX.equalToSuperview()
// make.height.equalTo(30)
// make.bottom.equalToSuperview().offset(-(kSPTabbarSafeBottomMargin + 10))
// }
self.progressTimeLabel.snp.makeConstraints { make in
make.left.equalTo(self.progressView)
make.bottom.equalTo(self.progressView).offset(-12)
// make.left.equalTo(self.progressView)
// make.bottom.equalTo(self.progressView).offset(-12)
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(16)
}
speedButton.snp.makeConstraints { make in
make.centerY.equalTo(self.progressTimeLabel)
make.right.equalToSuperview().offset(-15)
make.width.equalTo(40)
make.height.equalTo(20)
retreatButton.snp.makeConstraints { make in
make.centerY.equalTo(playImageView)
make.right.equalTo(playImageView.snp.left).offset(kSPMainW(-50))
}
speedSelectedView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.bottom.equalTo(self.speedButton.snp.top).offset(-30)
advanceButton.snp.makeConstraints { make in
make.centerY.equalTo(playImageView)
make.left.equalTo(playImageView.snp.right).offset(kSPMainW(50))
}
// speedButton.snp.makeConstraints { make in
// make.centerY.equalTo(self.progressTimeLabel)
// make.right.equalToSuperview().offset(-15)
// make.width.equalTo(40)
// make.height.equalTo(20)
// }
// speedSelectedView.snp.makeConstraints { make in
// make.left.right.equalToSuperview()
// make.bottom.equalTo(self.speedButton.snp.top).offset(-30)
// }
}
}
@ -164,4 +280,24 @@ extension SPPlayerDetailControlView {
self.speedSelectedView.currentSpeed = self.viewModel?.speedModel.speed ?? .x1
}
}
@objc private func handlePlayImageView() {
self.viewModel?.handlePauseOrPlay?()
}
///退
@objc private func handleRetreatButton() {
self.viewModel?.seekToTime(toTime: self.currentTime - 5)
resetTimer()
}
///
@objc private func handleAdvanceButton() {
self.viewModel?.seekToTime(toTime: self.currentTime + 5)
resetTimer()
}
}

View File

@ -9,6 +9,7 @@ import UIKit
class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol {
var PlayerControlViewClass: SPPlayerControlView.Type {
return SPPlayerControlView.self
}
@ -111,9 +112,22 @@ class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol {
}
}
///
var duration: Int {
get {
return player.duration
}
}
///
var currentPosition: Int {
get {
return player.currentPosition
}
}
var rate: Float {
set {
return player.rate = newValue
player.rate = newValue
}
get {
return player.rate
@ -139,6 +153,10 @@ class SPPlayerListCell: SPCollectionViewCell, SPPlayerProtocol {
player.replay()
}
func seekToTime(toTime: Int) {
player.seekToTime(toTime: toTime)
}
}
extension SPPlayerListCell {

View File

@ -32,10 +32,10 @@ class SPPlayerProgressView: UIView {
///
private var panProgress: CGFloat = 0
var progressColor: UIColor = .colorFFFFFF(alpha: 0.12)
var currentProgress: UIColor = .colorFFFFFF(alpha: 0.48)
var progressColor: UIColor = .color3D4556()
var currentProgress: UIColor = .colorFFFFFF()
var lineWidth: CGFloat = 5
var lineWidth: CGFloat = 2
///
private var isPaning: Bool = false

View File

@ -37,6 +37,10 @@ class SPPlayerListViewModel: NSObject {
currentPlayer?.rate = speedModel.getRate()
}
///
func seekToTime(toTime: Int) {
self.currentPlayer?.seekToTime(toTime: toTime)
}
///
var handlePauseOrPlay: (() -> Void)?

View File

@ -171,8 +171,14 @@ class SPPlayer: NSObject {
}
func seekToTime(toTime: Int) {
// self.player.seek(toTime: Int64(toTime), seekMode: AVP_SEEKMODE_ACCURATE)
self.player.seek(toTime: TimeInterval(toTime), completionHandler: nil)
var time = toTime
if time < 0 {
time = 0
}
if time > self.duration {
time = self.duration
}
self.player.seek(toTime: TimeInterval(time), completionHandler: nil)
}

View File

@ -5,12 +5,12 @@
"scale" : "1x"
},
{
"filename" : "play@2x.png",
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "play@3x.png",
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 1912056659@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 1912056659@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 43@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 43@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -20,7 +20,6 @@
"Episodes" = "Episodes";
"Save" = "Save";
"Added" = "Added";
"Series" = "Series";
"Order Record" = "Order Record";
"Language" = "Language";
"Privacy Policy" = "Privacy Policy";
@ -40,6 +39,9 @@
"More" = "More";
"Historical search" = "Historical search";
"Top Search" = "Top Search";
"EP%@" = "EP%@";
"Full Episodes" = "Full Episodes";
"All" = "All";
"Shorts" = "Shorts";
///视频详情标题
"kPlayerDetailTitleString" = "Episode %@ / %@";

View File

@ -428,7 +428,7 @@ static NSInteger const kWMControllerCountUndefined = -1;
WMScrollView *scrollView = [[WMScrollView alloc] init];
scrollView.scrollsToTop = NO;
scrollView.pagingEnabled = YES;
scrollView.backgroundColor = [UIColor whiteColor];
scrollView.backgroundColor = [UIColor clearColor];
scrollView.delegate = self;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
@ -681,7 +681,7 @@ static NSInteger const kWMControllerCountUndefined = -1;
#pragma mark - Life Cycle
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.view.backgroundColor = [UIColor clearColor];
if (!self.childControllersCount) return;
[self wm_calculateSize];
[self wm_addScrollView];