Fixing reuse and sizing issues.

This commit is contained in:
Pfeil, Scott Robert 2020-04-10 11:15:55 -04:00
parent 185efa547e
commit 8da03356e4
4 changed files with 63 additions and 34 deletions

View File

@ -54,6 +54,32 @@ open class Carousel: View {
private var size: CGFloat?
// Updates the model and index.
public func updateModelIndex() {
(model as? CarouselModel)?.index = pageIndex
}
open override func layoutSubviews() {
super.layoutSubviews()
// Accounts for any collection size changes
DispatchQueue.main.async {
self.layoutCollection()
}
}
/// Invalidates the layout and ensures we are paged to the correct cell.
open func layoutCollection() {
collectionView.collectionViewLayout.invalidateLayout()
showPeaking(false)
// Go to current cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. The dispatch is a sad way to ensure the collection view is ready to be scrolled.
DispatchQueue.main.async {
self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false)
self.collectionView.layoutIfNeeded()
self.showPeaking(true)
}
}
// MARK: - MVMCoreViewProtocol
open override func setupView() {
super.setupView()
@ -73,15 +99,12 @@ open class Carousel: View {
open override func updateView(_ size: CGFloat) {
super.updateView(size)
self.size = size
collectionView.collectionViewLayout.invalidateLayout()
showPeaking(false)
// Go to current cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. The dispatch is a sad way to ensure the collection view is ready to be scrolled.
DispatchQueue.main.async {
self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false)
self.collectionView.layoutIfNeeded()
self.showPeaking(true)
// Update cells and re-layout.
for cell in collectionView.visibleCells {
(cell as? MVMCoreViewProtocol)?.updateView(size)
}
layoutCollection()
}
// MARK: - MoleculeViewProtocol
@ -108,6 +131,9 @@ open class Carousel: View {
}
setupPagingMolecule(carouselModel.pagingMolecule, delegateObject: delegateObject)
pageIndex = carouselModel.index
pagingView?.setPage(carouselModel.index)
collectionView.reloadData()
}
@ -197,6 +223,7 @@ open class Carousel: View {
}
let currentPage = pager.currentPage()
localSelf.pageIndex = currentPage
localSelf.updateModelIndex()
localSelf.goTo(localSelf.currentIndex, animated: !UIAccessibility.isVoiceOverRunning)
})
}
@ -246,7 +273,7 @@ open class Carousel: View {
extension Carousel: UICollectionViewDelegateFlowLayout {
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemWidth = (size ?? collectionView.bounds.width) * CGFloat(itemWidthPercent)
let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent)
return CGSize(width: itemWidth, height: collectionView.bounds.height)
}
@ -280,19 +307,18 @@ extension Carousel: UIScrollViewDelegate {
func goTo(_ index: Int, animated: Bool) {
showPeaking(false)
setAccessiblity(collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)), index: index)
self.currentIndex = index
self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: animated)
if let cell = collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)) {
setAccessiblity(collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)), index: index)
setAccessiblity(collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)), index: index)
currentIndex = index
updateModelIndex()
collectionView.scrollToItem(at: IndexPath(row: currentIndex, section: 0), at: itemAlignment, animated: animated)
if let cell = collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)) {
setAccessiblity(collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)), index: index)
UIAccessibility.post(notification: .layoutChanged, argument: cell)
}
}
func handleUserOnBufferCell() {
guard loop else {
return
}
guard loop else { return }
let lastPageIndex = numberOfPages + 1
let goToIndex = {(index: Int) in
@ -320,9 +346,11 @@ extension Carousel: UIScrollViewDelegate {
let index = scrollView.contentOffset.x / (itemWidth + separatorWidth)
let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1
if index < 1 {
self.currentIndex = 0
currentIndex = 0
updateModelIndex()
} else if index > CGFloat(lastCellIndex - 1) {
self.currentIndex = lastCellIndex
currentIndex = lastCellIndex
updateModelIndex()
}
}
@ -348,9 +376,7 @@ extension Carousel: UIScrollViewDelegate {
targetContentOffset.pointee = scrollView.contentOffset
// This is for setting up smooth custom paging. (Since UICollectionView only handles paging based on collection view size and not cell size).
guard let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing else {
return
}
guard let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing else { return }
// We switch cards if we pass the velocity threshold or position threshold (currently 50%).
let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent)

View File

@ -12,7 +12,7 @@ import UIKit
public static var identifier: String = "carousel"
public var backgroundColor: Color?
public var molecules: [CarouselItemModel]
public var index: Int = 0
public var spacing: Float?
public var border: Bool?
public var loop: Bool?
@ -29,6 +29,7 @@ import UIKit
case moleculeName
case backgroundColor
case molecules
case index
case spacing
case border
case loop
@ -40,15 +41,16 @@ import UIKit
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
self.molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules)
self.backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
self.spacing = try typeContainer.decodeIfPresent(Float.self, forKey: .spacing)
self.border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border)
self.loop = try typeContainer.decodeIfPresent(Bool.self, forKey: .loop)
self.height = try typeContainer.decodeIfPresent(Float.self, forKey: .height)
self.itemWidthPercent = try typeContainer.decodeIfPresent(Float.self, forKey: .itemWidthPercent)
self.itemAlignment = try typeContainer.decodeIfPresent(UICollectionView.ScrollPosition.self, forKey: .itemAlignment)
self.pagingMolecule = try typeContainer.decodeModelIfPresent(codingKey: .pagingMolecule)
molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules)
index = try typeContainer.decodeIfPresent(Int.self, forKey: .index) ?? 0
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
spacing = try typeContainer.decodeIfPresent(Float.self, forKey: .spacing)
border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border)
loop = try typeContainer.decodeIfPresent(Bool.self, forKey: .loop)
height = try typeContainer.decodeIfPresent(Float.self, forKey: .height)
itemWidthPercent = try typeContainer.decodeIfPresent(Float.self, forKey: .itemWidthPercent)
itemAlignment = try typeContainer.decodeIfPresent(UICollectionView.ScrollPosition.self, forKey: .itemAlignment)
pagingMolecule = try typeContainer.decodeModelIfPresent(codingKey: .pagingMolecule)
}
public func encode(to encoder: Encoder) throws {

View File

@ -33,7 +33,7 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController {
bottomView.updateView(width)
showFooter(width)
}
self.tableView?.reloadData()
tableView?.reloadData()
}
open override func handleNewData() {

View File

@ -278,7 +278,8 @@ import UIKit
return
}
if needsUpdateUI || screenSizeChanged() {
// First update should be explicit (hence the zero check)
if needsUpdateUI || (previousScreenSize != .zero && screenSizeChanged()) {
updateViews()
needsUpdateUI = false
}