首页bug修改
This commit is contained in:
parent
5fdccdad66
commit
f9f5b83e20
@ -89,6 +89,7 @@
|
|||||||
85606A9F2EEBE95A005D989D /* NRDashedLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A9E2EEBE95A005D989D /* NRDashedLineView.swift */; };
|
85606A9F2EEBE95A005D989D /* NRDashedLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85606A9E2EEBE95A005D989D /* NRDashedLineView.swift */; };
|
||||||
85859E5C2EF3FC5F0020D282 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 85859E552EF3FC5F0020D282 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
85859E5C2EF3FC5F0020D282 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 85859E552EF3FC5F0020D282 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
85859E662EF3FC6E0020D282 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85859E632EF3FC6E0020D282 /* NotificationService.swift */; };
|
85859E662EF3FC6E0020D282 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85859E632EF3FC6E0020D282 /* NotificationService.swift */; };
|
||||||
|
85859E682EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85859E672EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift */; };
|
||||||
85CF941D2EEBFEA6006467E3 /* NRCoinsPackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF941C2EEBFEA6006467E3 /* NRCoinsPackModel.swift */; };
|
85CF941D2EEBFEA6006467E3 /* NRCoinsPackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF941C2EEBFEA6006467E3 /* NRCoinsPackModel.swift */; };
|
||||||
85CF941F2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF941E2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift */; };
|
85CF941F2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF941E2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift */; };
|
||||||
85CF94212EEC050D006467E3 /* NRCoinsPackBuyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94202EEC050D006467E3 /* NRCoinsPackBuyView.swift */; };
|
85CF94212EEC050D006467E3 /* NRCoinsPackBuyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94202EEC050D006467E3 /* NRCoinsPackBuyView.swift */; };
|
||||||
@ -588,6 +589,7 @@
|
|||||||
85859E552EF3FC5F0020D282 /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
85859E552EF3FC5F0020D282 /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
85859E622EF3FC6E0020D282 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
85859E622EF3FC6E0020D282 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
85859E632EF3FC6E0020D282 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
85859E632EF3FC6E0020D282 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||||
|
85859E672EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRHomeMustReadTodayTransformer.swift; sourceTree = "<group>"; };
|
||||||
85CF941C2EEBFEA6006467E3 /* NRCoinsPackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackModel.swift; sourceTree = "<group>"; };
|
85CF941C2EEBFEA6006467E3 /* NRCoinsPackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackModel.swift; sourceTree = "<group>"; };
|
||||||
85CF941E2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackReceiveModel.swift; sourceTree = "<group>"; };
|
85CF941E2EEBFECF006467E3 /* NRCoinsPackReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackReceiveModel.swift; sourceTree = "<group>"; };
|
||||||
85CF94202EEC050D006467E3 /* NRCoinsPackBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackBuyView.swift; sourceTree = "<group>"; };
|
85CF94202EEC050D006467E3 /* NRCoinsPackBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRCoinsPackBuyView.swift; sourceTree = "<group>"; };
|
||||||
@ -1359,6 +1361,7 @@
|
|||||||
0398109E2ED069890006E317 /* M */ = {
|
0398109E2ED069890006E317 /* M */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
85859E672EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift */,
|
||||||
039810BB2ED43C8E0006E317 /* NRReadWhatViewTransformer.swift */,
|
039810BB2ED43C8E0006E317 /* NRReadWhatViewTransformer.swift */,
|
||||||
F34990B82EDEB1620039E939 /* NRHomeNovelModuleItem.swift */,
|
F34990B82EDEB1620039E939 /* NRHomeNovelModuleItem.swift */,
|
||||||
);
|
);
|
||||||
@ -2529,6 +2532,7 @@
|
|||||||
85CF94472EF001AD006467E3 /* NRMyUnlocksViewController.swift in Sources */,
|
85CF94472EF001AD006467E3 /* NRMyUnlocksViewController.swift in Sources */,
|
||||||
F3B8596B2EE91C9F0095A9CC /* NRStoreCoinsCell.swift in Sources */,
|
F3B8596B2EE91C9F0095A9CC /* NRStoreCoinsCell.swift in Sources */,
|
||||||
F3B859712EE94A1B0095A9CC /* NRFeedbackViewController.swift in Sources */,
|
F3B859712EE94A1B0095A9CC /* NRFeedbackViewController.swift in Sources */,
|
||||||
|
85859E682EFCD1D80020D282 /* NRHomeMustReadTodayTransformer.swift in Sources */,
|
||||||
85CF94392EEFE35A006467E3 /* NRLoginManager+Facebook.swift in Sources */,
|
85CF94392EEFE35A006467E3 /* NRLoginManager+Facebook.swift in Sources */,
|
||||||
F34348C72ED6CCBC00AA7E70 /* NRExploreNovelContentListViewController.swift in Sources */,
|
F34348C72ED6CCBC00AA7E70 /* NRExploreNovelContentListViewController.swift in Sources */,
|
||||||
039810B82ED431780006E317 /* NRHomeNovelReadWhatView.swift in Sources */,
|
039810B82ED431780006E317 /* NRHomeNovelReadWhatView.swift in Sources */,
|
||||||
|
|||||||
@ -5,116 +5,137 @@
|
|||||||
// Created by 澜声世纪 on 2025/11/26.
|
// Created by 澜声世纪 on 2025/11/26.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import SnapKit
|
import SnapKit
|
||||||
|
import UIKit
|
||||||
|
|
||||||
class NRExploreNovelContentListViewController: NRViewController {
|
class NRExploreNovelContentListViewController: NRViewController {
|
||||||
|
|
||||||
var menuItem: NRExploreNovelMenuItem?
|
var menuItem: NRExploreNovelMenuItem?
|
||||||
|
|
||||||
var contentType: NRExploreNovelContentViewController.ContentType = .today
|
var contentType: NRExploreNovelContentViewController.ContentType = .today
|
||||||
|
|
||||||
lazy var dataArr: [NRNovelModel] = []
|
lazy var dataArr: [NRNovelModel] = []
|
||||||
|
|
||||||
lazy var collectionViewLayout: UICollectionViewCompositionalLayout = {
|
lazy var collectionViewLayout: UICollectionViewCompositionalLayout = {
|
||||||
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)))
|
let item = NSCollectionLayoutItem(
|
||||||
|
layoutSize: .init(
|
||||||
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(60)), subitems: [item])
|
widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)))
|
||||||
|
|
||||||
|
let group = NSCollectionLayoutGroup.horizontal(
|
||||||
|
layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(60)),
|
||||||
|
subitems: [item])
|
||||||
|
|
||||||
let section = NSCollectionLayoutSection(group: group)
|
let section = NSCollectionLayoutSection(group: group)
|
||||||
section.interGroupSpacing = 8
|
section.interGroupSpacing = 8
|
||||||
section.contentInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0)
|
section.contentInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0)
|
||||||
|
|
||||||
let configuration = UICollectionViewCompositionalLayoutConfiguration()
|
let configuration = UICollectionViewCompositionalLayoutConfiguration()
|
||||||
|
|
||||||
let layout = UICollectionViewCompositionalLayout(section: section, configuration: configuration)
|
let layout = UICollectionViewCompositionalLayout(
|
||||||
|
section: section, configuration: configuration)
|
||||||
|
|
||||||
return layout
|
return layout
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var collectionView: NRCollectionView = {
|
lazy var collectionView: NRCollectionView = {
|
||||||
let collectionView = NRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
let collectionView = NRCollectionView(
|
||||||
|
frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dataSource = self
|
collectionView.dataSource = self
|
||||||
collectionView.contentInset = .init(top: 0, left: 0, bottom: 10, right: 0)
|
collectionView.contentInset = .init(top: 0, left: 0, bottom: 10, right: 0)
|
||||||
collectionView.register(NRExploreNovelContentListCell.self, forCellWithReuseIdentifier: "cell")
|
collectionView.register(
|
||||||
|
NRExploreNovelContentListCell.self, forCellWithReuseIdentifier: "cell")
|
||||||
return collectionView
|
return collectionView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@MainActor deinit {
|
@MainActor deinit {
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.backgroundImageView.isHidden = true
|
self.backgroundImageView.isHidden = true
|
||||||
self.view.backgroundColor = .clear
|
self.view.backgroundColor = .clear
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: NRNetworkReachableManager.networkStatusDidChangeNotification, object: nil)
|
NotificationCenter.default.addObserver(
|
||||||
|
self, selector: #selector(networkStatusDidChangeNotification),
|
||||||
|
name: NRNetworkReachableManager.networkStatusDidChangeNotification, object: nil)
|
||||||
|
|
||||||
nr_setupUI()
|
nr_setupUI()
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
await requestDataArr()
|
await requestDataArr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@objc private func networkStatusDidChangeNotification() {
|
@objc private func networkStatusDidChangeNotification() {
|
||||||
guard NRNetworkReachableManager.manager.isReachable == true, self.dataArr.isEmpty else { return }
|
guard NRNetworkReachableManager.manager.isReachable == true, self.dataArr.isEmpty else {
|
||||||
|
return
|
||||||
|
}
|
||||||
Task {
|
Task {
|
||||||
await requestDataArr()
|
await requestDataArr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NRExploreNovelContentListViewController {
|
extension NRExploreNovelContentListViewController {
|
||||||
|
|
||||||
private func nr_setupUI() {
|
private func nr_setupUI() {
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
collectionView.snp.makeConstraints { make in
|
collectionView.snp.makeConstraints { make in
|
||||||
make.left.right.bottom.equalToSuperview()
|
make.left.right.bottom.equalToSuperview()
|
||||||
make.top.equalToSuperview().offset(12)
|
make.top.equalToSuperview().offset(12)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||||
extension NRExploreNovelContentListViewController: UICollectionViewDelegate, UICollectionViewDataSource {
|
extension NRExploreNovelContentListViewController: UICollectionViewDelegate,
|
||||||
|
UICollectionViewDataSource
|
||||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
{
|
||||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! NRExploreNovelContentListCell
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
|
||||||
|
-> UICollectionViewCell
|
||||||
|
{
|
||||||
|
let cell =
|
||||||
|
collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
|
||||||
|
as! NRExploreNovelContentListCell
|
||||||
cell.menuItem = self.menuItem
|
cell.menuItem = self.menuItem
|
||||||
cell.row = indexPath.row
|
cell.row = indexPath.row
|
||||||
cell.model = dataArr[indexPath.row]
|
cell.model = dataArr[indexPath.row]
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int)
|
||||||
|
-> Int
|
||||||
|
{
|
||||||
return dataArr.count
|
return dataArr.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
let model = dataArr[indexPath.row]
|
let model = dataArr[indexPath.row]
|
||||||
let vc = NRNovelDetailViewController()
|
let vc = NRNovelDetailViewController()
|
||||||
vc.novelId = model.id ?? ""
|
vc.novelId = model.id ?? ""
|
||||||
self.navigationController?.pushViewController(vc, animated: true)
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NRExploreNovelContentListViewController {
|
extension NRExploreNovelContentListViewController {
|
||||||
|
|
||||||
private func requestDataArr() async {
|
private func requestDataArr() async {
|
||||||
guard let type = self.menuItem?.type else { return }
|
guard let type = self.menuItem?.type else { return }
|
||||||
guard let list = await NRHomeAPI.requestRankingCollection(type: type.rawValue, days: self.contentType.rawValue) else { return }
|
guard
|
||||||
|
let list = await NRHomeAPI.requestRankingCollection(
|
||||||
|
type: type.rawValue, days: self.contentType.rawValue)
|
||||||
|
else { return }
|
||||||
|
|
||||||
self.dataArr = list
|
self.dataArr = list
|
||||||
|
|
||||||
self.collectionView.reloadData()
|
self.collectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
47
ReaderHive/Class/Home/M/NRHomeMustReadTodayTransformer.swift
Normal file
47
ReaderHive/Class/Home/M/NRHomeMustReadTodayTransformer.swift
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// NRHomeMustReadTodayTransformer.swift
|
||||||
|
// ReaderHive
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import FSPagerView
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class NRHomeMustReadTodayTransformer: FSPagerViewTransformer {
|
||||||
|
|
||||||
|
nonisolated override init(type: FSPagerViewTransformerType) {
|
||||||
|
super.init(type: type)
|
||||||
|
}
|
||||||
|
|
||||||
|
nonisolated override func applyTransform(to attributes: FSPagerViewLayoutAttributes) {
|
||||||
|
MainActor.assumeIsolated {
|
||||||
|
guard let pagerView = self.pagerView else { return }
|
||||||
|
|
||||||
|
let itemWidth = pagerView.itemSize.width
|
||||||
|
let pagerWidth = pagerView.frame.width
|
||||||
|
|
||||||
|
// 目标左边距为 16
|
||||||
|
let leftMargin: CGFloat = 16
|
||||||
|
|
||||||
|
// FSPagerView 默认将 item 居中显示
|
||||||
|
// 当前 item 的中心点在 pagerView.width / 2
|
||||||
|
// 我们希望 item 的左侧距离边框为 16,即中心点应该在 (16 + itemWidth / 2)
|
||||||
|
let targetCenter = leftMargin + itemWidth / 2
|
||||||
|
let currentCenter = pagerWidth / 2
|
||||||
|
let offset = currentCenter - targetCenter
|
||||||
|
|
||||||
|
// 将所有 item 向左平移 offset 距离,实现靠左停留的效果
|
||||||
|
attributes.transform = CGAffineTransform(translationX: -offset, y: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonisolated override func proposedInteritemSpacing() -> CGFloat {
|
||||||
|
guard let pagerView = self.pagerView else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return MainActor.assumeIsolated {
|
||||||
|
return pagerView.interitemSpacing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,20 +5,21 @@
|
|||||||
// Created by 澜声世纪 on 2025/11/24.
|
// Created by 澜声世纪 on 2025/11/24.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import FSPagerView
|
||||||
import SnapKit
|
import SnapKit
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class NRHomeNovelMustReadTodayCell: FSPagerViewCell {
|
||||||
|
|
||||||
class NRHomeNovelMustReadTodayCell: UICollectionViewCell {
|
|
||||||
|
|
||||||
var model: NRNovelModel? {
|
var model: NRNovelModel? {
|
||||||
didSet {
|
didSet {
|
||||||
coverImageView.nr_setImage(model?.image_url)
|
coverImageView.nr_setImage(model?.image_url)
|
||||||
titleLabel.text = model?.name
|
titleLabel.text = model?.name
|
||||||
desLabel.text = model?.nr_description
|
desLabel.text = model?.nr_description
|
||||||
|
|
||||||
starView.grade = (model?.rate ?? 0) / 2
|
starView.grade = (model?.rate ?? 0) / 2
|
||||||
starView.text = NSNumber(value: model?.rate ?? 0).toString(maximumFractionDigits: 1, minimumFractionDigits: 1)
|
starView.text = NSNumber(value: model?.rate ?? 0).toString(maximumFractionDigits: 1, minimumFractionDigits: 1)
|
||||||
|
|
||||||
if let text = model?.category?.first, text.count > 0 {
|
if let text = model?.category?.first, text.count > 0 {
|
||||||
categoryView.isHidden = false
|
categoryView.isHidden = false
|
||||||
categoryLabel.text = text
|
categoryLabel.text = text
|
||||||
@ -27,19 +28,19 @@ class NRHomeNovelMustReadTodayCell: UICollectionViewCell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy var bgView: UIImageView = {
|
lazy var bgView: UIImageView = {
|
||||||
let view = UIImageView(image: UIImage(named: "home_cell_bg_image_01"))
|
let view = UIImageView(image: UIImage(named: "home_cell_bg_image_01"))
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var coverImageView: NRImageView = {
|
lazy var coverImageView: NRImageView = {
|
||||||
let imageView = NRImageView()
|
let imageView = NRImageView()
|
||||||
imageView.layer.cornerRadius = 4
|
imageView.layer.cornerRadius = 4
|
||||||
imageView.layer.masksToBounds = true
|
imageView.layer.masksToBounds = true
|
||||||
return imageView
|
return imageView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var categoryView: UIView = {
|
lazy var categoryView: UIView = {
|
||||||
let view = UIView()
|
let view = UIView()
|
||||||
view.backgroundColor = .black.withAlphaComponent(0.05)
|
view.backgroundColor = .black.withAlphaComponent(0.05)
|
||||||
@ -47,21 +48,21 @@ class NRHomeNovelMustReadTodayCell: UICollectionViewCell {
|
|||||||
view.layer.masksToBounds = true
|
view.layer.masksToBounds = true
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var categoryLabel: UILabel = {
|
lazy var categoryLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 10, weight: .regular)
|
label.font = .font(ofSize: 10, weight: .regular)
|
||||||
label.textColor = .black.withAlphaComponent(0.5)
|
label.textColor = .black.withAlphaComponent(0.5)
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var titleLabel: UILabel = {
|
lazy var titleLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 14, weight: .medium)
|
label.font = .font(ofSize: 14, weight: .medium)
|
||||||
label.textColor = .black
|
label.textColor = .black
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var desLabel: UILabel = {
|
lazy var desLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 10, weight: .regular)
|
label.font = .font(ofSize: 10, weight: .regular)
|
||||||
@ -69,17 +70,19 @@ class NRHomeNovelMustReadTodayCell: UICollectionViewCell {
|
|||||||
label.numberOfLines = 2
|
label.numberOfLines = 2
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var readNowBgView: UIView = {
|
lazy var readNowBgView: UIView = {
|
||||||
let view = NRGradientView()
|
let view = NRGradientView()
|
||||||
view.colors = [UIColor.F_3912_F.cgColor, UIColor.FF_4_A_4_A.cgColor, UIColor.FA_9_B_1_F.cgColor]
|
view.colors = [
|
||||||
|
UIColor.F_3912_F.cgColor, UIColor.FF_4_A_4_A.cgColor, UIColor.FA_9_B_1_F.cgColor,
|
||||||
|
]
|
||||||
view.startPoint = .init(x: 0, y: 0.5)
|
view.startPoint = .init(x: 0, y: 0.5)
|
||||||
view.endPoint = .init(x: 1, y: 0.5)
|
view.endPoint = .init(x: 1, y: 0.5)
|
||||||
view.layer.cornerRadius = 8
|
view.layer.cornerRadius = 8
|
||||||
view.layer.masksToBounds = true
|
view.layer.masksToBounds = true
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var readNowLabel: UILabel = {
|
lazy var readNowLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 14, weight: .medium)
|
label.font = .font(ofSize: 14, weight: .medium)
|
||||||
@ -87,17 +90,17 @@ class NRHomeNovelMustReadTodayCell: UICollectionViewCell {
|
|||||||
label.text = "Read Now".localized
|
label.text = "Read Now".localized
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var starView: NRStarGradeView = {
|
lazy var starView: NRStarGradeView = {
|
||||||
let view = NRStarGradeView()
|
let view = NRStarGradeView()
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
self.contentView.layer.cornerRadius = 12
|
self.contentView.layer.cornerRadius = 12
|
||||||
self.contentView.layer.masksToBounds = true
|
self.contentView.layer.masksToBounds = true
|
||||||
|
|
||||||
categoryLabel.text = "Satisfying"
|
categoryLabel.text = "Satisfying"
|
||||||
titleLabel.text = "A Strike to the Heart"
|
titleLabel.text = "A Strike to the Heart"
|
||||||
desLabel.text = "Haunted by fading memories, a man navigates a labyrinth of dreams and reality, uncovering truths that blur the line between past and present."
|
desLabel.text = "Haunted by fading memories, a man navigates a labyrinth of dreams and reality, uncovering truths that blur the line between past and present."
|
||||||
@ -109,11 +112,11 @@ class NRHomeNovelMustReadTodayCell: UICollectionViewCell {
|
|||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NRHomeNovelMustReadTodayCell {
|
extension NRHomeNovelMustReadTodayCell {
|
||||||
|
|
||||||
private func nr_setupUI() {
|
private func nr_setupUI() {
|
||||||
contentView.addSubview(bgView)
|
contentView.addSubview(bgView)
|
||||||
contentView.addSubview(coverImageView)
|
contentView.addSubview(coverImageView)
|
||||||
@ -124,57 +127,57 @@ extension NRHomeNovelMustReadTodayCell {
|
|||||||
contentView.addSubview(desLabel)
|
contentView.addSubview(desLabel)
|
||||||
contentView.addSubview(readNowBgView)
|
contentView.addSubview(readNowBgView)
|
||||||
readNowBgView.addSubview(readNowLabel)
|
readNowBgView.addSubview(readNowLabel)
|
||||||
|
|
||||||
bgView.snp.makeConstraints { make in
|
bgView.snp.makeConstraints { make in
|
||||||
make.edges.equalToSuperview()
|
make.edges.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
coverImageView.snp.makeConstraints { make in
|
coverImageView.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(12)
|
make.left.equalToSuperview().offset(12)
|
||||||
make.centerY.equalToSuperview()
|
make.centerY.equalToSuperview()
|
||||||
make.width.equalTo(100)
|
make.width.equalTo(100)
|
||||||
make.height.equalTo(150)
|
make.height.equalTo(150)
|
||||||
}
|
}
|
||||||
|
|
||||||
categoryView.snp.makeConstraints { make in
|
categoryView.snp.makeConstraints { make in
|
||||||
make.left.equalTo(coverImageView.snp.right).offset(12)
|
make.left.equalTo(coverImageView.snp.right).offset(12)
|
||||||
make.right.lessThanOrEqualToSuperview().offset(-12)
|
make.right.lessThanOrEqualToSuperview().offset(-12)
|
||||||
make.top.equalTo(coverImageView)
|
make.top.equalTo(coverImageView)
|
||||||
make.height.equalTo(20)
|
make.height.equalTo(20)
|
||||||
}
|
}
|
||||||
|
|
||||||
categoryLabel.snp.makeConstraints { make in
|
categoryLabel.snp.makeConstraints { make in
|
||||||
make.center.equalToSuperview()
|
make.center.equalToSuperview()
|
||||||
make.left.equalToSuperview().offset(8)
|
make.left.equalToSuperview().offset(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
titleLabel.snp.makeConstraints { make in
|
titleLabel.snp.makeConstraints { make in
|
||||||
make.left.equalTo(categoryView)
|
make.left.equalTo(categoryView)
|
||||||
make.top.equalTo(coverImageView).offset(24)
|
make.top.equalTo(coverImageView).offset(24)
|
||||||
make.right.lessThanOrEqualToSuperview().offset(-12)
|
make.right.lessThanOrEqualToSuperview().offset(-12)
|
||||||
}
|
}
|
||||||
|
|
||||||
starView.snp.makeConstraints { make in
|
starView.snp.makeConstraints { make in
|
||||||
make.left.equalTo(titleLabel)
|
make.left.equalTo(titleLabel)
|
||||||
make.top.equalTo(titleLabel.snp.bottom).offset(6)
|
make.top.equalTo(titleLabel.snp.bottom).offset(6)
|
||||||
}
|
}
|
||||||
|
|
||||||
desLabel.snp.makeConstraints { make in
|
desLabel.snp.makeConstraints { make in
|
||||||
make.left.equalTo(titleLabel)
|
make.left.equalTo(titleLabel)
|
||||||
make.top.equalTo(titleLabel.snp.bottom).offset(33)
|
make.top.equalTo(titleLabel.snp.bottom).offset(33)
|
||||||
make.right.lessThanOrEqualToSuperview().offset(-12)
|
make.right.lessThanOrEqualToSuperview().offset(-12)
|
||||||
}
|
}
|
||||||
|
|
||||||
readNowBgView.snp.makeConstraints { make in
|
readNowBgView.snp.makeConstraints { make in
|
||||||
make.left.equalTo(titleLabel)
|
make.left.equalTo(titleLabel)
|
||||||
make.bottom.equalTo(coverImageView)
|
make.bottom.equalTo(coverImageView)
|
||||||
make.right.equalToSuperview().offset(-12)
|
make.right.equalToSuperview().offset(-12)
|
||||||
make.height.equalTo(36)
|
make.height.equalTo(36)
|
||||||
}
|
}
|
||||||
|
|
||||||
readNowLabel.snp.makeConstraints { make in
|
readNowLabel.snp.makeConstraints { make in
|
||||||
make.center.equalToSuperview()
|
make.center.equalToSuperview()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,82 +5,88 @@
|
|||||||
// Created by 澜声世纪 on 2025/11/24.
|
// Created by 澜声世纪 on 2025/11/24.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import FSPagerView
|
||||||
import SnapKit
|
import SnapKit
|
||||||
|
import UIKit
|
||||||
import YYCategories
|
import YYCategories
|
||||||
|
|
||||||
class NRHomeNovelMustReadTodayView: NRHomeNovelHeaderContentView {
|
class NRHomeNovelMustReadTodayView: NRHomeNovelHeaderContentView {
|
||||||
|
|
||||||
|
|
||||||
var dataArr: [NRNovelModel] = [] {
|
var dataArr: [NRNovelModel] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
self.collectionView.reloadData()
|
self.pagerView.reloadData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy var pagerView: FSPagerView = {
|
||||||
lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
let pagerView = FSPagerView()
|
||||||
let layout = UICollectionViewFlowLayout()
|
pagerView.delegate = self
|
||||||
layout.scrollDirection = .horizontal
|
pagerView.dataSource = self
|
||||||
layout.itemSize = .init(width: 316, height: 174)
|
// 设置无限滚动
|
||||||
layout.minimumLineSpacing = 16
|
pagerView.isInfinite = true
|
||||||
return layout
|
// 设置自动滚动间隔
|
||||||
|
pagerView.automaticSlidingInterval = 5.0
|
||||||
|
// 设置 item 之间的间距
|
||||||
|
pagerView.interitemSpacing = 16
|
||||||
|
// 设置 item 大小
|
||||||
|
pagerView.itemSize = CGSize(width: 316, height: 174)
|
||||||
|
// 设置靠左停靠的 Transformer
|
||||||
|
pagerView.transformer = NRHomeMustReadTodayTransformer(type: .linear)
|
||||||
|
// 注册 Cell
|
||||||
|
pagerView.register(NRHomeNovelMustReadTodayCell.self, forCellWithReuseIdentifier: "cell")
|
||||||
|
return pagerView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var collectionView: NRCollectionView = {
|
|
||||||
let collectionView = NRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
|
||||||
collectionView.delegate = self
|
|
||||||
collectionView.dataSource = self
|
|
||||||
collectionView.showsHorizontalScrollIndicator = false
|
|
||||||
collectionView.contentInset = .init(top: 0, left: 16, bottom: 0, right: 16)
|
|
||||||
collectionView.register(NRHomeNovelMustReadTodayCell.self, forCellWithReuseIdentifier: "cell")
|
|
||||||
return collectionView
|
|
||||||
}()
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
self.titleLabel.text = "Must-Read Today".localized
|
self.titleLabel.text = "Must-Read Today".localized
|
||||||
|
|
||||||
nr_setupUI()
|
nr_setupUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor required init?(coder: NSCoder) {
|
@MainActor required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NRHomeNovelMustReadTodayView {
|
extension NRHomeNovelMustReadTodayView {
|
||||||
|
|
||||||
private func nr_setupUI() {
|
private func nr_setupUI() {
|
||||||
contentView.addSubview(collectionView)
|
contentView.addSubview(pagerView)
|
||||||
|
|
||||||
collectionView.snp.makeConstraints { make in
|
pagerView.snp.makeConstraints { make in
|
||||||
make.left.right.top.equalToSuperview()
|
make.left.right.top.equalToSuperview()
|
||||||
make.bottom.equalToSuperview()
|
make.bottom.equalToSuperview()
|
||||||
make.height.equalTo(self.collectionViewLayout.itemSize.height)
|
make.height.equalTo(174)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
// MARK: - FSPagerViewDataSource, FSPagerViewDelegate
|
||||||
extension NRHomeNovelMustReadTodayView: UICollectionViewDelegate, UICollectionViewDataSource {
|
extension NRHomeNovelMustReadTodayView: FSPagerViewDataSource, FSPagerViewDelegate {
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
func numberOfItems(in pagerView: FSPagerView) -> Int {
|
||||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! NRHomeNovelMustReadTodayCell
|
|
||||||
cell.model = self.dataArr[indexPath.row]
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
|
||||||
return self.dataArr.count
|
return self.dataArr.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell {
|
||||||
|
let cell =
|
||||||
|
pagerView.dequeueReusableCell(withReuseIdentifier: "cell", at: index)
|
||||||
|
as! NRHomeNovelMustReadTodayCell
|
||||||
|
cell.model = self.dataArr[index]
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func pagerView(_ pagerView: FSPagerView, didSelectItemAt index: Int) {
|
||||||
|
pagerView.deselectItem(at: index, animated: true)
|
||||||
|
|
||||||
let vc = NRNovelDetailViewController()
|
let vc = NRNovelDetailViewController()
|
||||||
vc.novelId = dataArr[indexPath.row].id ?? ""
|
vc.novelId = dataArr[index].id ?? ""
|
||||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果需要像之前的 UICollectionViewContentInset 一样在两边留白,FSPagerView 的处理方式通常是调整 itemSize 和 transformer
|
||||||
|
// 或者直接在布局层面控制。在这里我们通过 transform 效果或者间距来实现类似感观。
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class NRReadChapterCatalogModel: NSObject, SmartCodable {
|
|||||||
func parserEmpty() {
|
func parserEmpty() {
|
||||||
let chapterModel = NRReadChapterModel()
|
let chapterModel = NRReadChapterModel()
|
||||||
if self.is_lock == true {
|
if self.is_lock == true {
|
||||||
chapterModel.parserEmpty("Not unlocked yet".localized)
|
chapterModel.parserEmpty("Chapter Locked".localized)
|
||||||
} else {
|
} else {
|
||||||
chapterModel.parserEmpty("Loading".localized)
|
chapterModel.parserEmpty("Loading".localized)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,7 @@ class NRReadChapterModel: NSObject, SmartCodable {
|
|||||||
|
|
||||||
///解析一个空白页面
|
///解析一个空白页面
|
||||||
func parserEmpty(_ text: String) {
|
func parserEmpty(_ text: String) {
|
||||||
fullContent = NSMutableAttributedString(string: "\n\n\n\n\n" + text, attributes: NRNovelReadSetManager.manager.attributes(isTitle: true))
|
fullContent = NSMutableAttributedString(string: "\n\n\n\n\n" + text, attributes: NRNovelReadSetManager.manager.attributes(isTitle: false))
|
||||||
|
|
||||||
let pageModel = NRReadPageModel()
|
let pageModel = NRReadPageModel()
|
||||||
pageModel.content = fullContent
|
pageModel.content = fullContent
|
||||||
|
|||||||
@ -201,10 +201,10 @@ extension NRNovelReadViewModel {
|
|||||||
self.vc?.loadData()
|
self.vc?.loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.didDismissHandle = { [weak self] in
|
// view.didDismissHandle = { [weak self] in
|
||||||
guard let self = self else { return }
|
// guard let self = self else { return }
|
||||||
self.showVipRetainAlert(catalogModel)
|
// self.showVipRetainAlert(catalogModel)
|
||||||
}
|
// }
|
||||||
view.present(in: nil)
|
view.present(in: nil)
|
||||||
|
|
||||||
self.popView = view
|
self.popView = view
|
||||||
|
|||||||
@ -76,7 +76,7 @@
|
|||||||
"alert_title_01" = "Recommend this book?";
|
"alert_title_01" = "Recommend this book?";
|
||||||
"alert_detail_01" = "Help us share this story with others.";
|
"alert_detail_01" = "Help us share this story with others.";
|
||||||
"Yes, Recommend" = "Yes, Recommend";
|
"Yes, Recommend" = "Yes, Recommend";
|
||||||
"Not unlocked yet" = "Not unlocked yet";
|
"Chapter Locked" = "Chapter Locked";
|
||||||
"No data" = "No data";
|
"No data" = "No data";
|
||||||
"Coins" = "Coins";
|
"Coins" = "Coins";
|
||||||
"Bonus" = "Bonus";
|
"Bonus" = "Bonus";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user