角色模块标签
This commit is contained in:
parent
9fb598f906
commit
a3b1677409
|
@ -121,19 +121,14 @@ class CLTopHeaderView: UIView {
|
|||
|
||||
// MARK: Action
|
||||
@objc func searchImgViewClicked() {
|
||||
print("111111")
|
||||
// UIWindow.getTopViewController()?.navigationController?.pushViewController(TestEntrancesController(), animated: true)
|
||||
|
||||
subject.send(.search)
|
||||
}
|
||||
|
||||
@objc func calendarImgViewClicked() {
|
||||
print("2222")
|
||||
subject.send(.check)
|
||||
}
|
||||
|
||||
@objc func discordImgViewClicked() {
|
||||
print("333")
|
||||
subject.send(.discord)
|
||||
}
|
||||
|
||||
|
|
|
@ -188,6 +188,61 @@ class EPChipFilterButton: EPChipButton {
|
|||
}
|
||||
}
|
||||
|
||||
class EPRoleTagsFilterButton: EPChipButton {
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = UIColor(hex: "#BAC5D2") // EPSystemToken.color(.surfaceElementNormal)
|
||||
layer.borderWidth = 0
|
||||
|
||||
addSubview(textLabel)
|
||||
textLabel.snp.makeConstraints { make in
|
||||
make.edges.equalTo(self).inset(paddingInsets).priority(.high)
|
||||
make.height.equalTo(chipButtonHeight)
|
||||
}
|
||||
}
|
||||
|
||||
override func setupTheme() {
|
||||
super.setupTheme()
|
||||
layer.borderColor = UIColor(hex: "#0065FF").cgColor // EPSystemToken.color(.primaryVariantNormal).cgColor
|
||||
}
|
||||
|
||||
override var paddingInsets: UIEdgeInsets {
|
||||
UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize{
|
||||
return CGSize(width: textLabel.size.width + 32, height: chipButtonHeight)
|
||||
}
|
||||
|
||||
override var isHighlighted: Bool {
|
||||
didSet {
|
||||
backgroundColor = isSelected
|
||||
? (isHighlighted ? UIColor(hex: "#BAC5D2") : UIColor(hex: "#0065FF"))
|
||||
: (isHighlighted ? UIColor(hex: "#0065FF") : UIColor(hex: "#BAC5D2"))
|
||||
}
|
||||
}
|
||||
|
||||
override var isSelected: Bool {
|
||||
didSet {
|
||||
backgroundColor = isSelected
|
||||
? UIColor(hex: "#0065FF")
|
||||
: UIColor(hex: "#BAC5D2")
|
||||
layer.borderWidth = isSelected ? 1 : 0
|
||||
}
|
||||
}
|
||||
|
||||
override var isEnabled: Bool {
|
||||
didSet {
|
||||
textLabel.textColor = isEnabled
|
||||
? UIColor.white
|
||||
: UIColor(hex: "#E5F1FF")
|
||||
backgroundColor = isEnabled
|
||||
? UIColor.c.csen
|
||||
: UIColor.c.csed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EPChipCenterIconButton: EPChipButton {
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
|
|
@ -45,7 +45,7 @@ class HorizontalScrollTagsView: UIView {
|
|||
private var stackView: UIStackView!
|
||||
|
||||
/// 标签按钮数组
|
||||
private var tagButtons: [EPChipFilterButton] = []
|
||||
private var tagButtons: [EPRoleTagsFilterButton] = []
|
||||
|
||||
/// 标签数据源
|
||||
private var tags: [String] = []
|
||||
|
@ -163,7 +163,7 @@ class HorizontalScrollTagsView: UIView {
|
|||
|
||||
// 创建新按钮
|
||||
for (index, tag) in tags.enumerated() {
|
||||
let button = EPChipFilterButton()
|
||||
let button = EPRoleTagsFilterButton()
|
||||
button.text = tag
|
||||
button.tag = index
|
||||
button.addTarget(self, action: #selector(tagButtonTapped(_:)), for: .touchUpInside)
|
||||
|
@ -173,7 +173,7 @@ class HorizontalScrollTagsView: UIView {
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func tagButtonTapped(_ sender: EPChipFilterButton) {
|
||||
@objc private func tagButtonTapped(_ sender: EPRoleTagsFilterButton) {
|
||||
let index = sender.tag
|
||||
|
||||
// 切换选中状态
|
||||
|
@ -184,7 +184,6 @@ class HorizontalScrollTagsView: UIView {
|
|||
selectedIndices.insert(index)
|
||||
sender.isSelected = true
|
||||
}
|
||||
|
||||
// 通知选择变更
|
||||
notifySelectionChanged()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// CLRoleTagsModel.swift
|
||||
// Visual_Novel_iOS
|
||||
//
|
||||
// Created by mh on 2025/10/17.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct CLRoleTagsModel: Codable {
|
||||
var name: String = ""
|
||||
var isSelected: Bool = false
|
||||
}
|
|
@ -129,7 +129,7 @@ class CLRoleCollectionCell: UICollectionViewCell {
|
|||
contentView.addSubview(remindLab)
|
||||
|
||||
coverImgView.snp.makeConstraints { make in
|
||||
make.width.equalTo(cellWidth)
|
||||
make.width.equalTo(cellWidth).priority(999)
|
||||
make.height.equalTo(coverImgView.snp.width).multipliedBy(4.0 / 3.0)
|
||||
make.top.left.right.equalToSuperview()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
//
|
||||
// CLRoleTagsView.swift
|
||||
// Visual_Novel_iOS
|
||||
//
|
||||
// Created by mh on 2025/10/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class CLRoleTagsView: UIView {
|
||||
|
||||
// let tags = ["#浪漫", "#温柔", "#多愁善感", "#深情", "#this is good", "#沙瓦迪", "#科技哈", "#等好a", "#a"]
|
||||
var tagModels: [CLRoleTagsModel] = [
|
||||
CLRoleTagsModel(name: "#浪漫浪漫浪漫浪漫浪漫浪漫浪漫浪漫浪漫漫浪漫浪漫浪漫漫浪漫浪漫浪漫漫浪漫浪漫浪漫", isSelected: false),
|
||||
CLRoleTagsModel(name: "#温柔", isSelected: false),
|
||||
CLRoleTagsModel(name: "#多愁善感", isSelected: false),
|
||||
CLRoleTagsModel(name: "#this is good", isSelected: false),
|
||||
CLRoleTagsModel(name: "#沙瓦迪", isSelected: false),
|
||||
CLRoleTagsModel(name: "#科技哈", isSelected: false),
|
||||
CLRoleTagsModel(name: "#等好a", isSelected: false),
|
||||
CLRoleTagsModel(name: "#a", isSelected: false),
|
||||
CLRoleTagsModel(name: "#浪漫", isSelected: false),
|
||||
]
|
||||
|
||||
lazy var collectionView: AutoHeightCollectionView = {
|
||||
let layout = TagFlowLayout()
|
||||
layout.interItemSpacing = 10 // 横向间距
|
||||
layout.lineSpacing = 8
|
||||
layout.maxLineWidth = UIScreen.width - 20.0
|
||||
layout.delegate = self
|
||||
|
||||
let collectionView = AutoHeightCollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.backgroundColor = .clear
|
||||
collectionView.setContentHuggingPriority(.required, for: .vertical)
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
collectionView.register(RoleTagCollectionCell.self, forCellWithReuseIdentifier: "RoleTagCollectionCell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
setupSubviews()
|
||||
// setupDatas()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: Subviews
|
||||
func setupSubviews() {
|
||||
|
||||
addSubview(collectionView)
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: data
|
||||
private func setupDatas() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
extension CLRoleTagsView: UICollectionViewDataSource, UICollectionViewDelegate, TagFlowLayoutDelegate {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
tagModels.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell: RoleTagCollectionCell = collectionView.dequeueReusableCell(withReuseIdentifier: "RoleTagCollectionCell", for: indexPath) as! RoleTagCollectionCell
|
||||
|
||||
cell.setupData(model: tagModels[indexPath.item])
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
print("点击了标签:\(tagModels[indexPath.item].name)")
|
||||
tagModels[indexPath.item].isSelected.toggle()
|
||||
// collectionView.reloadItems(at: [indexPath])
|
||||
collectionView.reloadData()
|
||||
|
||||
}
|
||||
|
||||
// 根据文字计算 size
|
||||
func collectionView(_ collectionView: UICollectionView,
|
||||
layout: TagFlowLayout,
|
||||
sizeForItemAt indexPath: IndexPath) -> CGSize {
|
||||
let text = tagModels[indexPath.item].name
|
||||
let font = UIFont.boldSystemFont(ofSize: 12)
|
||||
let w = text.size(withAttributes: [.font: font]).width + 20 // 左右 10 pt padding
|
||||
return CGSize(width: min(w, layout.maxItemWidth), height: 23)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
final class AutoHeightCollectionView: UICollectionView {
|
||||
override var contentSize: CGSize {
|
||||
didSet { invalidateIntrinsicContentSize() }
|
||||
}
|
||||
override var intrinsicContentSize: CGSize {
|
||||
CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// RoleTagCollectionCell.swift
|
||||
// Visual_Novel_iOS
|
||||
//
|
||||
// Created by mh on 2025/10/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class RoleTagCollectionCell: UICollectionViewCell {
|
||||
|
||||
lazy var containerView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = UIColor(hex: "#BAC5D2")
|
||||
view.cornerRadius = 11.5
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var titleLab: UILabel = {
|
||||
let lab = UILabel()
|
||||
lab.font = UIFont.boldSystemFont(ofSize: 12)
|
||||
lab.textColor = UIColor(hex: "#E5F1FF")
|
||||
lab.textAlignment = .center
|
||||
return lab
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.contentView.clipsToBounds = true
|
||||
setupViews()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setupViews() {
|
||||
|
||||
contentView.addSubview(containerView)
|
||||
containerView.addSubview(titleLab)
|
||||
|
||||
containerView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLab.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.right.equalToSuperview().inset(7)
|
||||
}
|
||||
}
|
||||
|
||||
func setupData(model: CLRoleTagsModel) {
|
||||
titleLab.text = model.name
|
||||
if model.isSelected {
|
||||
containerView.backgroundColor = UIColor(hex: "#0065FF")
|
||||
titleLab.textColor = .white
|
||||
} else {
|
||||
containerView.backgroundColor = UIColor(hex: "#BAC5D2")
|
||||
titleLab.textColor = UIColor(hex: "#E5F1FF")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,10 @@ class RolesRootPageView: CLContainer {
|
|||
|
||||
let itemWidth: CGFloat = (UIScreen.width - 30.0) / 2.0
|
||||
var jumpPublisher: AnyPublisher<JumpTarget, Never> { topView.jumpPublisher }
|
||||
|
||||
// private lazy var pagingView = JXPagingListRefreshView(delegate: self)
|
||||
// lazy var headerView:
|
||||
|
||||
|
||||
let data: [String] = [
|
||||
"Once a prodigy, Lin Feng had his cultivation shattered and was cast out Once a prodigy, Lin Feng had his cultivation shattered and was cast",
|
||||
|
@ -46,6 +50,11 @@ class RolesRootPageView: CLContainer {
|
|||
return view
|
||||
}()
|
||||
|
||||
lazy var tagsView: CLRoleTagsView = {
|
||||
let tagsView = CLRoleTagsView()
|
||||
return tagsView
|
||||
}()
|
||||
|
||||
lazy var collectionView: UICollectionView = {
|
||||
let layout = CLWaterfallLayout()
|
||||
layout.columnCount = 2
|
||||
|
@ -65,6 +74,7 @@ class RolesRootPageView: CLContainer {
|
|||
super.init(frame: frame)
|
||||
|
||||
setupViews()
|
||||
setupDatas()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
|
@ -73,6 +83,8 @@ class RolesRootPageView: CLContainer {
|
|||
|
||||
private func setupViews() {
|
||||
addSubview(self.topView)
|
||||
// addSubview(tagsChooseView)
|
||||
addSubview(tagsView)
|
||||
addSubview(collectionView)
|
||||
|
||||
topView.snp.makeConstraints { make in
|
||||
|
@ -80,11 +92,20 @@ class RolesRootPageView: CLContainer {
|
|||
make.height.equalTo(UIDevice().navHeight)
|
||||
}
|
||||
|
||||
tagsView.snp.makeConstraints { make in
|
||||
make.right.left.equalToSuperview()
|
||||
make.top.equalTo(topView.snp.bottom).offset(0)
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.bottom.left.right.equalToSuperview()
|
||||
make.top.equalTo(topView.snp.bottom).offset(20)
|
||||
make.top.equalTo(tagsView.snp.bottom).offset(0)
|
||||
}
|
||||
}
|
||||
|
||||
private func setupDatas() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
extension RolesRootPageView: UICollectionViewDelegate, UICollectionViewDataSource, WaterfallLayoutDelegate {
|
||||
|
@ -100,6 +121,10 @@ extension RolesRootPageView: UICollectionViewDelegate, UICollectionViewDataSourc
|
|||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView,
|
||||
layout: CLWaterfallLayout,
|
||||
heightForItemAt indexPath: IndexPath) -> CGFloat {
|
||||
|
@ -131,3 +156,69 @@ extension RolesRootPageView: UICollectionViewDelegate, UICollectionViewDataSourc
|
|||
return coverH + 10.0 + textH + 5.0 + remindH
|
||||
}
|
||||
}
|
||||
|
||||
//extension RolesRootPageView: JXPagingViewDelegate {
|
||||
// func tableHeaderViewHeight(in _: JXPagingView) -> Int {
|
||||
// return 100
|
||||
// }
|
||||
//
|
||||
// func tableHeaderView(in _: JXPagingView) -> UIView {
|
||||
// return headerView
|
||||
// }
|
||||
//
|
||||
// func heightForPinSectionHeader(in _: JXPagingView) -> Int {
|
||||
// return headerPinHeadHeight
|
||||
// }
|
||||
//
|
||||
// func viewForPinSectionHeader(in _: JXPagingView) -> UIView {
|
||||
// return pinHeaderView
|
||||
// }
|
||||
//
|
||||
// func numberOfLists(in _: JXPagingView) -> Int {
|
||||
// return controllers.count
|
||||
// }
|
||||
//
|
||||
// func pagingView(_: JXPagingView, initListAtIndex index: Int) -> JXPagingViewListViewDelegate {
|
||||
// let vc = controllers[index]
|
||||
// return vc
|
||||
// }
|
||||
//
|
||||
// func segmentedView(_ segmentedView: JXSegmentedView, didSelectedItemAt index: Int) {
|
||||
// if segmentedView == pinHeaderView.segmentedView {
|
||||
// refreshSubTagsSegmentView()
|
||||
// }
|
||||
//// else if segmentedView == pinHeaderView.subSegementedView {
|
||||
//// let selectTag = tagsNodes[index]
|
||||
//// if let currentVc = controllers[pinHeaderView.segmentedView.selectedIndex] as? DiscoverRolesGridController {
|
||||
//// currentVc.tryLoad(code: selectTag.code!)
|
||||
//// }
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// func mainTableViewDidScroll(_ scrollView: UIScrollView) {
|
||||
// NaviAlphaHandle.changeNaviViewsAlpha(scrollView: scrollView, alphaViews: [bgBdView, navigationView?.bgView], oppositeViews: [])
|
||||
// }
|
||||
//}
|
||||
|
||||
//extension DiscoverRootPageView: JXPagingMainTableViewGestureDelegate {
|
||||
// func mainTableViewGestureRecognizer(
|
||||
// _ gestureRecognizer: UIGestureRecognizer,
|
||||
// shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
// // 如果是 UICollectionView 的手势,先判断滚动方向
|
||||
// if let panGesture = otherGestureRecognizer as? UIPanGestureRecognizer,
|
||||
// let otherView = otherGestureRecognizer.view,
|
||||
// otherView is UICollectionView {
|
||||
// let velocity = panGesture.velocity(in: otherView)
|
||||
// // 横向滚动时禁止
|
||||
// if abs(velocity.x) > abs(velocity.y) {
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// // 禁止segmentedView左右滑动的时候,上下和左右都可以滚动
|
||||
//// if otherGestureRecognizer == segmentedView.collectionView.panGestureRecognizer {
|
||||
//// return false
|
||||
//// }
|
||||
// return gestureRecognizer.isKind(of: UIPanGestureRecognizer.self)
|
||||
// && otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.self)
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// TagFlowLayout.swift
|
||||
// Visual_Novel_iOS
|
||||
//
|
||||
// Created by mh on 2025/10/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class TagFlowLayout: UICollectionViewLayout {
|
||||
// MARK: - 可外部配置
|
||||
var maxLineWidth: CGFloat = UIScreen.width - 20.0
|
||||
var maxItemWidth: CGFloat = (UIScreen.width - 50.0) / 2.0
|
||||
var interItemSpacing: CGFloat = 8
|
||||
var lineSpacing: CGFloat = 6
|
||||
var sectionInset: UIEdgeInsets = .init(top: 12, left: 20, bottom: 12, right: 10)
|
||||
var delegate: TagFlowLayoutDelegate? = nil
|
||||
|
||||
// MARK: - 私有缓存
|
||||
private var cache: [UICollectionViewLayoutAttributes] = []
|
||||
private var contentHeight: CGFloat = 0
|
||||
|
||||
override var collectionViewContentSize: CGSize {
|
||||
CGSize(width: maxLineWidth, height: contentHeight)
|
||||
}
|
||||
|
||||
override func prepare() {
|
||||
super.prepare()
|
||||
guard cache.isEmpty, let cv = collectionView else { return }
|
||||
|
||||
contentHeight = sectionInset.top
|
||||
var x: CGFloat = sectionInset.left
|
||||
var y: CGFloat = sectionInset.top
|
||||
var lineHeight: CGFloat = 0
|
||||
|
||||
for idx in 0..<cv.numberOfItems(inSection: 0) {
|
||||
let indexPath = IndexPath(item: idx, section: 0)
|
||||
// 拿 size(走 delegate 或默认)
|
||||
let size = delegate?.collectionView(cv, layout: self, sizeForItemAt: indexPath) ??
|
||||
CGSize(width: 60, height: 32)
|
||||
|
||||
// 换行判断
|
||||
if x + size.width + sectionInset.right > maxLineWidth && idx > 0 {
|
||||
x = sectionInset.left
|
||||
y += lineHeight + lineSpacing
|
||||
lineHeight = 0
|
||||
}
|
||||
|
||||
// 缓存 frame
|
||||
let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath)
|
||||
attr.frame = CGRect(origin: CGPoint(x: x, y: y), size: size)
|
||||
cache.append(attr)
|
||||
|
||||
// 更新游标
|
||||
x += size.width + interItemSpacing
|
||||
lineHeight = max(lineHeight, size.height)
|
||||
}
|
||||
|
||||
contentHeight = y + lineHeight + sectionInset.bottom
|
||||
}
|
||||
|
||||
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
|
||||
cache.filter { $0.frame.intersects(rect) }
|
||||
}
|
||||
|
||||
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
|
||||
cache[safe: indexPath.item]
|
||||
}
|
||||
|
||||
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
|
||||
newBounds.width != maxLineWidth
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - 可选 delegate(动态 size)
|
||||
protocol TagFlowLayoutDelegate: AnyObject {
|
||||
func collectionView(_ collectionView: UICollectionView,
|
||||
layout: TagFlowLayout,
|
||||
sizeForItemAt indexPath: IndexPath) -> CGSize
|
||||
}
|
Loading…
Reference in New Issue