Files
youle_app_ios_v2/ylgamehall/Source/Share/SharePanel.swift
T
joywayer d471393806 4.B SharePanel: 替换字符占位为 imageset 图标
从 docs/res/Images.xcassets 拷贝 shareWechat / shareQQ / shareDouyin
三套 imageset(@1x/@2x/@3x)到 ylgamehall/Assets.xcassets/。SharePanel
按钮从"彩色圆 + 首字"改为 setImage + clipsToBounds + 等比缩放,未安装
平台改 alpha 灰显(与原 daoqi msext SharePanel.m:147 createButtonWithImage
同款写法)。

ylgamehall/ 是 PBXFileSystemSynchronizedRootGroup,无需手改 pbxproj。
2026-06-24 07:33:26 +08:00

167 lines
6.2 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 = 200
private static let buttonSize: CGFloat = 60
private static let animationDuration: TimeInterval = 0.25
private let content: ShareContent
private let completion: (ShareResult) -> Void
private let contentView = UIView()
public init(content: ShareContent, completion: @escaping (ShareResult) -> Void) {
self.content = content
self.completion = completion
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: - 公共入口
/// 弹出分享面板。任何时候同一个面板只允许一个实例。
public static func show(content: ShareContent, completion: @escaping (ShareResult) -> Void) {
guard let window = topWindow() else {
completion(.failed(reason: "no key window"))
return
}
let panel = SharePanel(content: content, completion: completion)
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 { [self] in completion(.cancelled) }
}
}
@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 {
Task { @MainActor in
let result = await platform.share(snapshotContent, scene: scene)
Self.log.debug("share via \(platform.name, privacy: .public) result=\(String(describing: result), privacy: .public)")
self.completion(result)
}
}
}
}