// // LNMultiLineStackView.swift // Lanu // // Created by OneeChan on 2025/12/14. // import Foundation import UIKit import SnapKit class LNMultiLineStackView: UIStackView { var columns: Int = 0 var itemDistribution: UIStackView.Distribution = .fillEqually var itemSpacing: CGFloat = 0 private var lineViews: [UIStackView] = [] private(set) var curItemViews: [UIView] = [] private var emptyView: [UIView] = [] override init(frame: CGRect) { super.init(frame: frame) axis = .vertical } func update(_ itemViews: [UIView]) { arrangedSubviews.forEach { removeArrangedSubview($0) $0.removeFromSuperview() } lineViews.removeAll() curItemViews.removeAll() emptyView.removeAll() if itemViews.isEmpty { return } var line = buildLine() itemViews.forEach { if $0.isHidden { return } if line.arrangedSubviews.count == columns { line = buildLine() } line.addArrangedSubview($0) curItemViews.append($0) } fillLastLine() } func append(_ itemViews: [UIView]) { var last = lineViews.last ?? buildLine() emptyView.forEach { last.removeArrangedSubview($0) $0.removeFromSuperview() } itemViews.forEach { if $0.isHidden { return } if last.arrangedSubviews.count == columns { last = buildLine() } last.addArrangedSubview($0) curItemViews.append($0) } fillLastLine() } func remove(_ itemViews: [UIView]) { curItemViews.removeAll { itemViews.contains($0) } update(curItemViews) } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNMultiLineStackView { private func fillLastLine() { if lineViews.isEmpty { return } guard let last = lineViews.last else { return } guard last.arrangedSubviews.count < columns else { return } for _ in last.arrangedSubviews.count.. UIStackView { let stackView = UIStackView() stackView.axis = .horizontal stackView.distribution = itemDistribution stackView.spacing = itemSpacing lineViews.append(stackView) addArrangedSubview(stackView) return stackView } } #if DEBUG import SwiftUI struct LNMultiLineStackViewPreview: UIViewRepresentable { func makeUIView(context: Context) -> some UIView { let container = UIView() container.backgroundColor = .lightGray let view = LNMultiLineStackView() view.backgroundColor = .orange container.addSubview(view) view.snp.makeConstraints { make in make.leading.trailing.equalToSuperview() make.centerY.equalToSuperview() } return container } func updateUIView(_ uiView: UIViewType, context: Context) { } } #Preview(body: { LNMultiLineStackViewPreview() }) #endif