角色list

This commit is contained in:
mh 2025-11-11 14:42:47 +08:00
parent 2c6bb330af
commit 8f61a1e969
9 changed files with 115 additions and 88 deletions

View File

@ -18,42 +18,58 @@ final class TopHeaderManager {
return view
}()
private var hostingView: UIView?
private var topConstraint: Constraint?
private var heightConstraint: Constraint?
private init() {}
var jumpPublisher: AnyPublisher<JumpTarget, Never> {
headerView.jumpPublisher
// CLTopHeaderView
// CLTopHeaderView
@discardableResult
func buildAndAttach(to superView: UIView) -> CLTopHeaderView {
if let existing = superView.subviews.first(where: { $0 is CLTopHeaderView }) as? CLTopHeaderView {
return existing
}
let header = CLTopHeaderView()
superView.addSubview(header)
header.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.height.equalTo(UIDevice().navHeight)
}
return header
}
func attachIfNeeded(to viewController: UIViewController) {
guard hostingView !== viewController.view else { return }
detach()
let container = viewController.view!
container.addSubview(headerView)
headerView.snp.makeConstraints { make in
topConstraint = make.top.equalToSuperview().constraint
make.leading.trailing.equalToSuperview()
heightConstraint = make.height.equalTo(UIDevice().navHeight).constraint
}
hostingView = container
headerView.isHidden = false
}
func show() {
headerView.isHidden = false
}
func hide() {
headerView.isHidden = true
}
func detach() {
headerView.removeFromSuperview()
hostingView = nil
}
// private var hostingView: UIView?
// private var topConstraint: Constraint?
// private var heightConstraint: Constraint?
//
// private init() {}
//
// var jumpPublisher: AnyPublisher<JumpTarget, Never> {
// headerView.jumpPublisher
// }
//
// func attachIfNeeded(to viewController: UIViewController) {
// guard hostingView !== viewController.view else { return }
// detach()
// let container = viewController.view!
// container.addSubview(headerView)
// headerView.snp.makeConstraints { make in
// topConstraint = make.top.equalToSuperview().constraint
// make.leading.trailing.equalToSuperview()
// heightConstraint = make.height.equalTo(UIDevice().navHeight).constraint
// }
// hostingView = container
// headerView.isHidden = false
// }
//
// func show() {
// headerView.isHidden = false
// }
//
// func hide() {
// headerView.isHidden = true
// }
//
// func detach() {
// headerView.removeFromSuperview()
// hostingView = nil
// }
}

View File

@ -27,17 +27,27 @@ struct RoleListModel: Codable {
var rows: [RoleItem] = []
}
enum RoleSourceType: Int, Codable {
case novel
case video
case other
}
struct RoleItem: Codable {
var id: String = ""
var name: String = ""
var coverImage: String = ""
var id: String?
var name: String?
var coverImage: String?
//
var sourceCoverImage: String?
var sourceName: String?
//
var headPortrait: String = ""
var headPortrait: String?
var score: Double?
var description: String = ""
var updateTime: String = ""
var sourceId: String = ""
var sourceType: Int = 0
var description: String?
var updateTime: String?
var sourceId: String?
// 0:;1:;2:
var sourceType: RoleSourceType?
var commonCount: Int?
var tags: [tagItem] = []
}

View File

@ -28,6 +28,9 @@ class FriendsRootHomeController: CLTabRootController<FriendsRootHomeView> {
// view.showEmpty(text: "Friends Coming soon")
// Tab Header
_ = TopHeaderManager.shared.buildAndAttach(to: view)
setupViews()
setupDats()
setupEvents()

View File

@ -23,6 +23,8 @@ class HomePageRootController: CLTabRootController<HomePageRootView> {
//container.viewModel = viewModel
container.setupViewModel(vm: viewModel)
// Tab Header
_ = TopHeaderManager.shared.buildAndAttach(to: view)
// Do any additional setup after loading the view.
// view.showEmpty(text: " Coming soon")

View File

@ -34,6 +34,7 @@ class HomePageRootView: UIView {
}
private func setupViews() {
// TopHeaderManager.shared.addFromSuperView(self)
emptyView = {
let v = UIView()

View File

@ -17,6 +17,9 @@ class MeRootPageController: CLTabRootController<MeRootPageView> {
override func viewDidLoad() {
super.viewDidLoad()
// Tab Header
_ = TopHeaderManager.shared.buildAndAttach(to: view)
setupViews()
setupDats()
setupEvents()

View File

@ -20,7 +20,6 @@ class CLRoleCollectionCell: UICollectionViewCell {
lazy var bookImgView: UIImageView = {
let imgView = UIImageView()
imgView.backgroundColor = .blue
imgView.cornerRadius = 7
return imgView
}()
@ -135,12 +134,13 @@ class CLRoleCollectionCell: UICollectionViewCell {
func setupData(item: RoleItem) {
descLab.text = item.description
nameLab.text = item.name
coverImgView.sd_setImage(with: URL(string: item.coverImage), placeholderImage: nil)
tagLab.text = item.tags.compactMap { $0.name }.joined(separator: "/")
// 0:;1:;2:
self.bookBgImgView.isHidden = item.sourceType != 0
self.playImgView.isHidden = item.sourceType != 1
// coverImgView.
coverImgView.sd_setImage(with: URL(string: item.coverImage ?? ""), placeholderImage: nil)
bookImgView.sd_setImage(with: URL(string: item.sourceCoverImage ?? ""), placeholderImage: nil)
tagLab.text = item.tags.compactMap { "#\($0.name)" }.joined(separator: "/")
sourceLab.text = item.score?.truncateString(places: 1)
self.bookBgImgView.isHidden = item.sourceType != .novel
self.playImgView.isHidden = item.sourceType != .video
self.remindLab.text = item.sourceName
}
// MARK: subviews

View File

@ -13,7 +13,7 @@ import Combine
class RolesRootPageView: CLContainer {
let itemWidth: CGFloat = (UIScreen.width - 30.0) / 2.0
var jumpPublisher: AnyPublisher<JumpTarget, Never> { topView.jumpPublisher }
var jumpPublisher: AnyPublisher<JumpTarget, Never> { TopHeaderManager.shared.buildAndAttach(to: self).jumpPublisher }
// private lazy var pagingView = JXPagingListRefreshView(delegate: self)
// lazy var headerView:
@ -25,33 +25,10 @@ class RolesRootPageView: CLContainer {
var data: [RoleItem] = []
var hasMoreData: Bool = true //
let remind: [String] = [
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]"
]
lazy var topView: CLTopHeaderView = {
let view = CLTopHeaderView()
return view
}()
// lazy var topView: CLTopHeaderView = {
// let view = CLTopHeaderView()
// return view
// }()
lazy var tagsView: CLRoleTagsView = {
let tagsView = CLRoleTagsView()
@ -85,19 +62,13 @@ class RolesRootPageView: CLContainer {
}
private func setupViews() {
addSubview(self.topView)
// addSubview(tagsChooseView)
// TopHeaderManager.shared.addFromSuperView(self)
addSubview(tagsView)
addSubview(collectionView)
topView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.height.equalTo(UIDevice().navHeight)
}
tagsView.snp.makeConstraints { make in
make.right.left.equalToSuperview()
make.top.equalTo(topView.snp.bottom).offset(0)
make.top.equalTo(TopHeaderManager.shared.buildAndAttach(to: self).snp.bottom).offset(0)
}
collectionView.snp.makeConstraints { make in
@ -206,7 +177,7 @@ extension RolesRootPageView: UICollectionViewDelegate, UICollectionViewDataSourc
let maxHeight = lineHeight * CGFloat(maxLines)
// maxHeight
let textSize = model.name.boundingRect(
let textSize = (model.name ?? "").boundingRect(
with: CGSize(width: itemWidth - 20, height: maxHeight), //
options: [.usesLineFragmentOrigin, .usesFontLeading],
attributes: [.font: font],
@ -216,8 +187,7 @@ extension RolesRootPageView: UICollectionViewDelegate, UICollectionViewDataSourc
let textH = min(textSize.height, maxHeight)
// remind 使
let remindIndex = indexPath.item % remind.count
let remindText = remind[remindIndex]
let remindText = model.sourceName ?? ""
let remindH = remindText.boundingRect(
with: CGSize(width: itemWidth - 20.0, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,

View File

@ -0,0 +1,22 @@
//
// DoubleExt.swift
// Visual_Novel_iOS
//
// Created by mh on 2025/11/11.
//
import Foundation
extension Double {
///
func truncate(places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return floor(self * divisor) / divisor
}
///
func truncateString(places: Int) -> String {
let truncated = truncate(places: places)
return String(format: "%.\(places)f", truncated)
}
}