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
class AttachmentBannerView: UIScrollView {
var attachments: [UIImage] = [] {
didSet {
rebuildViews()
}
var readAttachments: (() -> ([UIImage]))?
var onAttachmentsDelete: ((Int) -> Void)?
var attachments: [UIImage] {
get { readAttachments?() ?? [] }
set { assertionFailure() }
}
override var intrinsicContentSize: CGSize {
@@ -26,6 +27,8 @@ class AttachmentBannerView: UIScrollView {
)
}
let stackView = UIStackView()
init() {
super.init(frame: .zero)
@@ -34,6 +37,19 @@ class AttachmentBannerView: UIScrollView {
showsHorizontalScrollIndicator = 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()
}
@@ -42,23 +58,47 @@ class AttachmentBannerView: UIScrollView {
fatalError()
}
var reusableViews = [AttachmentPreviewView]()
func rebuildViews() {
subviews.forEach { $0.removeFromSuperview() }
for (index, attachment) in attachments.enumerated() {
let view = AttachmentPreviewView()
view.imageView.image = attachment
addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
view.frame = .init(
origin: .init(
x: (attachmentSize + attachmentSpacing) * CGFloat(index),
y: 0
),
size: .init(width: attachmentSize, height: attachmentSize)
)
let attachments = attachments
if reusableViews.count > attachments.count {
for index in attachments.count ..< reusableViews.count {
reusableViews[index].removeFromSuperview()
}
reusableViews.removeLast(reusableViews.count - attachments.count)
}
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()
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 deleteButton = UIButton()
var deleteButtonAction: (() -> Void)?
override var intrinsicContentSize: CGSize {
.init(width: attachmentSize, height: attachmentSize)
}
@@ -100,6 +142,8 @@ extension AttachmentBannerView {
deleteButton.heightAnchor.constraint(equalToConstant: 32),
].forEach { $0.isActive = true }
deleteButton.addTarget(self, action: #selector(deleteButtonTapped), for: .touchUpInside)
[
widthAnchor.constraint(equalToConstant: attachmentSize),
heightAnchor.constraint(equalToConstant: attachmentSize),
@@ -110,5 +154,10 @@ extension AttachmentBannerView {
required init?(coder _: NSCoder) {
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 }
}
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)
placeholderLabel.textColor = .label.withAlphaComponent(0.25)
placeholderLabel.font = textEditor.font
@@ -106,9 +124,7 @@ class InputEditView: UIView, UITextViewDelegate {
if textEditor.text != viewModel.text {
textEditor.text = viewModel.text
}
if attachmentsEditor.attachments != viewModel.attachments {
attachmentsEditor.attachments = viewModel.attachments
}
attachmentsEditor.rebuildViews()
parentViewController?.view.layoutIfNeeded()
}
}