Done PhotoPicker

This commit is contained in:
砍砍
2024-12-06 17:13:09 +08:00
parent 2721815907
commit 4cea298fa6
4 changed files with 135 additions and 20 deletions

View File

@@ -11,10 +11,11 @@ private let attachmentSize: CGFloat = 100
private let attachmentSpacing: CGFloat = 16 private let attachmentSpacing: CGFloat = 16
class AttachmentBannerView: UIScrollView { class AttachmentBannerView: UIScrollView {
var attachments: [UIImage] = [] { var readAttachments: (() -> ([UIImage]))?
didSet { var onAttachmentsDelete: ((Int) -> Void)?
rebuildViews() var attachments: [UIImage] {
} get { readAttachments?() ?? [] }
set { assertionFailure() }
} }
override var intrinsicContentSize: CGSize { override var intrinsicContentSize: CGSize {
@@ -26,6 +27,8 @@ class AttachmentBannerView: UIScrollView {
) )
} }
let stackView = UIStackView()
init() { init() {
super.init(frame: .zero) super.init(frame: .zero)
@@ -34,6 +37,19 @@ class AttachmentBannerView: UIScrollView {
showsHorizontalScrollIndicator = false showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false showsVerticalScrollIndicator = false
stackView.axis = .horizontal
stackView.spacing = attachmentSpacing
stackView.alignment = .center
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
[
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
].forEach { $0.isActive = true }
rebuildViews() rebuildViews()
} }
@@ -42,23 +58,47 @@ class AttachmentBannerView: UIScrollView {
fatalError() fatalError()
} }
var reusableViews = [AttachmentPreviewView]()
func rebuildViews() { func rebuildViews() {
subviews.forEach { $0.removeFromSuperview() } let attachments = attachments
for (index, attachment) in attachments.enumerated() {
let view = AttachmentPreviewView() if reusableViews.count > attachments.count {
view.imageView.image = attachment for index in attachments.count ..< reusableViews.count {
addSubview(view) reusableViews[index].removeFromSuperview()
view.translatesAutoresizingMaskIntoConstraints = false }
view.frame = .init( reusableViews.removeLast(reusableViews.count - attachments.count)
origin: .init(
x: (attachmentSize + attachmentSpacing) * CGFloat(index),
y: 0
),
size: .init(width: attachmentSize, height: attachmentSize)
)
} }
if reusableViews.count < attachments.count {
for _ in reusableViews.count ..< attachments.count {
let view = AttachmentPreviewView()
view.alpha = 0
reusableViews.append(view)
}
}
assert(reusableViews.count == attachments.count)
for (index, attachment) in attachments.enumerated() {
let view = reusableViews[index]
view.imageView.image = attachment
stackView.addArrangedSubview(view)
view.deleteButtonAction = { [weak self] in
self?.onAttachmentsDelete?(index)
}
}
invalidateIntrinsicContentSize() invalidateIntrinsicContentSize()
contentSize = intrinsicContentSize contentSize = intrinsicContentSize
UIView.performWithoutAnimation {
self.layoutIfNeeded()
}
UIView.animate(withDuration: 0.3) {
for view in self.reusableViews {
view.alpha = 1
}
}
} }
} }
@@ -67,6 +107,8 @@ extension AttachmentBannerView {
let imageView = UIImageView() let imageView = UIImageView()
let deleteButton = UIButton() let deleteButton = UIButton()
var deleteButtonAction: (() -> Void)?
override var intrinsicContentSize: CGSize { override var intrinsicContentSize: CGSize {
.init(width: attachmentSize, height: attachmentSize) .init(width: attachmentSize, height: attachmentSize)
} }
@@ -100,6 +142,8 @@ extension AttachmentBannerView {
deleteButton.heightAnchor.constraint(equalToConstant: 32), deleteButton.heightAnchor.constraint(equalToConstant: 32),
].forEach { $0.isActive = true } ].forEach { $0.isActive = true }
deleteButton.addTarget(self, action: #selector(deleteButtonTapped), for: .touchUpInside)
[ [
widthAnchor.constraint(equalToConstant: attachmentSize), widthAnchor.constraint(equalToConstant: attachmentSize),
heightAnchor.constraint(equalToConstant: attachmentSize), heightAnchor.constraint(equalToConstant: attachmentSize),
@@ -110,5 +154,10 @@ extension AttachmentBannerView {
required init?(coder _: NSCoder) { required init?(coder _: NSCoder) {
fatalError() fatalError()
} }
@objc func deleteButtonTapped() {
deleteButtonAction?()
deleteButtonAction = nil
}
} }
} }

View File

@@ -0,0 +1,12 @@
//
// InputEditView+Camera.swift
// Intelligents
//
// Created by on 2024/12/6.
//
import UIKit
extension InputEditView {
@objc func takePhoto() {}
}

View File

@@ -0,0 +1,38 @@
//
// InputEditView+Photo.swift
// Intelligents
//
// Created by on 2024/12/6.
//
import PhotosUI
import UIKit
extension InputEditView: PHPickerViewControllerDelegate {
@objc func selectPhoto() {
var config = PHPickerConfiguration(photoLibrary: .shared())
config.filter = .images
config.selectionLimit = 9
let picker = PHPickerViewController(configuration: config)
picker.modalPresentationStyle = .formSheet
picker.delegate = self
parentViewController?.present(picker, animated: true, completion: nil)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
loadPNG(from: results)
}
private func loadPNG(from results: [PHPickerResult]) {
for result in results {
result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, _ in
if let image = image as? UIImage {
DispatchQueue.main.async {
self?.viewModel.attachments.append(image)
}
}
}
}
}
}

View File

@@ -52,6 +52,24 @@ class InputEditView: UIView, UITextViewDelegate {
].forEach { $0.isActive = true } ].forEach { $0.isActive = true }
} }
attachmentsEditor.readAttachments = { [weak self] in
self?.viewModel.attachments ?? []
}
attachmentsEditor.onAttachmentsDelete = { [weak self] index in
self?.viewModel.attachments.remove(at: index)
}
controlBanner.cameraButton.addTarget(
self,
action: #selector(takePhoto),
for: .touchUpInside
)
controlBanner.photoButton.addTarget(
self,
action: #selector(selectPhoto),
for: .touchUpInside
)
textEditor.addSubview(placeholderLabel) textEditor.addSubview(placeholderLabel)
placeholderLabel.textColor = .label.withAlphaComponent(0.25) placeholderLabel.textColor = .label.withAlphaComponent(0.25)
placeholderLabel.font = textEditor.font placeholderLabel.font = textEditor.font
@@ -106,9 +124,7 @@ class InputEditView: UIView, UITextViewDelegate {
if textEditor.text != viewModel.text { if textEditor.text != viewModel.text {
textEditor.text = viewModel.text textEditor.text = viewModel.text
} }
if attachmentsEditor.attachments != viewModel.attachments { attachmentsEditor.rebuildViews()
attachmentsEditor.attachments = viewModel.attachments
}
parentViewController?.view.layoutIfNeeded() parentViewController?.view.layoutIfNeeded()
} }
} }