MediaPreviewFlowLayout.swift 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. import UIKit
  21. class MediaPreviewFlowLayout: UICollectionViewFlowLayout {
  22. /// Returns the width of the collectionView minus the relevant insets
  23. /// - Parameter bounds: the bounds of the collectionView
  24. /// - Returns: Width of a cell in the collectionView
  25. func cellWidth(bounds: CGRect) -> CGFloat {
  26. guard let collectionView = collectionView else {
  27. return 0
  28. }
  29. let insets = collectionView.contentInset
  30. let width = bounds.width - insets.left - insets.right
  31. if width < 0 {
  32. return 0
  33. } else {
  34. return width
  35. }
  36. }
  37. /// Returns the height of the collectionView minus the relevant insets
  38. /// - Parameter bounds: the bounds of the collectionView
  39. /// - Returns: Height of a cell in the collectionView
  40. func cellHeight(bounds : CGRect) -> CGFloat {
  41. guard let collectionView = collectionView else {
  42. return 0
  43. }
  44. let insets = collectionView.contentInset
  45. let height = bounds.height - insets.top - insets.bottom
  46. if height < 0 {
  47. return 0
  48. } else {
  49. return height
  50. }
  51. }
  52. // Update the estimatedItemSize to the bounds
  53. func updateEstimatedItemSize(bounds: CGRect) {
  54. let height = cellHeight(bounds: bounds)
  55. let width = cellWidth(bounds: bounds)
  56. estimatedItemSize = CGSize(
  57. width: width,
  58. height: height
  59. )
  60. }
  61. func updateContentOffset(bounds: CGRect) {
  62. guard let collectionView = self.collectionView?.dataSource as? MainCollectionViewController else {
  63. return
  64. }
  65. guard let selection = collectionView.delegate.getCurrentlyVisibleItem() else {
  66. return
  67. }
  68. guard let largeCollectionView = collectionView.delegate.largeCollectionView else {
  69. return
  70. }
  71. let size = collectionView.collectionView(largeCollectionView, layout: self, sizeForItemAt: selection)
  72. let xOffset = size.width * CGFloat(selection.item)
  73. let offset = CGPoint(x: xOffset, y: 0.0)
  74. self.collectionView?.contentOffset = offset
  75. }
  76. // Is called whenever the layout is invalid.
  77. // Either on first display or when the layout is manually invalidated.
  78. override func prepare() {
  79. super.prepare()
  80. let bounds = collectionView?.bounds ?? .zero
  81. updateEstimatedItemSize(bounds: bounds)
  82. updateContentOffset(bounds: bounds)
  83. }
  84. // Update the estimated size and the content offset if the screen size has changed
  85. // i.e. if the device has been rotated
  86. override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
  87. let _ = super.shouldInvalidateLayout(forBoundsChange: newBounds)
  88. guard let collectionView = collectionView else {
  89. return false
  90. }
  91. let oldSize = collectionView.bounds.size
  92. if oldSize == newBounds.size {
  93. return false
  94. }
  95. updateEstimatedItemSize(bounds: newBounds)
  96. updateContentOffset(bounds: newBounds)
  97. return true
  98. }
  99. }