banner优化
This commit is contained in:
parent
cf398971db
commit
93a8ea36c1
@ -212,5 +212,17 @@ extension UIColor {
|
|||||||
static func colorFFD791(alpha: CGFloat = 1) -> UIColor {
|
static func colorFFD791(alpha: CGFloat = 1) -> UIColor {
|
||||||
return color(hex: 0xFFD791, alpha: alpha)
|
return color(hex: 0xFFD791, alpha: alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func color262014(alpha: CGFloat = 1) -> UIColor {
|
||||||
|
return color(hex: 0x262014, alpha: alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func colorA69B89(alpha: CGFloat = 1) -> UIColor {
|
||||||
|
return color(hex: 0xA69B89, alpha: alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func colorFFD28F(alpha: CGFloat = 1) -> UIColor {
|
||||||
|
return color(hex: 0xFFD28F, alpha: alpha)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,107 +0,0 @@
|
|||||||
//
|
|
||||||
// SPZoomCollectionViewLayout.swift
|
|
||||||
// Thimra
|
|
||||||
//
|
|
||||||
// Created by Overseas on 2025/4/22.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
class SPZoomCollectionViewLayout: UICollectionViewFlowLayout {
|
|
||||||
|
|
||||||
let minimumScale: CGFloat = 0.08 // 调整缩放大小
|
|
||||||
|
|
||||||
private(set) var currentIndexPath: IndexPath = IndexPath(row: 0, section: 0)
|
|
||||||
|
|
||||||
|
|
||||||
private var cellWidth: CGFloat {
|
|
||||||
return itemSize.width + minimumLineSpacing
|
|
||||||
}
|
|
||||||
|
|
||||||
override func prepare() {
|
|
||||||
super.prepare()
|
|
||||||
scrollDirection = .horizontal
|
|
||||||
self.collectionView?.decelerationRate = .fast
|
|
||||||
let screenWidth = UIScreen.main.bounds.size.width
|
|
||||||
let insetLeft = (screenWidth - self.itemSize.width) / 2
|
|
||||||
collectionView?.contentInset = UIEdgeInsets(top: 0, left: insetLeft, bottom: 0, right: insetLeft)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
|
|
||||||
guard let collectionView = collectionView else { return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) }
|
|
||||||
|
|
||||||
let proposedRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView.bounds.width, height: collectionView.bounds.height)
|
|
||||||
|
|
||||||
guard let layoutAttributes = layoutAttributesForElements(in: proposedRect) else {
|
|
||||||
return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
|
|
||||||
}
|
|
||||||
|
|
||||||
let horizontalCenterX = proposedContentOffset.x + collectionView.bounds.width / 2
|
|
||||||
var offsetAdjustment = CGFloat.greatestFiniteMagnitude
|
|
||||||
// ydLog(message: "offsetAdjustment = \(offsetAdjustment)")
|
|
||||||
// ydLog(message: "horizontalCenterX = \(horizontalCenterX)")
|
|
||||||
|
|
||||||
var currentIndexPath: IndexPath = IndexPath(row: 0, section: 0)
|
|
||||||
for attributes in layoutAttributes {
|
|
||||||
let itemHorizontalCenterX = attributes.center.x
|
|
||||||
let distance = itemHorizontalCenterX - horizontalCenterX
|
|
||||||
// ydLog(message: "distance = \(distance)")
|
|
||||||
//离中心距离最近的
|
|
||||||
if abs(distance) < abs(offsetAdjustment) {
|
|
||||||
offsetAdjustment = distance
|
|
||||||
currentIndexPath = attributes.indexPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.currentIndexPath = currentIndexPath
|
|
||||||
|
|
||||||
let point = CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
|
|
||||||
// ydLog(message: "proposedContentOffset = \(proposedContentOffset)")
|
|
||||||
// ydLog(message: "offsetAdjustment = \(offsetAdjustment)")
|
|
||||||
// ydLog(message: "point = \(point)")
|
|
||||||
// ydLog(message: "currentIndex = \(currentIndex)")
|
|
||||||
|
|
||||||
return point
|
|
||||||
}
|
|
||||||
|
|
||||||
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
|
|
||||||
guard let collectionView = collectionView else { return nil }
|
|
||||||
|
|
||||||
let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
|
|
||||||
let attributes = super.layoutAttributesForElements(in: rect)?.compactMap { $0.copy() as? UICollectionViewLayoutAttributes }
|
|
||||||
|
|
||||||
for attribute in attributes ?? [] {
|
|
||||||
let distance = visibleRect.midX - attribute.center.x
|
|
||||||
let normalizedDistance = distance / (collectionView.bounds.width * 0.5)
|
|
||||||
let zoom = 1 - abs(normalizedDistance) * minimumScale
|
|
||||||
|
|
||||||
//缩放
|
|
||||||
let scaleTransform = CGAffineTransform(scaleX: zoom, y: zoom)
|
|
||||||
|
|
||||||
|
|
||||||
//旋转
|
|
||||||
let rotationAngle = kSPAngleToRadians(angle: -normalizedDistance * 4)
|
|
||||||
let rotationTransform = CGAffineTransform(rotationAngle: rotationAngle)
|
|
||||||
|
|
||||||
// 组合旋转和缩放变换
|
|
||||||
let combinedTransform = rotationTransform.concatenating(scaleTransform)
|
|
||||||
// 应用变换
|
|
||||||
attribute.transform = combinedTransform
|
|
||||||
|
|
||||||
var alpha = 1.8 - abs(normalizedDistance)
|
|
||||||
if alpha < 0 {
|
|
||||||
alpha = 0
|
|
||||||
} else if alpha > 1 {
|
|
||||||
alpha = 1
|
|
||||||
}
|
|
||||||
attribute.alpha = alpha
|
|
||||||
}
|
|
||||||
|
|
||||||
return attributes
|
|
||||||
}
|
|
||||||
|
|
||||||
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -50,21 +50,17 @@ class SPHomeHeaderView: UICollectionReusableView {
|
|||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var bannerLayout: SPZoomCollectionViewLayout = {
|
private lazy var bannerView: ZKCycleScrollView = {
|
||||||
let layout = SPZoomCollectionViewLayout()
|
let view = ZKCycleScrollView(frame: .zero, shouldInfiniteLoop: true)
|
||||||
layout.itemSize = .init(width: 234, height: Self.bannerHeight())
|
view.itemSize = .init(width: 234, height: Self.bannerHeight())
|
||||||
layout.minimumLineSpacing = 10
|
view.itemAlpha = true
|
||||||
layout.minimumInteritemSpacing = 0
|
view.itemZoomScale = 0.9
|
||||||
return layout
|
view.itemSpacing = 10
|
||||||
}()
|
view.rotationAngle = 5
|
||||||
|
|
||||||
private lazy var bannerView: SPCollectionView = {
|
|
||||||
let view = SPCollectionView(frame: .zero, collectionViewLayout: bannerLayout)
|
|
||||||
view.delegate = self
|
view.delegate = self
|
||||||
view.dataSource = self
|
view.dataSource = self
|
||||||
view.showsVerticalScrollIndicator = false
|
view.hidesPageControl = true
|
||||||
view.showsHorizontalScrollIndicator = false
|
view.register(SPHomeZoomBannerCell.self, forCellWithReuseIdentifier: "banner")
|
||||||
SPHomeZoomBannerCell.registerCell(collectionView: view)
|
|
||||||
|
|
||||||
view.snp.makeConstraints { make in
|
view.snp.makeConstraints { make in
|
||||||
make.width.equalTo(kSPScreenWidth)
|
make.width.equalTo(kSPScreenWidth)
|
||||||
@ -153,6 +149,28 @@ extension SPHomeHeaderView: UICollectionViewDelegate, UICollectionViewDataSource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- ZKCycleScrollViewDelegate & ZKCycleScrollViewDataSource --------------
|
||||||
|
extension SPHomeHeaderView: ZKCycleScrollViewDelegate, ZKCycleScrollViewDataSource {
|
||||||
|
|
||||||
|
func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, cellForItemAt index: Int) -> ZKCycleScrollViewCell {
|
||||||
|
let cell = cycleScrollView.dequeueReusableCell(withReuseIdentifier: "banner", for: index) as! SPHomeZoomBannerCell
|
||||||
|
cell.model = self.viewModel?.moduleModel?.bannerData?[index]
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func numberOfItems(in cycleScrollView: ZKCycleScrollView) -> Int {
|
||||||
|
return self.viewModel?.moduleModel?.bannerData?.count ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, didSelectItemAt index: Int) {
|
||||||
|
let model = self.viewModel?.moduleModel?.bannerData?[index]
|
||||||
|
|
||||||
|
let vc = SPPlayerDetailViewController()
|
||||||
|
vc.shortPlayId = model?.short_play_id
|
||||||
|
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extension SPHomeHeaderView {
|
extension SPHomeHeaderView {
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class SPHomeZoomBannerCell: SPCollectionViewCell {
|
class SPHomeZoomBannerCell: ZKCycleScrollViewCell {
|
||||||
|
|
||||||
var model: SPShortModel? {
|
var model: SPShortModel? {
|
||||||
didSet {
|
didSet {
|
||||||
|
@ -25,7 +25,6 @@ class SPMineMemberNoView: UIView {
|
|||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
||||||
private lazy var activateButton: UIButton = {
|
private lazy var activateButton: UIButton = {
|
||||||
let button = JXButton(type: .custom)
|
let button = JXButton(type: .custom)
|
||||||
button.leftAnyRightmargin = 13
|
button.leftAnyRightmargin = 13
|
||||||
@ -36,9 +35,27 @@ class SPMineMemberNoView: UIView {
|
|||||||
button.layer.masksToBounds = true
|
button.layer.masksToBounds = true
|
||||||
button.layer.borderWidth = 1
|
button.layer.borderWidth = 1
|
||||||
button.layer.borderColor = UIColor.colorFFD791().cgColor
|
button.layer.borderColor = UIColor.colorFFD791().cgColor
|
||||||
|
button.backgroundColor = .color262014()
|
||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var textLabel1: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontMedium(ofSize: 12)
|
||||||
|
label.textColor = .colorA69B89()
|
||||||
|
label.text = "Members can enjoy".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var textLabel2: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .fontMedium(ofSize: 12)
|
||||||
|
label.textColor = .colorFFD28F()
|
||||||
|
label.text = "Unlimited access to all series".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
_setupUI()
|
_setupUI()
|
||||||
@ -56,6 +73,8 @@ extension SPMineMemberNoView {
|
|||||||
addSubview(iconImageView)
|
addSubview(iconImageView)
|
||||||
addSubview(titleLabel)
|
addSubview(titleLabel)
|
||||||
addSubview(activateButton)
|
addSubview(activateButton)
|
||||||
|
addSubview(textLabel1)
|
||||||
|
addSubview(textLabel2)
|
||||||
|
|
||||||
iconImageView.snp.makeConstraints { make in
|
iconImageView.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(12)
|
make.left.equalToSuperview().offset(12)
|
||||||
@ -73,6 +92,16 @@ extension SPMineMemberNoView {
|
|||||||
make.bottom.equalToSuperview().offset(-14)
|
make.bottom.equalToSuperview().offset(-14)
|
||||||
make.height.equalTo(28)
|
make.height.equalTo(28)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textLabel1.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.bottom.equalTo(textLabel2.snp.top).offset(-kSPMainW(5))
|
||||||
|
}
|
||||||
|
|
||||||
|
textLabel2.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(textLabel1)
|
||||||
|
make.bottom.equalToSuperview().offset(-kSPMainW(12))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,8 @@
|
|||||||
"Log in" = "Log in";
|
"Log in" = "Log in";
|
||||||
"You are not a member yet" = "You are not a member yet";
|
"You are not a member yet" = "You are not a member yet";
|
||||||
"Activate" = "Activate";
|
"Activate" = "Activate";
|
||||||
|
"Members can enjoy" = "Members can enjoy";
|
||||||
|
"Unlimited access to all series" = "Unlimited access to all series";
|
||||||
|
|
||||||
|
|
||||||
"kLoginAgreementText" = "By continuing, you agree to the User Agreement and Privacy Policy";
|
"kLoginAgreementText" = "By continuing, you agree to the User Agreement and Privacy Policy";
|
||||||
|
@ -128,6 +128,20 @@ public enum ZKScrollDirection: Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///item渐隐效果
|
||||||
|
open var itemAlpha = false {
|
||||||
|
didSet {
|
||||||
|
flowLayout.itemAlpha = itemAlpha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///旋转角度
|
||||||
|
open var rotationAngle = 0.0 {
|
||||||
|
didSet {
|
||||||
|
flowLayout.rotationAngle = rotationAngle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@IBInspectable open var hidesPageControl: Bool = false {
|
@IBInspectable open var hidesPageControl: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
pageControl?.isHidden = hidesPageControl
|
pageControl?.isHidden = hidesPageControl
|
||||||
|
@ -45,6 +45,10 @@ import UIKit
|
|||||||
open class ZKCycleScrollViewFlowLayout: UICollectionViewFlowLayout {
|
open class ZKCycleScrollViewFlowLayout: UICollectionViewFlowLayout {
|
||||||
|
|
||||||
open var zoomScale: CGFloat = 1.0
|
open var zoomScale: CGFloat = 1.0
|
||||||
|
///item渐隐效果
|
||||||
|
open var itemAlpha = false
|
||||||
|
///旋转角度
|
||||||
|
open var rotationAngle = 0.0
|
||||||
|
|
||||||
override open func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
|
override open func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
|
||||||
return true
|
return true
|
||||||
@ -74,19 +78,48 @@ open class ZKCycleScrollViewFlowLayout: UICollectionViewFlowLayout {
|
|||||||
default:
|
default:
|
||||||
let offset = collectionView.bounds.midX;
|
let offset = collectionView.bounds.midX;
|
||||||
let distanceForScale = itemSize.width + minimumLineSpacing;
|
let distanceForScale = itemSize.width + minimumLineSpacing;
|
||||||
|
|
||||||
|
|
||||||
for attr in attributes {
|
for attr in attributes {
|
||||||
var scale: CGFloat = 0.0;
|
var scale: CGFloat = 0.0;
|
||||||
let distance = abs(offset - attr.center.x)
|
let distance = offset - attr.center.x
|
||||||
if distance >= distanceForScale {
|
let abs_distance = abs(distance)
|
||||||
|
let screenScale = distance / (collectionView.bounds.width)
|
||||||
|
spLog(message: "++++++++++screenScale = \(screenScale), distanceForScale = \(distanceForScale), distance = \(abs_distance)")
|
||||||
|
|
||||||
|
if abs_distance >= distanceForScale {
|
||||||
scale = zoomScale;
|
scale = zoomScale;
|
||||||
} else if distance == 0.0 {
|
} else if abs_distance == 0.0 {
|
||||||
scale = 1.0
|
scale = 1.0
|
||||||
attr.zIndex = 1
|
attr.zIndex = 1
|
||||||
} else {
|
} else {
|
||||||
scale = zoomScale + (distanceForScale - distance) * (1.0 - zoomScale) / distanceForScale
|
scale = zoomScale + (distanceForScale - abs_distance) * (1.0 - zoomScale) / distanceForScale
|
||||||
}
|
}
|
||||||
attr.transform = CGAffineTransform(scaleX: scale, y: scale)
|
|
||||||
|
if itemAlpha {
|
||||||
|
var alpha = 1 - abs(screenScale)
|
||||||
|
if alpha < 0 {
|
||||||
|
alpha = 0
|
||||||
|
} else if alpha > 1 {
|
||||||
|
alpha = 1
|
||||||
|
}
|
||||||
|
attr.alpha = alpha
|
||||||
|
} else {
|
||||||
|
attr.alpha = 1
|
||||||
|
}
|
||||||
|
//缩放
|
||||||
|
let scaleTransform = CGAffineTransform(scaleX: scale, y: scale)
|
||||||
|
|
||||||
|
//旋转
|
||||||
|
let rotationAngle = kSPAngleToRadians(angle: -screenScale * self.rotationAngle)
|
||||||
|
let rotationTransform = CGAffineTransform(rotationAngle: rotationAngle)
|
||||||
|
|
||||||
|
// attr.transform = CGAffineTransform(scaleX: scale, y: scale)
|
||||||
|
|
||||||
|
// 组合旋转和缩放变换
|
||||||
|
let combinedTransform = rotationTransform.concatenating(scaleTransform)
|
||||||
|
// 应用变换
|
||||||
|
attr.transform = combinedTransform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user