diff --git a/Demo/MediaViewerDemo/Samples/Camera/CameraLikeView.swift b/Demo/MediaViewerDemo/Samples/Camera/CameraLikeView.swift index 22dc53f8..e23c76da 100644 --- a/Demo/MediaViewerDemo/Samples/Camera/CameraLikeView.swift +++ b/Demo/MediaViewerDemo/Samples/Camera/CameraLikeView.swift @@ -41,6 +41,14 @@ final class CameraLikeView: UIView { return button }() + private let buttonArea: UIView = { + let view = UIView() + view.backgroundColor = .black.withAlphaComponent(0.1) + return view + }() + + private let shutterButtonWidth = 68.0 + // MARK: - Initializers override init(frame: CGRect) { @@ -58,42 +66,69 @@ final class CameraLikeView: UIView { // Subviews addSubview(previewView) - addSubview(shutterButton) - addSubview(showLibraryButton) - addSubview(toggleTabBarHiddenButton) + addSubview(buttonArea) + buttonArea.addSubview(shutterButton) + buttonArea.addSubview(showLibraryButton) + buttonArea.addSubview(toggleTabBarHiddenButton) - let bottomAreaLayoutGuide = UILayoutGuide() - addLayoutGuide(bottomAreaLayoutGuide) + shutterButton.layer.cornerRadius = shutterButtonWidth / 2 // Layout + showLibraryButton.autoLayout { item in + item.leading.equal(to: layoutMarginsGuide) + item.centerY.equal(to: shutterButton) + item.size.equal(toSquare: 48) + } + + toggleTabBarHiddenButton.autoLayout { item in + item.trailing.equal(to: layoutMarginsGuide) + item.centerY.equal(to: shutterButton) + } + + switch traitCollection.horizontalSizeClass { + case .unspecified, .compact: + layoutForCompactScreen() + case .regular: + layoutForRegularScreen() + @unknown default: + fatalError() + } + } + + private func layoutForCompactScreen() { previewView.autoLayout { item in item.top.equal(to: safeAreaLayoutGuide, plus: 44) item.width.equal(to: item.height, multipliedBy: 3.0 / 4) item.leadingTrailing.equalToSuperview() } - bottomAreaLayoutGuide.autoLayout { item in + buttonArea.autoLayout { item in item.top.equal(to: previewView.bottomAnchor) item.leadingTrailing.equalToSuperview() item.bottom.equal(to: safeAreaLayoutGuide) } - let shutterButtonWidth = 68.0 - shutterButton.layer.cornerRadius = shutterButtonWidth / 2 shutterButton.autoLayout { item in - item.center.equal(to: bottomAreaLayoutGuide) + item.center.equalToSuperview() item.size.equal(toSquare: shutterButtonWidth) } + } + + private func layoutForRegularScreen() { + previewView.autoLayout { item in + item.edges.equalToSuperview() + } - showLibraryButton.autoLayout { item in - item.leading.equal(to: layoutMarginsGuide) - item.centerY.equal(to: bottomAreaLayoutGuide) - item.size.equal(toSquare: 48) + buttonArea.autoLayout { item in + item.leadingTrailing.equalToSuperview() + item.bottom.equalToSuperview() } - toggleTabBarHiddenButton.autoLayout { item in - item.trailing.equal(to: layoutMarginsGuide) - item.centerY.equal(to: bottomAreaLayoutGuide) + shutterButton.autoLayout { item in + item.centerX.equalToSuperview() + item.top.equalToSuperview(plus: 16) + item.bottom.equal(to: safeAreaLayoutGuide, plus: -16) + item.size.equal(toSquare: shutterButtonWidth) } } } diff --git a/Demo/MediaViewerDemo/Samples/Grid/ImageGridView.swift b/Demo/MediaViewerDemo/Samples/Grid/ImageGridView.swift index 78341f18..07ce25a0 100644 --- a/Demo/MediaViewerDemo/Samples/Grid/ImageGridView.swift +++ b/Demo/MediaViewerDemo/Samples/Grid/ImageGridView.swift @@ -12,10 +12,24 @@ final class ImageGridView: UIView { let collectionView: UICollectionView = { let layout = UICollectionViewCompositionalLayout { _, layoutEnvironment in - let columnCount = 3 - let itemSpacing = 2.0 + let minimumItemWidth: CGFloat + let itemSpacing: CGFloat + let contentInsetsReference: UIContentInsetsReference + switch layoutEnvironment.traitCollection.horizontalSizeClass { + case .unspecified, .compact: + minimumItemWidth = 130 + itemSpacing = 2 + contentInsetsReference = .automatic + case .regular: + minimumItemWidth = 160 + itemSpacing = 16 + contentInsetsReference = .layoutMargins + @unknown default: + fatalError() + } let effectiveFullWidth = layoutEnvironment.container.effectiveContentSize.width + let columnCount = Int(effectiveFullWidth / minimumItemWidth) let totalSpacing = itemSpacing * CGFloat(columnCount - 1) let estimatedItemWidth = (effectiveFullWidth - totalSpacing) / CGFloat(columnCount) let group = NSCollectionLayoutGroup.horizontal( @@ -33,10 +47,16 @@ final class ImageGridView: UIView { let section = NSCollectionLayoutSection(group: group) section.interGroupSpacing = itemSpacing + section.contentInsetsReference = contentInsetsReference return section } - return UICollectionView(frame: .zero, collectionViewLayout: layout) + let collectionView = UICollectionView( + frame: .zero, + collectionViewLayout: layout + ) + collectionView.preservesSuperviewLayoutMargins = true + return collectionView }() // MARK: - Initializers @@ -52,6 +72,7 @@ final class ImageGridView: UIView { } private func setUpViews() { + preservesSuperviewLayoutMargins = true backgroundColor = .systemBackground // Subviews diff --git a/Demo/MediaViewerDemo/Samples/Grid/SyncImagesViewController.swift b/Demo/MediaViewerDemo/Samples/Grid/SyncImagesViewController.swift index 32f06965..0aaeb948 100644 --- a/Demo/MediaViewerDemo/Samples/Grid/SyncImagesViewController.swift +++ b/Demo/MediaViewerDemo/Samples/Grid/SyncImagesViewController.swift @@ -60,6 +60,17 @@ final class SyncImagesViewController: UIViewController { } ) + private lazy var toggleToolbarButton = UIBarButtonItem( + title: "Toggle Toolbar", + primaryAction: .init { [weak self] _ in + guard let self, let navigationController else { return } + navigationController.setToolbarHidden( + !navigationController.isToolbarHidden, + animated: true + ) + } + ) + // MARK: - Lifecycle override func loadView() { @@ -79,6 +90,14 @@ final class SyncImagesViewController: UIViewController { navigationItem.title = "Sync Sample" navigationItem.backButtonDisplayMode = .minimal navigationItem.leftBarButtonItem = refreshButton + navigationItem.rightBarButtonItem = toggleToolbarButton + + // Toolbar + toolbarItems = [ + .flexibleSpace(), + .init(title: "Toolbar"), + .flexibleSpace() + ] // Subviews imageGridView.collectionView.refreshControl = .init( diff --git a/README.md b/README.md index ad0bd975..c3440833 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ See demo for more detailed usage. To use the `MediaViewer` library in a SwiftPM project, add the following line to the dependencies in your `Package.swift` file: ```swift -.package(url: "https://github.com/jrsaruo/MediaViewer", from: "0.1.1"), +.package(url: "https://github.com/jrsaruo/MediaViewer", from: "0.1.2"), ``` and add `MediaViewer` as a dependency for your target: diff --git a/Sources/MediaViewer/Transitions/MediaViewerInteractivePopTransition.swift b/Sources/MediaViewer/Transitions/MediaViewerInteractivePopTransition.swift index 04efcabb..b61c9dda 100644 --- a/Sources/MediaViewer/Transitions/MediaViewerInteractivePopTransition.swift +++ b/Sources/MediaViewer/Transitions/MediaViewerInteractivePopTransition.swift @@ -131,7 +131,9 @@ extension MediaViewerInteractivePopTransition: UIViewControllerInteractiveTransi : 1 // [Workaround] Prevent toVC.toolbarItems from showing up during transition. - toVC.toolbarItems = nil + if mediaViewer.toolbarHiddenBackup { + toVC.toolbarItems = nil + } /* * [Workaround] @@ -152,10 +154,10 @@ extension MediaViewerInteractivePopTransition: UIViewControllerInteractiveTransi var viewsToFadeDuringTransition = mediaViewer.subviewsToFadeDuringTransition let isTabBarHidden = tabBar?.isHidden ?? true if isTabBarHidden { - viewsToFadeDuringTransition.append(contentsOf: [ - toolbar, - mediaViewer.pageControlToolbar - ]) + if mediaViewer.toolbarHiddenBackup { + viewsToFadeDuringTransition.append(toolbar) + } + viewsToFadeDuringTransition.append(mediaViewer.pageControlToolbar) } mediaViewer.willStartInteractivePopTransition() @@ -186,6 +188,15 @@ extension MediaViewerInteractivePopTransition: UIViewControllerInteractiveTransi width: pageControlToolbarFrame.width, height: 0 ) + + /* + * [Workaround] + * If the tabBar becomes visible and the toolbar remains visible, + * move it manually because repositioning is not animated. + */ + if !mediaViewer.toolbarHiddenBackup, let tabBar = self.tabBar { + toolbar.frame.origin.y = tabBar.frame.origin.y - toolbar.bounds.height + } } } diff --git a/Sources/MediaViewer/Transitions/MediaViewerTransition.swift b/Sources/MediaViewer/Transitions/MediaViewerTransition.swift index 91ecd30a..7c24fb6e 100644 --- a/Sources/MediaViewer/Transitions/MediaViewerTransition.swift +++ b/Sources/MediaViewer/Transitions/MediaViewerTransition.swift @@ -157,10 +157,12 @@ final class MediaViewerTransition: NSObject, UIViewControllerAnimatedTransitioni } var viewsToFadeDuringTransition = mediaViewer.subviewsToFadeDuringTransition - viewsToFadeDuringTransition.append(toolbar) if wasTabBarHidden { viewsToFadeDuringTransition.append(mediaViewer.pageControlToolbar) } + if mediaViewer.toolbarHiddenBackup { + viewsToFadeDuringTransition.append(toolbar) + } for view in viewsToFadeDuringTransition { view.alpha = 0 } @@ -188,6 +190,17 @@ final class MediaViewerTransition: NSObject, UIViewControllerAnimatedTransitioni currentPageImageView.contentMode = sourceView.contentMode } currentPageImageView.layer.masksToBounds = true + + /* + * [Workaround] + * If the tabBar becomes hidden and the toolbar remains visible, + * move it manually because repositioning is not animated. + */ + if !mediaViewer.toolbarHiddenBackup, + let tabBar, + tabBarHiddenBackup! { + toolbar.frame.origin.y = tabBar.frame.origin.y + } } animator.addCompletion { position in defer { transitionContext.completeTransition() } @@ -243,7 +256,9 @@ final class MediaViewerTransition: NSObject, UIViewControllerAnimatedTransitioni assert(toolbar.layer.animationKeys() == nil) // [Workaround] Prevent toVC.toolbarItems from showing up during transition. - toVC.toolbarItems = nil + if mediaViewer.toolbarHiddenBackup { + toVC.toolbarItems = nil + } /* * [Workaround] @@ -282,10 +297,10 @@ final class MediaViewerTransition: NSObject, UIViewControllerAnimatedTransitioni let tabBar = toVC.tabBarController?.tabBar let isTabBarHidden = tabBar?.isHidden ?? true if isTabBarHidden { - viewsToFadeDuringTransition.append(contentsOf: [ - toolbar, - mediaViewer.pageControlToolbar - ]) + if mediaViewer.toolbarHiddenBackup { + viewsToFadeDuringTransition.append(toolbar) + } + viewsToFadeDuringTransition.append(mediaViewer.pageControlToolbar) } // MARK: Animation @@ -307,6 +322,15 @@ final class MediaViewerTransition: NSObject, UIViewControllerAnimatedTransitioni currentPageImageView.alpha = 0 } currentPageImageView.clipsToBounds = true // TODO: Change according to the source configuration + + /* + * [Workaround] + * If the tabBar becomes visible and the toolbar remains visible, + * move it manually because repositioning is not animated. + */ + if !mediaViewer.toolbarHiddenBackup, let tabBar { + toolbar.frame.origin.y = tabBar.frame.origin.y - toolbar.bounds.height + } } // Customize the tabBar animation