// // PlaceholderView.swift // Crush // // Created by Leon on 2025/7/14. // import SnapKit import UIKit /// A reusable placeholder view with an image and text label class PlaceholderView: UIView { // MARK: - Properties lazy var emptyImage: UIImage? = { UIImage(named: "empty_placeholder_icon") }() var viewStartOffset: CGFloat = 0 var startY: CGFloat = 0 private let placeholderImageView: UIImageView = { let imageView = UIImageView() imageView.contentMode = .scaleAspectFit imageView.tintColor = .gray // Adjust tint for template images return imageView }() private let placeholderLabel: UILabel = { let label = UILabel() label.textAlignment = .center label.textColor = .gray label.font = .systemFont(ofSize: 16, weight: .regular) label.numberOfLines = 0 // Allow multiple lines return label }() // MARK: - Initialization init(text: String, viewStartOffset: CGFloat = 0) { super.init(frame: .zero) self.viewStartOffset = viewStartOffset setupViews(image: emptyImage) updateViewOffset(text: text) } init(text: String, startY: CGFloat = 0) { super.init(frame: .zero) self.startY = startY setupViews(image: emptyImage) updateViewStartY(text: text) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - Setup private func setupViews(image: UIImage?) { isUserInteractionEnabled = false backgroundColor = .clear // Adjust as needed // Add subviews addSubview(placeholderImageView) addSubview(placeholderLabel) // Configure content placeholderImageView.image = image } // MARK: - Public Methods func updateViewOffset(text: String) { placeholderLabel.text = text placeholderImageView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.centerY.equalToSuperview().offset((-40 + viewStartOffset) * 0.5) // Offset to position image above text make.size.equalTo(CGSize(width: 183, height: 135)) } placeholderLabel.snp.makeConstraints { make in make.top.equalTo(placeholderImageView.snp.bottom).offset(16) make.left.right.equalToSuperview().inset(16) } } func updateViewStartY(text: String) { placeholderLabel.text = text placeholderImageView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.top.equalToSuperview().offset(startY) make.width.height.equalTo(100) // Adjust size as needed } placeholderLabel.snp.makeConstraints { make in make.top.equalTo(placeholderImageView.snp.bottom).offset(16) make.left.right.equalToSuperview().inset(16) } } } // MARK: - UIView Extension extension UIView { /// Adds a placeholder view with an image and text to the view /// - Parameters: /// - text: The placeholder text /// - Returns: The created PlaceholderView instance @discardableResult func showEmpty(text: String, viewStartOffset: CGFloat = 0) -> PlaceholderView { // Remove any existing placeholder views subviews.filter { $0 is PlaceholderView }.forEach { $0.removeFromSuperview() } // Create and configure placeholder view let placeholderView = PlaceholderView(text: text, viewStartOffset: viewStartOffset) addSubview(placeholderView) // Setup Auto Layout placeholderView.snp.makeConstraints { make in make.edges.equalToSuperview() } placeholderView.setNeedsDisplay() placeholderView.layoutIfNeeded() return placeholderView } @discardableResult func showStartYEmpty(text: String, startY: CGFloat = 200) -> PlaceholderView { // Remove any existing placeholder views subviews.filter { $0 is PlaceholderView }.forEach { $0.removeFromSuperview() } // Create and configure placeholder view let placeholderView = PlaceholderView(text: text, startY: startY) addSubview(placeholderView) // Setup Auto Layout placeholderView.snp.makeConstraints { make in make.edges.equalToSuperview() } return placeholderView } /// Removes any existing placeholder view func removeEmpty() { subviews.filter { $0 is PlaceholderView }.forEach { $0.removeFromSuperview() } } func hideEmpty(){ removeEmpty() } // MARK: - Public func setupEmpty(empty: Bool, startY: CGFloat? = 0, msg: String?){ if(empty){ if let y = startY, y > 0{ showStartYEmpty(text: msg ?? "", startY: y) }else{ showEmpty(text: msg ?? "") } }else{ removeEmpty() } } }