Workaround for UIHostingConfiguration requiring iOS 16
This commit is contained in:
parent
e0e9d4a185
commit
96fdef0558
@ -8,34 +8,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
final class AttachmentCollectionViewCell: UICollectionViewCell {
|
struct AttachmentCollectionViewCellView: View {
|
||||||
let attachmentView: UIView// & UIContentView
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
attachmentView = UIView()
|
|
||||||
attachmentView.backgroundColor = .red
|
|
||||||
// attachmentView = UIHostingConfiguration(content: {
|
|
||||||
// AttachmentCollectionViewCellView(attachment: nil)
|
|
||||||
// }).makeContentView()
|
|
||||||
|
|
||||||
super.init(frame: frame)
|
|
||||||
|
|
||||||
attachmentView.frame = bounds
|
|
||||||
addSubview(attachmentView)
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUI(attachment: DraftAttachment) {
|
|
||||||
// attachmentView.configuration = UIHostingConfiguration(content: {
|
|
||||||
// AttachmentCollectionViewCellView(attachment: attachment)
|
|
||||||
// }).margins(.all, .zero)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct AttachmentCollectionViewCellView: View {
|
|
||||||
let attachment: DraftAttachment?
|
let attachment: DraftAttachment?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -147,6 +120,21 @@ private struct SquareFrame: Layout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(visionOS)
|
||||||
|
@available(iOS, obsoleted: 16.0)
|
||||||
|
private struct LegacySquareFrame<Content: View>: View {
|
||||||
|
@ViewBuilder let content: Content
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
GeometryReader { proxy in
|
||||||
|
let minDimension = min(proxy.size.width, proxy.size.height)
|
||||||
|
content
|
||||||
|
.frame(width: minDimension, height: minDimension, alignment: .center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private extension View {
|
private extension View {
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func squareFrame() -> some View {
|
func squareFrame() -> some View {
|
||||||
@ -160,7 +148,9 @@ private extension View {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self
|
LegacySquareFrame {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ private class WrappedCollectionViewController: UIViewController {
|
|||||||
var draft: Draft!
|
var draft: Draft!
|
||||||
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||||
fileprivate var currentInteractiveMoveStartOffsetInCell: CGPoint?
|
fileprivate var currentInteractiveMoveStartOffsetInCell: CGPoint?
|
||||||
fileprivate var currentInteractiveMoveCell: AttachmentCollectionViewCell?
|
fileprivate var currentInteractiveMoveCell: HostingCollectionViewCell?
|
||||||
fileprivate var addAttachment: ((DraftAttachment) -> Void)? = nil
|
fileprivate var addAttachment: ((DraftAttachment) -> Void)? = nil
|
||||||
|
|
||||||
init(spacing: CGFloat, minItemSize: CGFloat) {
|
init(spacing: CGFloat, minItemSize: CGFloat) {
|
||||||
@ -91,14 +91,11 @@ private class WrappedCollectionViewController: UIViewController {
|
|||||||
section.interGroupSpacing = spacing
|
section.interGroupSpacing = spacing
|
||||||
return section
|
return section
|
||||||
}
|
}
|
||||||
let attachmentCell = UICollectionView.CellRegistration<AttachmentCollectionViewCell, DraftAttachment> { cell, indexPath, attachment in
|
let attachmentCell = UICollectionView.CellRegistration<HostingCollectionViewCell, DraftAttachment> { cell, indexPath, attachment in
|
||||||
cell.updateUI(attachment: attachment)
|
cell.setView(AttachmentCollectionViewCellView(attachment: attachment))
|
||||||
}
|
}
|
||||||
let addButtonCell = UICollectionView.CellRegistration<UICollectionViewCell, Bool> { [unowned self] cell, indexPath, item in
|
let addButtonCell = UICollectionView.CellRegistration<HostingCollectionViewCell, Bool> { [unowned self] cell, indexPath, item in
|
||||||
cell.contentView.backgroundColor = .blue
|
cell.setView(AddAttachmentButton(viewController: self, enabled: item))
|
||||||
// cell.contentConfiguration = UIHostingConfiguration(content: {
|
|
||||||
// AddAttachmentButton(viewController: self, enabled: item)
|
|
||||||
// }).margins(.all, .zero)
|
|
||||||
}
|
}
|
||||||
let collectionView = IntrinsicContentSizeCollectionView(frame: .zero, collectionViewLayout: layout)
|
let collectionView = IntrinsicContentSizeCollectionView(frame: .zero, collectionViewLayout: layout)
|
||||||
self.view = collectionView
|
self.view = collectionView
|
||||||
@ -187,14 +184,14 @@ private class WrappedCollectionViewController: UIViewController {
|
|||||||
case .ended:
|
case .ended:
|
||||||
collectionView.endInteractiveMovement()
|
collectionView.endInteractiveMovement()
|
||||||
UIView.animate(withDuration: 0.2) {
|
UIView.animate(withDuration: 0.2) {
|
||||||
self.currentInteractiveMoveCell?.attachmentView.transform = .identity
|
self.currentInteractiveMoveCell?.hostView?.transform = .identity
|
||||||
}
|
}
|
||||||
currentInteractiveMoveCell = nil
|
currentInteractiveMoveCell = nil
|
||||||
currentInteractiveMoveStartOffsetInCell = nil
|
currentInteractiveMoveStartOffsetInCell = nil
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
collectionView.cancelInteractiveMovement()
|
collectionView.cancelInteractiveMovement()
|
||||||
UIView.animate(withDuration: 0.2) {
|
UIView.animate(withDuration: 0.2) {
|
||||||
self.currentInteractiveMoveCell?.attachmentView.transform = .identity
|
self.currentInteractiveMoveCell?.hostView?.transform = .identity
|
||||||
}
|
}
|
||||||
currentInteractiveMoveCell = nil
|
currentInteractiveMoveCell = nil
|
||||||
currentInteractiveMoveStartOffsetInCell = nil
|
currentInteractiveMoveStartOffsetInCell = nil
|
||||||
@ -218,17 +215,20 @@ extension WrappedCollectionViewController: UIGestureRecognizerDelegate {
|
|||||||
let collectionView = gestureRecognizer.view as! UICollectionView
|
let collectionView = gestureRecognizer.view as! UICollectionView
|
||||||
let location = gestureRecognizer.location(in: collectionView)
|
let location = gestureRecognizer.location(in: collectionView)
|
||||||
guard let indexPath = collectionView.indexPathForItem(at: location),
|
guard let indexPath = collectionView.indexPathForItem(at: location),
|
||||||
let cell = collectionView.cellForItem(at: indexPath) as? AttachmentCollectionViewCell else {
|
let cell = collectionView.cellForItem(at: indexPath) as? HostingCollectionViewCell else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
guard collectionView.beginInteractiveMovementForItem(at: indexPath) else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
UIView.animate(withDuration: 0.2) {
|
UIView.animate(withDuration: 0.2) {
|
||||||
cell.attachmentView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
|
cell.hostView?.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
|
||||||
}
|
}
|
||||||
currentInteractiveMoveCell = cell
|
currentInteractiveMoveCell = cell
|
||||||
currentInteractiveMoveStartOffsetInCell = gestureRecognizer.location(in: cell)
|
currentInteractiveMoveStartOffsetInCell = gestureRecognizer.location(in: cell)
|
||||||
currentInteractiveMoveStartOffsetInCell!.x -= cell.bounds.midX
|
currentInteractiveMoveStartOffsetInCell!.x -= cell.bounds.midX
|
||||||
currentInteractiveMoveStartOffsetInCell!.y -= cell.bounds.midY
|
currentInteractiveMoveStartOffsetInCell!.y -= cell.bounds.midY
|
||||||
return collectionView.beginInteractiveMovementForItem(at: indexPath)
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +279,62 @@ private final class IntrinsicContentSizeCollectionView: UICollectionView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(visionOS)
|
||||||
|
private class HostingCollectionViewCell: UICollectionViewCell {
|
||||||
|
private(set) var hostView: UIView?
|
||||||
|
|
||||||
|
func setView<V: View>(_ view: V) {
|
||||||
|
let config = UIHostingConfiguration(content: {
|
||||||
|
view
|
||||||
|
}).margins(.all, 0)
|
||||||
|
|
||||||
|
if let hostView = hostView as? UIContentView {
|
||||||
|
hostView.configuration = config
|
||||||
|
} else {
|
||||||
|
hostView = config.makeContentView()
|
||||||
|
hostView!.frame = contentView.bounds
|
||||||
|
contentView.addSubview(hostView!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
@available(iOS, obsoleted: 16.0)
|
||||||
|
private class HostingCollectionViewCell: UICollectionViewCell {
|
||||||
|
@available(iOS, obsoleted: 16.0)
|
||||||
|
private var hostController: UIHostingController<AnyView>?
|
||||||
|
private(set) var hostView: UIView?
|
||||||
|
|
||||||
|
func setView<V: View>(_ view: V) {
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
let config = UIHostingConfiguration(content: {
|
||||||
|
view
|
||||||
|
}).margins(.all, 0)
|
||||||
|
|
||||||
|
// We don't just use the cell's contentConfiguration property because we need to animate
|
||||||
|
// the size of the host view, and when the host view is the contentView, that doesn't work.
|
||||||
|
if let hostView = hostView as? UIContentView {
|
||||||
|
hostView.configuration = config
|
||||||
|
} else {
|
||||||
|
hostView = config.makeContentView()
|
||||||
|
hostView!.frame = contentView.bounds
|
||||||
|
contentView.addSubview(hostView!)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let hostController {
|
||||||
|
hostController.rootView = AnyView(view)
|
||||||
|
} else {
|
||||||
|
let host = UIHostingController(rootView: AnyView(view))
|
||||||
|
host.view.frame = contentView.bounds
|
||||||
|
contentView.addSubview(host.view)
|
||||||
|
hostController = host
|
||||||
|
hostView = host.view
|
||||||
|
// drop the hosting controller on the floor and hope nothing bad happens
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private struct AddAttachmentButton: View {
|
private struct AddAttachmentButton: View {
|
||||||
unowned let viewController: WrappedCollectionViewController
|
unowned let viewController: WrappedCollectionViewController
|
||||||
let enabled: Bool
|
let enabled: Bool
|
||||||
@ -308,7 +364,7 @@ private struct AddAttachmentButton: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "photo.badge.plus")
|
Image(systemName: iconName)
|
||||||
.imageScale(.large)
|
.imageScale(.large)
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||||
.background {
|
.background {
|
||||||
@ -321,6 +377,14 @@ private struct AddAttachmentButton: View {
|
|||||||
}
|
}
|
||||||
.disabled(!enabled)
|
.disabled(!enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var iconName: String {
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
"photo.badge.plus"
|
||||||
|
} else {
|
||||||
|
"photo"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AddAttachmentConditionsModifier: ViewModifier {
|
struct AddAttachmentConditionsModifier: ViewModifier {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user