Files
youle_app_ios_v2/ylgamehall/Source/Share/SharePanel.swift
T
2026-06-30 17:41:10 +08:00

161 lines
5.9 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// SharePanel.swift
// ylgamehall
//
// 原生分享面板:底部弹出三选一(微信好友 / QQ / 抖音)。
//
// 与 msext SharePanel.m 等价行为:
// - 半透明黑底覆盖全屏,点击空白区关闭
// - 内容视图从屏幕底部滑入,0.25s 动画
// - 三个圆形按钮 + label,等间距居中布局
// - 点击按钮后先 dismiss 再触发对应 SharePlatform.share
//
// Phase 4.B 阶段:UI 完整 + 调用 SharePlatform stub
// Phase 4.C/4.D 阶段:SharePlatform 升级为真实 URL Scheme 实现,本类不变。
//
import UIKit
import os.log
@MainActor
public final class SharePanel: UIView {
private static let log = Logger(subsystem: "ylgamehall", category: "SharePanel")
private static let panelHeight: CGFloat = 150
private static let buttonSize: CGFloat = 60
private static let animationDuration: TimeInterval = 0.25
private let content: ShareContent
private let contentView = UIView()
public init(content: ShareContent) {
self.content = content
super.init(frame: UIScreen.main.bounds)
backgroundColor = UIColor(white: 0, alpha: 0)
setupUI()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) is not supported")
}
// MARK: - 公共入口
/// 弹出分享面板。fire-and-forgetsharesuccess 已在 FriendsShareHandler 立即触发,
/// 用户取消(点空白)或选好平台后不再向 H5 回报结果。
public static func show(content: ShareContent) {
guard let window = topWindow() else { return }
let panel = SharePanel(content: content)
window.addSubview(panel)
panel.animateIn()
}
private static func topWindow() -> UIWindow? {
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap(\.windows)
.first { $0.isKeyWindow }
}
// MARK: - UI 装配
private func setupUI() {
// 半透明背景手势
let tap = UITapGestureRecognizer(target: self, action: #selector(handleBackgroundTap(_:)))
addGestureRecognizer(tap)
// 内容视图(屏幕底部,初始 Y 在屏幕外)
let screen = UIScreen.main.bounds
contentView.frame = CGRect(x: 0, y: screen.height, width: screen.width, height: Self.panelHeight)
contentView.backgroundColor = .white
let mask = CAShapeLayer()
mask.path = UIBezierPath(
roundedRect: contentView.bounds,
byRoundingCorners: [.topLeft, .topRight],
cornerRadii: CGSize(width: 10, height: 10)
).cgPath
contentView.layer.mask = mask
addSubview(contentView)
// 三个按钮 + label 等间距居中布局
let buttonsContainer = UIView(frame: CGRect(x: 0, y: 30, width: screen.width, height: 110))
contentView.addSubview(buttonsContainer)
let buttons: [(title: String, platform: SharePlatform, imageName: String)] = [
("微信", WechatShare.shared, "shareWechat"),
("QQ", QQShare.shared, "shareQQ"),
("抖音", DouyinShare.shared, "shareDouyin")
]
let totalButtonsWidth = Self.buttonSize * CGFloat(buttons.count)
let spacing = (screen.width - totalButtonsWidth) / CGFloat(buttons.count + 1)
for (index, b) in buttons.enumerated() {
let x = spacing + CGFloat(index) * (Self.buttonSize + spacing)
let button = UIButton(type: .custom)
button.frame = CGRect(x: x, y: 0, width: Self.buttonSize, height: Self.buttonSize)
button.setImage(UIImage(named: b.imageName), for: .normal)
button.imageView?.contentMode = .scaleAspectFit
button.layer.cornerRadius = Self.buttonSize / 2
button.clipsToBounds = true
button.alpha = b.platform.isInstalled ? 1.0 : 0.4
button.tag = index
button.addTarget(self, action: #selector(handleButtonTap(_:)), for: .touchUpInside)
buttonsContainer.addSubview(button)
let label = UILabel(frame: CGRect(x: x, y: Self.buttonSize + 8, width: Self.buttonSize, height: 20))
label.text = b.title
label.textAlignment = .center
label.font = .systemFont(ofSize: 13)
label.textColor = .darkGray
buttonsContainer.addSubview(label)
}
}
// MARK: - 动画
private func animateIn() {
UIView.animate(withDuration: Self.animationDuration) {
self.backgroundColor = UIColor(white: 0, alpha: 0.5)
var frame = self.contentView.frame
frame.origin.y = UIScreen.main.bounds.height - Self.panelHeight
self.contentView.frame = frame
}
}
private func dismiss(then action: (() -> Void)? = nil) {
UIView.animate(withDuration: Self.animationDuration, animations: {
self.backgroundColor = UIColor(white: 0, alpha: 0)
var frame = self.contentView.frame
frame.origin.y = UIScreen.main.bounds.height
self.contentView.frame = frame
}, completion: { _ in
self.removeFromSuperview()
action?()
})
}
// MARK: - 事件
@objc private func handleBackgroundTap(_ gesture: UITapGestureRecognizer) {
let point = gesture.location(in: self)
if !contentView.frame.contains(point) {
dismiss()
}
}
@objc private func handleButtonTap(_ sender: UIButton) {
let platforms: [SharePlatform] = [WechatShare.shared, QQShare.shared, DouyinShare.shared]
let platform = platforms[sender.tag]
let scene: ShareScene = content.sharefriend == "2" ? .timeline : .friend
let snapshotContent = content
dismiss { [weak platform] in
guard let platform else { return }
Self.log.debug("share via \(platform.name, privacy: .public)")
platform.share(snapshotContent, scene: scene)
}
}
}