578 lines
20 KiB
Swift
578 lines
20 KiB
Swift
|
|
//
|
|||
|
|
// PhotoBrowserController.swift
|
|||
|
|
// Crush
|
|||
|
|
//
|
|||
|
|
// Created by Leon on 2025/7/26.
|
|||
|
|
//
|
|||
|
|
|
|||
|
|
import Photos
|
|||
|
|
import SnapKit
|
|||
|
|
import UIKit
|
|||
|
|
import Combine
|
|||
|
|
|
|||
|
|
enum PhotoBrowserType {
|
|||
|
|
/// 普通查看大图,无其他额外操作
|
|||
|
|
case normal
|
|||
|
|
/// 我的AI角色图片
|
|||
|
|
case roleMine
|
|||
|
|
/// 他人的AI角色图片
|
|||
|
|
case roleOthersInIm
|
|||
|
|
/// 浏览他人相册 & Meet 查看大图
|
|||
|
|
case roleOthersInAlbum
|
|||
|
|
/// 聊天背景图选择(AI生图)
|
|||
|
|
case chatBackgroundGeneratedSelect
|
|||
|
|
/// 设置聊天背景图
|
|||
|
|
case chatBackgroundSet
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class PhotoBrowserController: UIViewController, UIScrollViewDelegate, BrowseImageZoomViewDelegate {
|
|||
|
|
private let kScrollLeftAndRightSpace: CGFloat = 0
|
|||
|
|
@Published var currentIndex: Int = 0
|
|||
|
|
private var imageCount: Int = 0
|
|||
|
|
private var scrollView: UIScrollView!
|
|||
|
|
var titleView: NavigationView!
|
|||
|
|
private var titleTitleStackH: UIStackView!
|
|||
|
|
var titleLockIcon: EPIconTertiaryButton! // 🔒
|
|||
|
|
var titleunlockedIcon: EPIconPrimaryButton! // 🔓 + 主题背景色
|
|||
|
|
private var countLabel: UILabel?
|
|||
|
|
private var deleteButton: UIButton?
|
|||
|
|
|
|||
|
|
// Data
|
|||
|
|
private var visibleZoomViews: Set<BrowseImageZoomView> = []
|
|||
|
|
private var reusableZoomViews: Set<BrowseImageZoomView> = []
|
|||
|
|
var imageModels: [PhotoBrowserModel] = []
|
|||
|
|
|
|||
|
|
@Published var type: PhotoBrowserType = .normal
|
|||
|
|
private var cancellables = Set<AnyCancellable>()
|
|||
|
|
|
|||
|
|
// Flag
|
|||
|
|
var isRequesting = false
|
|||
|
|
|
|||
|
|
// MARK: - Commone通用业务Views
|
|||
|
|
var bottomGradientContainer: GradientView!
|
|||
|
|
var bottomGradientOperateStackV: UIStackView!
|
|||
|
|
|
|||
|
|
// MARK: Role Mine
|
|||
|
|
/// 解锁方式:免费或coin解锁
|
|||
|
|
var rolePhotoUnlockEntry: RolePhotoUnlockEntryView!
|
|||
|
|
var setDefaultEntry: RolePhotoSetDefaultEntryView!
|
|||
|
|
var moreButton: EPIconGhostButton?
|
|||
|
|
|
|||
|
|
// MARK: Role See others
|
|||
|
|
|
|||
|
|
var roleOthersContainer: SelectiveDeliveryEventsView?
|
|||
|
|
var roleOthersCenterLock: UIImageView?
|
|||
|
|
var iconLabel: CLIconLabel?
|
|||
|
|
var iconUnlockButton: StyleButton?
|
|||
|
|
|
|||
|
|
// MARK: 通用的地步操作view
|
|||
|
|
/// 居中底部显示一个chipButton
|
|||
|
|
var bottomCommonOperateContainer: SelectiveDeliveryEventsView?
|
|||
|
|
var operateChipButton : EPChipContrastButton?
|
|||
|
|
var likeView: HeartLikeCountView?
|
|||
|
|
|
|||
|
|
// MARK: Chatbackground set
|
|||
|
|
var setBackgroundDisableButton: StyleButton!
|
|||
|
|
|
|||
|
|
override func viewDidLoad() {
|
|||
|
|
super.viewDidLoad()
|
|||
|
|
view.backgroundColor = .black
|
|||
|
|
setupScrollView()
|
|||
|
|
loadTitleView()
|
|||
|
|
|
|||
|
|
// 其他业务通用的一些容器、View
|
|||
|
|
setupCommonContainers()
|
|||
|
|
setupOprateViews()
|
|||
|
|
|
|||
|
|
setupEvent()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func setupEvent(){
|
|||
|
|
$type.sink {[weak self] type in
|
|||
|
|
if type == .roleMine || type == .chatBackgroundSet{
|
|||
|
|
self?.moreButton?.isHidden = false
|
|||
|
|
}else{
|
|||
|
|
self?.moreButton?.isHidden = true
|
|||
|
|
}
|
|||
|
|
}.store(in: &cancellables)
|
|||
|
|
|
|||
|
|
$currentIndex.sink {[weak self] index in
|
|||
|
|
self?.reloadStates(index: index)
|
|||
|
|
}.store(in: &cancellables)
|
|||
|
|
|
|||
|
|
WalletCore.shared.$balance.sink {[weak self] balance in
|
|||
|
|
if let priceLabel = self?.iconLabel {
|
|||
|
|
// let balance = balance.balance ?? 0
|
|||
|
|
// let coin = Coin(cents: balance)
|
|||
|
|
priceLabel.contentLabel.text = balance.displayBalance()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}.store(in: &cancellables)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - SetupViews
|
|||
|
|
private func setupScrollView() {
|
|||
|
|
scrollView = UIScrollView()
|
|||
|
|
scrollView.isHidden = true
|
|||
|
|
view.addSubview(scrollView)
|
|||
|
|
view.sendSubviewToBack(scrollView)
|
|||
|
|
|
|||
|
|
scrollView.showsVerticalScrollIndicator = false
|
|||
|
|
scrollView.showsHorizontalScrollIndicator = false
|
|||
|
|
scrollView.contentInsetAdjustmentBehavior = .never
|
|||
|
|
scrollView.isPagingEnabled = true
|
|||
|
|
scrollView.bounces = true
|
|||
|
|
scrollView.backgroundColor = .clear
|
|||
|
|
scrollView.delegate = self
|
|||
|
|
|
|||
|
|
scrollView.snp.makeConstraints { make in
|
|||
|
|
make.edges.equalTo(UIEdgeInsets(top: 0, left: -kScrollLeftAndRightSpace, bottom: 0, right: kScrollLeftAndRightSpace))
|
|||
|
|
make.width.equalTo(UIScreen.main.bounds.width + kScrollLeftAndRightSpace)
|
|||
|
|
make.height.equalTo(UIScreen.main.bounds.height)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func loadTitleView() {
|
|||
|
|
guard titleView == nil else {
|
|||
|
|
titleView?.alpha = 1
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
titleView = NavigationView()
|
|||
|
|
titleView.bgView.alpha = 0
|
|||
|
|
titleView.setupBackButtonCloseIcon()
|
|||
|
|
titleView.clipsToBounds = false
|
|||
|
|
view.addSubview(titleView)
|
|||
|
|
titleView.snp.makeConstraints { make in
|
|||
|
|
make.top.leading.trailing.equalToSuperview()
|
|||
|
|
make.height.equalTo(UIWindow.statusBarHeight + 44)
|
|||
|
|
}
|
|||
|
|
let gradient = CLSystemToken.gradient(token: .cob)
|
|||
|
|
let gradientUnderTitle = GradientView(colors: [gradient.secondColor!, gradient.firstColor!], gradientType: .topToBottom) // [UIColor.c.cob.withAlphaComponent(0), UIColor.c.cbd]
|
|||
|
|
titleView.insertSubview(gradientUnderTitle, at: 0)
|
|||
|
|
gradientUnderTitle.snp.makeConstraints { make in
|
|||
|
|
make.leading.trailing.top.equalToSuperview()
|
|||
|
|
make.height.equalTo(140)
|
|||
|
|
}
|
|||
|
|
titleView.tapBackButtonAction = {[weak self] in
|
|||
|
|
self?.backButtonAction()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
titleTitleStackH = {
|
|||
|
|
let v = UIStackView()
|
|||
|
|
v.spacing = 8
|
|||
|
|
v.alignment = .center
|
|||
|
|
titleView.addSubview(v)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.height.equalTo(44)
|
|||
|
|
make.centerX.equalToSuperview()
|
|||
|
|
make.bottom.equalToSuperview()
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
titleLockIcon = {
|
|||
|
|
// EPIconTertiaryButton
|
|||
|
|
let v = EPIconTertiaryButton(radius: .rectangle, iconSize: .small, iconCode: .iconPrivate)
|
|||
|
|
titleTitleStackH.addArrangedSubview(v)
|
|||
|
|
v.isHidden = true
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
titleunlockedIcon = {
|
|||
|
|
let v = EPIconPrimaryButton(radius: .rectangle, iconSize: .small, iconCode: .iconPublic)
|
|||
|
|
titleTitleStackH.addArrangedSubview(v)
|
|||
|
|
v.isHidden = true
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
countLabel = {
|
|||
|
|
let v = UILabel()
|
|||
|
|
titleTitleStackH.addArrangedSubview(v)
|
|||
|
|
v.textColor = .white
|
|||
|
|
v.font = .t.ttm
|
|||
|
|
v.textAlignment = .center
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - 各项业务对应的view
|
|||
|
|
private func setupCommonContainers(){
|
|||
|
|
bottomGradientContainer = {
|
|||
|
|
let gradient = CLSystemToken.gradient(token: .cob)
|
|||
|
|
let gradientUnderTitle = GradientView(colors: [gradient.firstColor!, gradient.secondColor!], gradientType: .topToBottom) // [UIColor.c.cob.withAlphaComponent(0), UIColor.c.cbd]
|
|||
|
|
view.addSubview(gradientUnderTitle)
|
|||
|
|
gradientUnderTitle.snp.makeConstraints { make in
|
|||
|
|
make.leading.trailing.bottom.equalToSuperview()
|
|||
|
|
}
|
|||
|
|
return gradientUnderTitle
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
bottomGradientOperateStackV = {
|
|||
|
|
let v = UIStackView()
|
|||
|
|
v.axis = .vertical
|
|||
|
|
v.spacing = 16
|
|||
|
|
bottomGradientContainer!.addSubview(v)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.top.equalToSuperview().offset(48)
|
|||
|
|
make.leading.equalToSuperview().offset(24)
|
|||
|
|
make.trailing.equalToSuperview().offset(-24)
|
|||
|
|
make.bottom.equalToSuperview().offset(-16 - UIWindow.safeAreaBottom * 0.5)
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
bottomGradientContainer?.isHidden = true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func setupOprateViews() {
|
|||
|
|
switch type {
|
|||
|
|
case .roleMine:
|
|||
|
|
createOperateViewOfRoleMine()
|
|||
|
|
case .roleOthersInIm, .roleOthersInAlbum:
|
|||
|
|
createOperateViewOfOthers()
|
|||
|
|
createBottomCommonOperateView()
|
|||
|
|
case .chatBackgroundSet:
|
|||
|
|
createChatBackgroundSetViews()
|
|||
|
|
case .chatBackgroundGeneratedSelect:
|
|||
|
|
createBottomCommonOperateView()
|
|||
|
|
setupChatBackgroundSelectView()
|
|||
|
|
default:
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func createBottomCommonOperateView(){
|
|||
|
|
bottomCommonOperateContainer = {
|
|||
|
|
let v = SelectiveDeliveryEventsView()
|
|||
|
|
view.insertSubview(v, belowSubview: titleView)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.edges.equalToSuperview()
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
operateChipButton = {
|
|||
|
|
let v = EPChipContrastButton()
|
|||
|
|
v.iconCode = .like
|
|||
|
|
v.addTarget(self, action: #selector(tapOperateChipButton(_:)), for: .touchUpInside)
|
|||
|
|
bottomCommonOperateContainer?.addSubview(v)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.centerX.equalToSuperview()
|
|||
|
|
make.bottom.equalToSuperview().offset(-16-UIWindow.safeAreaBottom*0.5)
|
|||
|
|
}
|
|||
|
|
v.isHidden = true
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
likeView = {
|
|||
|
|
let v = HeartLikeCountView(viewSize: .xxl)
|
|||
|
|
bottomCommonOperateContainer?.addSubview(v)
|
|||
|
|
v.snp.makeConstraints { make in
|
|||
|
|
make.centerX.equalToSuperview()
|
|||
|
|
make.bottom.equalToSuperview().offset(-16-UIWindow.safeAreaBottom*0.5)
|
|||
|
|
}
|
|||
|
|
v.likeButton.addTarget(self, action: #selector(tapLikeButton), for: .touchUpInside)
|
|||
|
|
v.isHidden = true
|
|||
|
|
return v
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
bottomCommonOperateContainer?.isHidden = true
|
|||
|
|
roleOthersContainer?.isHidden = true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private func setupChatBackgroundSelectView(){
|
|||
|
|
#warning("to do")
|
|||
|
|
//operateChipButton.text = "Select"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// MARK: - 看图控件
|
|||
|
|
func setupViews() {
|
|||
|
|
visibleZoomViews.forEach { view in
|
|||
|
|
view.prepareForReuse()
|
|||
|
|
view.removeFromSuperview()
|
|||
|
|
reusableZoomViews.insert(view)
|
|||
|
|
}
|
|||
|
|
visibleZoomViews.removeAll()
|
|||
|
|
|
|||
|
|
imageCount = imageModels.count
|
|||
|
|
|
|||
|
|
let width = UIScreen.main.bounds.width
|
|||
|
|
let height = UIScreen.main.bounds.height
|
|||
|
|
scrollView.contentOffset = CGPoint(x: (width + kScrollLeftAndRightSpace) * CGFloat(currentIndex), y: 0)
|
|||
|
|
scrollView.contentSize = CGSize(width: (width + kScrollLeftAndRightSpace) * CGFloat(imageCount), height: height)
|
|||
|
|
setupZoomView(at: currentIndex)
|
|||
|
|
reloadViews()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func setupZoomView(at index: Int) {
|
|||
|
|
guard index < imageModels.count, index >= 0 else { return }
|
|||
|
|
let model = imageModels[index]
|
|||
|
|
let zoomView = BrowseImageZoomView(imageModel: model)
|
|||
|
|
zoomView.delegate = self
|
|||
|
|
let width = UIScreen.main.bounds.width
|
|||
|
|
let height = UIScreen.main.bounds.height
|
|||
|
|
zoomView.frame = CGRect(
|
|||
|
|
x: (width + kScrollLeftAndRightSpace) * CGFloat(index) + kScrollLeftAndRightSpace,
|
|||
|
|
y: 0,
|
|||
|
|
width: width,
|
|||
|
|
height: height
|
|||
|
|
)
|
|||
|
|
zoomView.displayIndex = index
|
|||
|
|
scrollView.addSubview(zoomView)
|
|||
|
|
visibleZoomViews.insert(zoomView)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func reloadZoomView(_ zoomView: BrowseImageZoomView, at index: Int) {
|
|||
|
|
let width = UIScreen.main.bounds.width
|
|||
|
|
let height = UIScreen.main.bounds.height
|
|||
|
|
guard !imageModels.isEmpty else { return }
|
|||
|
|
let safeIndex = min(index, imageModels.count - 1)
|
|||
|
|
|
|||
|
|
zoomView.frame = CGRect(
|
|||
|
|
x: (width + kScrollLeftAndRightSpace) * CGFloat(safeIndex) + kScrollLeftAndRightSpace,
|
|||
|
|
y: 0,
|
|||
|
|
width: width,
|
|||
|
|
height: height
|
|||
|
|
)
|
|||
|
|
zoomView.reloadImage(imageModels[safeIndex])
|
|||
|
|
zoomView.delegate = self
|
|||
|
|
zoomView.displayIndex = safeIndex
|
|||
|
|
scrollView.addSubview(zoomView)
|
|||
|
|
visibleZoomViews.insert(zoomView)
|
|||
|
|
reusableZoomViews.remove(zoomView)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - Public
|
|||
|
|
func reloadViews() {
|
|||
|
|
guard imageCount > 1 else { return }
|
|||
|
|
|
|||
|
|
var hasFrontDisplay = false
|
|||
|
|
var hasAfterDisplay = false
|
|||
|
|
|
|||
|
|
visibleZoomViews.forEach { zoomView in
|
|||
|
|
if zoomView.displayIndex == currentIndex + 1 {
|
|||
|
|
hasAfterDisplay = true
|
|||
|
|
}
|
|||
|
|
if zoomView.displayIndex == currentIndex - 1 {
|
|||
|
|
hasFrontDisplay = true
|
|||
|
|
}
|
|||
|
|
if abs(zoomView.displayIndex - currentIndex) > 1 {
|
|||
|
|
zoomView.prepareForReuse()
|
|||
|
|
zoomView.removeFromSuperview()
|
|||
|
|
reusableZoomViews.insert(zoomView)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
visibleZoomViews.subtract(reusableZoomViews)
|
|||
|
|
|
|||
|
|
if currentIndex + 1 < imageCount, !hasAfterDisplay {
|
|||
|
|
if let zoomView = reusableZoomViews.first {
|
|||
|
|
reloadZoomView(zoomView, at: currentIndex + 1)
|
|||
|
|
} else {
|
|||
|
|
setupZoomView(at: currentIndex + 1)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if currentIndex - 1 >= 0, !hasFrontDisplay {
|
|||
|
|
if let zoomView = reusableZoomViews.first {
|
|||
|
|
reloadZoomView(zoomView, at: currentIndex - 1)
|
|||
|
|
} else {
|
|||
|
|
setupZoomView(at: currentIndex - 1)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func reloadCurrentZoomImage(){
|
|||
|
|
if let zoomView = visibleZoomViews.first {
|
|||
|
|
reloadZoomView(zoomView, at: currentIndex)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@objc func backButtonAction() {
|
|||
|
|
let zoomView = visibleZoomViews.first { view in
|
|||
|
|
guard currentIndex < imageModels.count else { return false }
|
|||
|
|
return view.imageModel == imageModels[currentIndex]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if let zoomView = zoomView {
|
|||
|
|
zoomView.alpha = 0
|
|||
|
|
hideAnimation(with: zoomView.imageView, toRect: zoomView.imageModel?.sourceRect ?? .zero)
|
|||
|
|
} else {
|
|||
|
|
UIView.animate(withDuration: 0.3) { [weak self] in
|
|||
|
|
self?.setVCViewBackgroundColor(0)
|
|||
|
|
} completion: { _ in
|
|||
|
|
PhotoBrowserManager.shared.hidePhotoBrowser()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func showAnimation(_ model: PhotoBrowserModel) {
|
|||
|
|
let imageView = UIImageView(frame: model.sourceRect)
|
|||
|
|
view.addSubview(imageView)
|
|||
|
|
|
|||
|
|
imageView.contentMode = model.imageContentMode
|
|||
|
|
imageView.image = model.image ?? model.placeHolder
|
|||
|
|
imageView.backgroundColor = .black
|
|||
|
|
imageView.clipsToBounds = true
|
|||
|
|
if imageView.image == nil {
|
|||
|
|
imageView.isHidden = true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var imageWidth = imageView.image?.size.width ?? 1
|
|||
|
|
var imageHeight = imageView.image?.size.height ?? 1
|
|||
|
|
let scale = imageHeight / imageWidth
|
|||
|
|
if imageWidth < imageWidth && imageHeight >= UIScreen.main.bounds.height {
|
|||
|
|
imageHeight = UIScreen.main.bounds.height
|
|||
|
|
imageWidth = imageHeight / scale
|
|||
|
|
} else {
|
|||
|
|
imageWidth = UIScreen.main.bounds.width
|
|||
|
|
imageHeight = imageWidth * scale
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let hasSourceRect = model.sourceRect.size.width > 0
|
|||
|
|
|
|||
|
|
if hasSourceRect {
|
|||
|
|
UIView.animate(withDuration: 0.3) { [weak self] in
|
|||
|
|
guard let self = self else { return }
|
|||
|
|
imageView.backgroundColor = .black
|
|||
|
|
self.view.backgroundColor = .black
|
|||
|
|
imageView.center = CGPoint(x: UIScreen.main.bounds.width * 0.5, y: UIScreen.main.bounds.height * 0.5)
|
|||
|
|
imageView.bounds = CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight)
|
|||
|
|
} completion: { [weak self] _ in
|
|||
|
|
guard let self = self else { return }
|
|||
|
|
self.scrollView.isHidden = false
|
|||
|
|
self.view.backgroundColor = .black
|
|||
|
|
imageView.removeFromSuperview()
|
|||
|
|
self.reloadCountLabel(hidden: self.type == .normal)
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
imageView.backgroundColor = .black
|
|||
|
|
view.backgroundColor = .black
|
|||
|
|
imageView.center = CGPoint(x: UIScreen.main.bounds.width * 0.5, y: UIScreen.main.bounds.height * 0.5)
|
|||
|
|
imageView.bounds = CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight)
|
|||
|
|
scrollView.isHidden = false
|
|||
|
|
view.backgroundColor = .black
|
|||
|
|
imageView.removeFromSuperview()
|
|||
|
|
reloadCountLabel(hidden: type == .normal)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private func hideAnimation(with imageView: UIImageView, toRect rect: CGRect) {
|
|||
|
|
let newImageView = UIImageView(frame: PhotoBrowserModel.getViewRectForScreen(with: imageView))
|
|||
|
|
view.addSubview(newImageView)
|
|||
|
|
|
|||
|
|
newImageView.contentMode = .scaleAspectFit
|
|||
|
|
newImageView.image = imageView.image
|
|||
|
|
newImageView.backgroundColor = .black
|
|||
|
|
newImageView.clipsToBounds = true
|
|||
|
|
|
|||
|
|
UIView.animate(withDuration: 0.3) { [weak self] in
|
|||
|
|
self?.setVCViewBackgroundColor(0)
|
|||
|
|
newImageView.contentMode = .scaleAspectFill
|
|||
|
|
newImageView.backgroundColor = .black
|
|||
|
|
newImageView.frame = rect.size.width > 0 ? rect : newImageView.frame
|
|||
|
|
newImageView.alpha = rect.size.width > 0 ? 0.6 : 0
|
|||
|
|
} completion: { _ in
|
|||
|
|
PhotoBrowserManager.shared.hidePhotoBrowser()
|
|||
|
|
newImageView.removeFromSuperview()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - Helper
|
|||
|
|
/// ⚠️此方法好像有问题
|
|||
|
|
private func getCurrentZoomView() -> BrowseImageZoomView? {
|
|||
|
|
let zoomView = visibleZoomViews.first { view in
|
|||
|
|
guard currentIndex < imageModels.count else { return false }
|
|||
|
|
return view.imageModel == imageModels[currentIndex]
|
|||
|
|
}
|
|||
|
|
return zoomView
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func getCurrentZoomView(byModel: PhotoBrowserModel) -> BrowseImageZoomView? {
|
|||
|
|
let zoomView = visibleZoomViews.first { view in
|
|||
|
|
guard currentIndex < imageModels.count else { return false }
|
|||
|
|
return view.imageModel == byModel
|
|||
|
|
}
|
|||
|
|
return zoomView
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - Functions
|
|||
|
|
|
|||
|
|
func reloadCountLabel(hidden: Bool) {
|
|||
|
|
if hidden || imageCount <= 1 {
|
|||
|
|
countLabel?.alpha = 0
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
countLabel?.alpha = 1
|
|||
|
|
countLabel?.text = "\(currentIndex + 1)/\(imageCount)"
|
|||
|
|
view.bringSubviewToFront(countLabel!)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func reloadStates(index: Int){
|
|||
|
|
guard imageModels.count > 0 else{
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
let model = imageModels[index]
|
|||
|
|
//let album = model.aiAlbum
|
|||
|
|
reloadStatesByModel(model: model)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// MARK: - Public
|
|||
|
|
|
|||
|
|
func setupView(with imageModels: [PhotoBrowserModel], currentIndex: Int) {
|
|||
|
|
guard !imageModels.isEmpty else { return }
|
|||
|
|
self.currentIndex = currentIndex
|
|||
|
|
imageCount = imageModels.count
|
|||
|
|
self.imageModels = imageModels
|
|||
|
|
showAnimation(imageModels[currentIndex])
|
|||
|
|
setupViews()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - RoleBrowse about
|
|||
|
|
|
|||
|
|
// MARK: - UIScrollViewDelegate
|
|||
|
|
|
|||
|
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|||
|
|
let index = Int(scrollView.contentOffset.x / (UIScreen.main.bounds.width + kScrollLeftAndRightSpace))
|
|||
|
|
// dlog("照片index: \(index)")
|
|||
|
|
guard index != currentIndex else { return }
|
|||
|
|
currentIndex = min(index, imageCount - 1)
|
|||
|
|
reloadViews()
|
|||
|
|
reloadCountLabel(hidden: false)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - BrowseImageZoomViewDelegate
|
|||
|
|
|
|||
|
|
func dismisAnimation(_ zoomImageView: UIImageView, toFrame frame: CGRect) {
|
|||
|
|
hideAnimation(with: zoomImageView, toRect: frame)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func setVCViewBackgroundColor(_ alpha: CGFloat) {
|
|||
|
|
view.backgroundColor = UIColor.black.withAlphaComponent(alpha)
|
|||
|
|
titleView?.alpha = alpha
|
|||
|
|
bottomGradientContainer?.alpha = alpha
|
|||
|
|
deleteButton?.alpha = alpha
|
|||
|
|
roleOthersContainer?.alpha = alpha
|
|||
|
|
bottomCommonOperateContainer?.alpha = alpha
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func singleTapZoomView(_ zoomImageView: UIImageView) -> Bool {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@discardableResult
|
|||
|
|
func longPressZoomView(_ zoomView: BrowseImageZoomView) -> Bool {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
deinit {
|
|||
|
|
print("♻️EGPhotoBrowserController dealloc")
|
|||
|
|
}
|
|||
|
|
}
|