From 63aac813b693353f0e50d08160583f20938002cd Mon Sep 17 00:00:00 2001 From: John Estropia Date: Tue, 27 Aug 2019 17:40:35 +0900 Subject: [PATCH 1/3] add insert(views:) method variants --- StackScrollView-Demo/ViewController.swift | 35 ++++++++++++---- StackScrollView/StackScrollView.swift | 50 +++++++++++++++++++++++ 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/StackScrollView-Demo/ViewController.swift b/StackScrollView-Demo/ViewController.swift index 9f1d151..d0efbd8 100644 --- a/StackScrollView-Demo/ViewController.swift +++ b/StackScrollView-Demo/ViewController.swift @@ -90,13 +90,14 @@ class ViewController: UIViewController { views.append(MarginStackCell(height: 40, backgroundColor: marginColor)) views.append(HeaderStackCell(title: "ButtonStackCell", backgroundColor: marginColor)) - - (0..<3).forEach { _ in - - let s = fullSeparator() - + + let makeRemovableButton: () -> [UIView] = { + + let s = self.fullSeparator() + + var views: [UIView] = [] views.append(s) - + views.append({ let v = ButtonStackCell(buttonTitle: "Remove") v.tapped = { [unowned v] in @@ -105,8 +106,28 @@ class ViewController: UIViewController { } return v }()) - + return views } + + views.append(contentsOf: { () -> [UIView] in + let s = fullSeparator() + let v = ButtonStackCell(buttonTitle: "Insert Before") + v.tapped = { [unowned stackScrollView, unowned s] in + let views = (0 ... .random(in: 1 ... 2)).flatMap { _ in makeRemovableButton() } + stackScrollView.insert(views: views, before: s, animated: true) + } + return [s, v] + }()) + + views.append(contentsOf: { () -> [UIView] in + let s = fullSeparator() + let v = ButtonStackCell(buttonTitle: "Insert After") + v.tapped = { [unowned stackScrollView, unowned v] in + let views = (0 ... .random(in: 1 ... 2)).flatMap { _ in makeRemovableButton() } + stackScrollView.insert(views: views, after: v, animated: true) + } + return [s, v] + }()) views.append(fullSeparator()) diff --git a/StackScrollView/StackScrollView.swift b/StackScrollView/StackScrollView.swift index a536f92..91610ba 100644 --- a/StackScrollView/StackScrollView.swift +++ b/StackScrollView/StackScrollView.swift @@ -112,6 +112,56 @@ open class StackScrollView: UICollectionView, UICollectionViewDataSource, UIColl func append(lazy: @escaping () -> UIView) { } + + open func insert(views _views: [UIView], at index: Int, animated: Bool) { + + var _views = _views + _views.removeAll(where: views.contains(_:)) + views.insert(contentsOf: _views, at: index) + _views.forEach { view in + register(Cell.self, forCellWithReuseIdentifier: identifier(view)) + } + let batchUpdates: () -> Void = { + self.performBatchUpdates({ + self.insertItems(at: (index ..< index.advanced(by: _views.count)).map({ IndexPath(item: $0, section: 0) })) + }, completion: nil) + } + if animated { + UIView.animate( + withDuration: 0.5, + delay: 0, + usingSpringWithDamping: 1, + initialSpringVelocity: 0, + options: [ + .beginFromCurrentState, + .allowUserInteraction, + .overrideInheritedCurve, + .overrideInheritedOptions, + .overrideInheritedDuration + ], + animations: batchUpdates, + completion: nil) + + } else { + UIView.performWithoutAnimation(batchUpdates) + } + } + + open func insert(views _views: [UIView], before view: UIView, animated: Bool) { + + guard let index = views.firstIndex(of: view) else { + return + } + insert(views: _views, at: index, animated: animated) + } + + open func insert(views _views: [UIView], after view: UIView, animated: Bool) { + + guard let index = views.firstIndex(of: view)?.advanced(by: 1) else { + return + } + insert(views: _views, at: index, animated: animated) + } open func remove(view: UIView, animated: Bool) { From 14abfeb1e1998307e4d5721145c4e811537086d8 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Wed, 23 Oct 2019 17:32:14 +0900 Subject: [PATCH 2/3] update dataSource inside performBatchUpdates() --- StackScrollView/StackScrollView.swift | 173 +++++++++++++++++--------- 1 file changed, 113 insertions(+), 60 deletions(-) diff --git a/StackScrollView/StackScrollView.swift b/StackScrollView/StackScrollView.swift index 91610ba..abdf2e9 100644 --- a/StackScrollView/StackScrollView.swift +++ b/StackScrollView/StackScrollView.swift @@ -115,14 +115,14 @@ open class StackScrollView: UICollectionView, UICollectionViewDataSource, UIColl open func insert(views _views: [UIView], at index: Int, animated: Bool) { - var _views = _views - _views.removeAll(where: views.contains(_:)) - views.insert(contentsOf: _views, at: index) _views.forEach { view in - register(Cell.self, forCellWithReuseIdentifier: identifier(view)) + self.register(Cell.self, forCellWithReuseIdentifier: identifier(view)) } let batchUpdates: () -> Void = { self.performBatchUpdates({ + var _views = _views + _views.removeAll(where: self.views.contains(_:)) + self.views.insert(contentsOf: _views, at: index) self.insertItems(at: (index ..< index.advanced(by: _views.count)).map({ IndexPath(item: $0, section: 0) })) }, completion: nil) } @@ -149,70 +149,130 @@ open class StackScrollView: UICollectionView, UICollectionViewDataSource, UIColl open func insert(views _views: [UIView], before view: UIView, animated: Bool) { - guard let index = views.firstIndex(of: view) else { - return + _views.forEach { view in + self.register(Cell.self, forCellWithReuseIdentifier: identifier(view)) + } + let batchUpdates: () -> Void = { + self.performBatchUpdates({ + guard let index = self.views.firstIndex(of: view) else { + return + } + var _views = _views + _views.removeAll(where: self.views.contains(_:)) + self.views.insert(contentsOf: _views, at: index) + self.insertItems(at: (index ..< index.advanced(by: _views.count)).map({ IndexPath(item: $0, section: 0) })) + }, completion: nil) + } + if animated { + UIView.animate( + withDuration: 0.5, + delay: 0, + usingSpringWithDamping: 1, + initialSpringVelocity: 0, + options: [ + .beginFromCurrentState, + .allowUserInteraction, + .overrideInheritedCurve, + .overrideInheritedOptions, + .overrideInheritedDuration + ], + animations: batchUpdates, + completion: nil) + + } else { + UIView.performWithoutAnimation(batchUpdates) } - insert(views: _views, at: index, animated: animated) } open func insert(views _views: [UIView], after view: UIView, animated: Bool) { - guard let index = views.firstIndex(of: view)?.advanced(by: 1) else { - return + _views.forEach { view in + self.register(Cell.self, forCellWithReuseIdentifier: identifier(view)) + } + let batchUpdates: () -> Void = { + self.performBatchUpdates({ + guard let index = self.views.firstIndex(of: view)?.advanced(by: 1) else { + return + } + var _views = _views + _views.removeAll(where: self.views.contains(_:)) + self.views.insert(contentsOf: _views, at: index) + self.insertItems(at: (index ..< index.advanced(by: _views.count)).map({ IndexPath(item: $0, section: 0) })) + }, completion: nil) + } + if animated { + UIView.animate( + withDuration: 0.5, + delay: 0, + usingSpringWithDamping: 1, + initialSpringVelocity: 0, + options: [ + .beginFromCurrentState, + .allowUserInteraction, + .overrideInheritedCurve, + .overrideInheritedOptions, + .overrideInheritedDuration + ], + animations: batchUpdates, + completion: nil) + + } else { + UIView.performWithoutAnimation(batchUpdates) } - insert(views: _views, at: index, animated: animated) } open func remove(view: UIView, animated: Bool) { - - if let index = views.firstIndex(of: view) { - views.remove(at: index) - if animated { - UIView.animate( - withDuration: 0.5, - delay: 0, - usingSpringWithDamping: 1, - initialSpringVelocity: 0, - options: [ - .beginFromCurrentState, - .allowUserInteraction, - .overrideInheritedCurve, - .overrideInheritedOptions, - .overrideInheritedDuration - ], - animations: { - self.performBatchUpdates({ - self.deleteItems(at: [IndexPath(item: index, section: 0)]) - }, completion: nil) - }) { (finish) in - - } - - } else { - UIView.performWithoutAnimation { - performBatchUpdates({ - self.deleteItems(at: [IndexPath(item: index, section: 0)]) - }, completion: nil) + + let batchUpdates: () -> Void = { + self.performBatchUpdates({ + guard let index = self.views.firstIndex(of: view) else { + return } - } + self.views.remove(at: index) + self.deleteItems(at: [IndexPath(item: index, section: 0)]) + }, completion: nil) + } + if animated { + UIView.animate( + withDuration: 0.5, + delay: 0, + usingSpringWithDamping: 1, + initialSpringVelocity: 0, + options: [ + .beginFromCurrentState, + .allowUserInteraction, + .overrideInheritedCurve, + .overrideInheritedOptions, + .overrideInheritedDuration + ], + animations: batchUpdates, + completion: nil) + + } else { + UIView.performWithoutAnimation(batchUpdates) } } open func remove(views: [UIView], animated: Bool) { - var indicesForRemove: [Int] = [] + let batchUpdates: () -> Void = { + self.performBatchUpdates({ + var indicesForRemove: [Int] = [] - for view in views { - if let index = self.views.firstIndex(of: view) { - indicesForRemove.append(index) - } - } + for view in views { + if let index = self.views.firstIndex(of: view) { + indicesForRemove.append(index) + } + } - // It seems that the layout is not updated properly unless the order is aligned. - indicesForRemove.sort(by: >) + // It seems that the layout is not updated properly unless the order is aligned. + indicesForRemove.sort(by: >) - for index in indicesForRemove { - self.views.remove(at: index) + for index in indicesForRemove { + self.views.remove(at: index) + } + self.deleteItems(at: indicesForRemove.map { IndexPath.init(item: $0, section: 0) }) + }, completion: nil) } if animated { @@ -228,17 +288,10 @@ open class StackScrollView: UICollectionView, UICollectionViewDataSource, UIColl .overrideInheritedOptions, .overrideInheritedDuration ], - animations: { - self.performBatchUpdates({ - self.deleteItems(at: indicesForRemove.map { IndexPath.init(item: $0, section: 0) }) - }, completion: nil) - }) + animations: batchUpdates, + completion: nil) } else { - UIView.performWithoutAnimation { - performBatchUpdates({ - self.deleteItems(at: indicesForRemove.map { IndexPath.init(item: $0, section: 0) }) - }, completion: nil) - } + UIView.performWithoutAnimation(batchUpdates) } } From fed673807c4d626cd36cd58a0bc7177e8a2bb404 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Wed, 23 Oct 2019 17:39:46 +0900 Subject: [PATCH 3/3] formatting --- StackScrollView/StackScrollView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/StackScrollView/StackScrollView.swift b/StackScrollView/StackScrollView.swift index abdf2e9..c96ee08 100644 --- a/StackScrollView/StackScrollView.swift +++ b/StackScrollView/StackScrollView.swift @@ -116,7 +116,7 @@ open class StackScrollView: UICollectionView, UICollectionViewDataSource, UIColl open func insert(views _views: [UIView], at index: Int, animated: Bool) { _views.forEach { view in - self.register(Cell.self, forCellWithReuseIdentifier: identifier(view)) + register(Cell.self, forCellWithReuseIdentifier: identifier(view)) } let batchUpdates: () -> Void = { self.performBatchUpdates({ @@ -150,7 +150,7 @@ open class StackScrollView: UICollectionView, UICollectionViewDataSource, UIColl open func insert(views _views: [UIView], before view: UIView, animated: Bool) { _views.forEach { view in - self.register(Cell.self, forCellWithReuseIdentifier: identifier(view)) + register(Cell.self, forCellWithReuseIdentifier: identifier(view)) } let batchUpdates: () -> Void = { self.performBatchUpdates({ @@ -187,7 +187,7 @@ open class StackScrollView: UICollectionView, UICollectionViewDataSource, UIColl open func insert(views _views: [UIView], after view: UIView, animated: Bool) { _views.forEach { view in - self.register(Cell.self, forCellWithReuseIdentifier: identifier(view)) + register(Cell.self, forCellWithReuseIdentifier: identifier(view)) } let batchUpdates: () -> Void = { self.performBatchUpdates({