You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

226 lines
6.8 KiB

//
// LTLivePlayLoopsListView.swift
// LTScrollView_Example
//
// Created by gaoliutong on 2022/3/5.
// Copyright © 2022 CocoaPods. All rights reserved.
//
import UIKit
@objc public protocol LTLivePlayLoopsListDelegate: UIScrollViewDelegate {
/// view
func didSelect(livePlayView: LTLivePlayLoopsListView, inView: UIView, index: Int)
/// view
func prefetch(livePlayView: LTLivePlayLoopsListView, inView: UIView, index: Int)
@objc optional
///
/// - Returns: truefalse
func checkCanScroll() -> Bool
}
@objc public protocol LTLivePlayLoopsListDataSource: NSObjectProtocol {
func numberofItems(livePlayView: LTLivePlayLoopsListView) -> Int
}
protocol LTLivePlayLoopsListInterface {
///
var dataSource: LTLivePlayLoopsListDataSource? { get set }
/// - LTLivePlayLoopsListDelegate
var delegate: UIScrollViewDelegate? { get set }
/// reloadreloadData
var currentIndex: Int { get set }
///
var isCanLoops: Bool { get set }
/// reloadData
func reloadData()
/// , reloadData
func scrollTo(index: Int)
}
/// LTLivePlayLoopsListInterface
public class LTLivePlayLoopsListView: UIScrollView, LTLivePlayLoopsListInterface {
@objc public var isCanLoops = true
@objc public var currentIndex = 0
@objc public weak var dataSource: LTLivePlayLoopsListDataSource?
@objc override weak public var delegate: UIScrollViewDelegate? {
didSet {
myDelegate = delegate as? LTLivePlayLoopsListDelegate
}
}
@objc public init(frame: CGRect, content: UIView.Type) {
self.topView = content.init()
self.currentView = content.init()
self.bottomView = content.init()
super.init(frame: frame)
itemW = frame.width
itemH = frame.height
glt_setupSystem()
glt_setupSubViews()
}
@objc public func scrollTo(index: Int) {
_scrollTo(index: index)
}
@objc public func reloadData() {
_reloadData()
}
private lazy var itemW: CGFloat = 0
private lazy var itemH: CGFloat = 0
private lazy var totalCount = 0
private lazy var isIgnoreOffset = false
private var topView: UIView
private var currentView: UIView
private var bottomView: UIView
private weak var myDelegate: LTLivePlayLoopsListDelegate?
public override var contentOffset: CGPoint {
set {
if newValue.equalTo(self.contentOffset) {
return
}
if let func_checkCanScroll = myDelegate?.checkCanScroll {
let canScroll = func_checkCanScroll()
guard canScroll else { return }
}
if !isCanLoops && isIgnoreOffset {
if (currentIndex == totalCount - 1 && newValue.y > itemH) || currentIndex == 0 && newValue.y < itemH {
return
}
}
super.contentOffset = newValue
contentOffsetDidChanged(offset: newValue)
}
get { super.contentOffset }
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension LTLivePlayLoopsListView {
private func glt_setupSystem() {
scrollsToTop = false
contentSize = CGSize(width: itemW, height: itemH * 3.0)
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
isPagingEnabled = true
bounces = false
if #available(iOS 11.0, *) {
contentInsetAdjustmentBehavior = .never
}
}
private func glt_setupSubViews() {
addSubview(topView)
addSubview(currentView)
addSubview(bottomView)
reset()
}
private func reset() {
isIgnoreOffset = false
super.contentOffset = CGPoint(x: 0, y: itemH)
isIgnoreOffset = true
topView.frame = CGRect(x: 0, y: 0, width: itemW, height: itemH)
currentView.frame = CGRect(x: 0, y: itemH, width: itemW, height: itemH)
bottomView.frame = CGRect(x: 0, y: itemH * 2, width: itemW, height: itemH)
}
private func didShow(index: Int) {
currentIndex = cycleIndex(index: index)
if currentIndex >= totalCount || currentIndex < 0 {
return
}
myDelegate?.didSelect(livePlayView: self, inView: currentView, index: currentIndex)
}
private func cycleIndex(index: Int) -> Int {
if !isCanLoops {
return index
}
if index < 0 {
return totalCount - 1
}else if index >= totalCount {
return 0
}
return index
}
private func prefetchingShow(view: UIView, index: Int) {
let newIndex = cycleIndex(index: index)
if newIndex >= totalCount || newIndex < 0 {
return
}
myDelegate?.prefetch(livePlayView: self, inView: view, index: newIndex)
}
private func prefetchingNextView() {
prefetchingShow(view: bottomView, index: currentIndex + 1)
}
private func prefetchingTopView() {
prefetchingShow(view: topView, index: currentIndex - 1)
}
private func _scrollTo(index: Int) {
if index >= totalCount {
return
}
prefetchingShow(view: currentView, index: index)
didShow(index: index)
if totalCount <= 1 {
isScrollEnabled = false
return
}
prefetchingNextView()
prefetchingTopView()
}
private func _reloadData() {
if let count = dataSource?.numberofItems(livePlayView: self) {
totalCount = count
scrollTo(index: currentIndex)
}
}
private func contentOffsetDidChanged(offset: CGPoint) {
if offset.y >= 2 * itemH {
isScrollEnabled = false
(currentView, bottomView, topView) = (bottomView, topView, currentView)
didShow(index: currentIndex + 1)
prefetchingNextView()
reset()
isScrollEnabled = true
}else if (offset.y <= 0) {
isScrollEnabled = false
(currentView, topView, bottomView) = (topView, bottomView, currentView)
didShow(index: currentIndex - 1)
prefetchingTopView()
reset()
isScrollEnabled = true
}
}
}