RoutePickerView.swift 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //
  2. // ChannelSelectPopView.swift
  3. // RoderickRalph
  4. //
  5. // Created by Neoa on 2025/9/2.
  6. //
  7. import Foundation
  8. import UIKit
  9. // MARK: - Channel Models & Popup
  10. struct Channel: Codable, Hashable {
  11. let id: String
  12. let name: String
  13. }
  14. protocol RoutePickerAgent: AnyObject {
  15. func routePicker(_ panel: RoutePickerView, didPick channel: Channel)
  16. }
  17. class RoutePickerView: UIView {
  18. weak var delegate: RoutePickerAgent?
  19. private let channels: [Channel]
  20. private let backdropView: UIView = {
  21. let v = UIView()
  22. v.backgroundColor = UIColor.black.withAlphaComponent(0.5)
  23. v.translatesAutoresizingMaskIntoConstraints = false
  24. return v
  25. }()
  26. private let cardImageView: UIImageView = {
  27. let imageView = UIImageView()
  28. imageView.image = UIImage(named: "res_ew6zkg25")
  29. imageView.contentMode = .scaleToFill
  30. imageView.translatesAutoresizingMaskIntoConstraints = false
  31. return imageView
  32. }()
  33. private let titleRibbon: UIButton = {
  34. let button = UIButton(type: .system)
  35. button.setBackgroundImage(UIImage(named: "res_x8brwne3"), for: .normal)
  36. button.setTitle("请选择渠道", for: .normal)
  37. button.setTitleColor(.white, for: .normal)
  38. button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18)
  39. button.translatesAutoresizingMaskIntoConstraints = false
  40. button.isUserInteractionEnabled = false
  41. return button
  42. }()
  43. private let scroller: UIScrollView = {
  44. let sv = UIScrollView()
  45. sv.translatesAutoresizingMaskIntoConstraints = false
  46. return sv
  47. }()
  48. private let stacker: UIStackView = {
  49. let sv = UIStackView()
  50. sv.axis = .vertical
  51. sv.spacing = 10
  52. sv.alignment = .fill
  53. sv.distribution = .fill
  54. sv.translatesAutoresizingMaskIntoConstraints = false
  55. return sv
  56. }()
  57. private let dismissBtn: UIButton = {
  58. let button = UIButton(type: .custom)
  59. button.setImage(UIImage(named: "res_9mx2yiyi"), for: .normal)
  60. button.translatesAutoresizingMaskIntoConstraints = false
  61. return button
  62. }()
  63. init(channels: [Channel]) {
  64. self.channels = channels
  65. super.init(frame: .zero)
  66. buildUI()
  67. applyLayout()
  68. inflateChannels()
  69. }
  70. required init?(coder: NSCoder) {
  71. fatalError("init(coder:) has not been implemented")
  72. }
  73. private func buildUI() {
  74. addSubview(backdropView)
  75. addSubview(cardImageView)
  76. addSubview(titleRibbon)
  77. addSubview(scroller)
  78. scroller.addSubview(stacker)
  79. addSubview(dismissBtn)
  80. dismissBtn.isHidden = true
  81. dismissBtn.addTarget(self, action: #selector(closePanel), for: .touchUpInside)
  82. // Tap to dismiss on the dim background
  83. let tapGesture = UITapGestureRecognizer(target: self, action: #selector(closePanel))
  84. backdropView.addGestureRecognizer(tapGesture)
  85. }
  86. private func applyLayout() {
  87. NSLayoutConstraint.activate([
  88. backdropView.topAnchor.constraint(equalTo: topAnchor),
  89. backdropView.bottomAnchor.constraint(equalTo: bottomAnchor),
  90. backdropView.leadingAnchor.constraint(equalTo: leadingAnchor),
  91. backdropView.trailingAnchor.constraint(equalTo: trailingAnchor),
  92. cardImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
  93. cardImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
  94. cardImageView.widthAnchor.constraint(equalToConstant: 333),
  95. cardImageView.heightAnchor.constraint(equalToConstant: 333),
  96. titleRibbon.topAnchor.constraint(equalTo: cardImageView.topAnchor, constant: 10),
  97. titleRibbon.centerXAnchor.constraint(equalTo: cardImageView.centerXAnchor),
  98. titleRibbon.widthAnchor.constraint(equalToConstant: 132),
  99. titleRibbon.heightAnchor.constraint(equalToConstant: 37),
  100. scroller.topAnchor.constraint(equalTo: titleRibbon.bottomAnchor, constant: 12),
  101. scroller.leadingAnchor.constraint(equalTo: cardImageView.leadingAnchor, constant: 20),
  102. scroller.trailingAnchor.constraint(equalTo: cardImageView.trailingAnchor, constant: -20),
  103. scroller.bottomAnchor.constraint(equalTo: cardImageView.bottomAnchor, constant: -20),
  104. stacker.topAnchor.constraint(equalTo: scroller.topAnchor),
  105. stacker.leadingAnchor.constraint(equalTo: scroller.leadingAnchor),
  106. stacker.trailingAnchor.constraint(equalTo: scroller.trailingAnchor),
  107. stacker.bottomAnchor.constraint(equalTo: scroller.bottomAnchor),
  108. stacker.widthAnchor.constraint(equalTo: scroller.widthAnchor),
  109. dismissBtn.topAnchor.constraint(equalTo: cardImageView.topAnchor, constant: -12),
  110. dismissBtn.trailingAnchor.constraint(equalTo: cardImageView.trailingAnchor, constant: 12),
  111. dismissBtn.widthAnchor.constraint(equalToConstant: 24),
  112. dismissBtn.heightAnchor.constraint(equalToConstant: 24)
  113. ])
  114. }
  115. private func makeChannelButton(title: String) -> UIButton {
  116. let button = UIButton(type: .system)
  117. button.setBackgroundImage(UIImage(named: "res_ux9fin4y"), for: .normal)
  118. button.setTitle(title, for: .normal)
  119. button.setTitleColor(.white, for: .normal)
  120. button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
  121. button.contentHorizontalAlignment = .center
  122. button.heightAnchor.constraint(equalToConstant: 45).isActive = true
  123. return button
  124. }
  125. private func inflateChannels() {
  126. for (idx, channel) in channels.enumerated() {
  127. let button = makeChannelButton(title: channel.name)
  128. button.tag = idx
  129. button.addTarget(self, action: #selector(didTapChannel(_:)), for: .touchUpInside)
  130. stacker.addArrangedSubview(button)
  131. }
  132. }
  133. @objc private func didTapChannel(_ sender: UIButton) {
  134. let idx = sender.tag
  135. guard idx >= 0 && idx < channels.count else { return }
  136. let channel = channels[idx]
  137. delegate?.routePicker(self, didPick: channel)
  138. }
  139. @objc private func closePanel() {
  140. // removeFromSuperview()
  141. }
  142. }