Skip to content

Commit 4b808ad

Browse files
committed
Added other docs, implemented visibleRows, enterlyVisibleRows and isEmpty methods
1 parent b9591b0 commit 4b808ad

File tree

10 files changed

+149
-17
lines changed

10 files changed

+149
-17
lines changed

README.md

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ You can think of it as `UITableView` but with several differences:
1616
- System Requirements
1717
- How to use it
1818
- Adding Rows
19-
- Removing Rows
19+
- Removing / Replacing Rows
20+
- Move Rows
21+
- Hide / Show Rows
22+
- Reload Rows
23+
- Sizing Rows
2024

2125
### Main Features
2226

@@ -66,6 +70,23 @@ Each row managed by `ScrollStack` is a subclass of `ScrollStackRow`: it strongly
6670

6771
You don't need to handle lifecycle of your rows/view controller until they are part of the rows inside the stack.
6872

73+
To get the list of rows of the stack you can use the `rows` property.
74+
75+
```swift
76+
// Standard methods
77+
let allRows = scrollStack.rows
78+
let isEmpty = scrollStack.isEmpty // true if it does not contains row
79+
let notHiddenRows = scrollStack.rows.filter { !$0.isHidden }
80+
81+
// By Vibility
82+
let currentlyVisibleRows = scrollStack.visibleRows // only currently visible rows (partially or enterly)
83+
let enterlyVisibleRows = scrollStack.enterlyVisibleRows // only enterly visible rows into the stack
84+
85+
// Shortcuts
86+
let firstRow = scrollStack.firstRow
87+
let lastRow = scrollStack.lastRow
88+
```
89+
6990
Let's take a look below.
7091

7192
#### Adding Rows
@@ -94,6 +115,96 @@ The following code add a rows with the view of each view controller passed:
94115
stackView.addRows(controllers: [welcomeVC, notesVC, tagsVC, galleryVC], animated: false)
95116
```
96117

97-
As you noted there is not need to keep a strong reference to any view controller; they are automatically strong referenced by each row created to add them into the stack.
118+
As you noticed there is not need to keep a strong reference to any view controller; they are automatically strong referenced by each row created to add them into the stack.
119+
120+
#### Removing / Replacing Rows
121+
122+
A similar set of APIs are used to remove existing rows from the stack:
123+
124+
- `removeAllRows(animated:)`: to remove all rows of the stack.
125+
- `removeRow(index:animated:) -> UIViewController?`: to remove a specific row at given index. It returns a reference to removed view controller.
126+
- `removeRows(indexes:animated:) -> [UIViewController]?`: to remove rows at specified indexes from the stack. Removed managed `UIViewController` instances are returned.
127+
- `replaceRow(index:withRow:animated:completion:)`: replace an existing row with a new row which manage new passed view controller.
128+
129+
An example:
130+
131+
```swift
132+
let newVC: UIViewController = ...
133+
stackView.replaceRow(index: 1, withRow: galleryVC, animated: true) {
134+
print("Gallery controller is now in place!!")
135+
}
136+
```
137+
138+
#### Move Rows
139+
140+
If you need to adjust the hierarchy of the stack by moving a row from a position to another you can use:
141+
142+
- `moveRow(index:to:animated:completion:)`: move a row at passed inside to another index (both of indexes must be valid).
143+
144+
The following method move the first row at a random position, by animating the transition:
145+
146+
```swift
147+
let randomDst = Int.random(in: 1..<stackView.rows.count)
148+
stackView.moveRow(index: 0, to: randomDst, animated: true, completion: nil)
149+
```
150+
151+
#### Hide / Show Rows
152+
153+
`ScrollStack` uses the power of `UIStackView`: you can show and hide rows easily with a gorgeous animation by using one of the following methods:
154+
155+
- `setRowHidden(index:isHidden:animated:completion:)`: hide or show a row at index.
156+
- `setRowsHidden(indexes:isHidden:animated:completion:)`: hide or show multiple rows at specified indexes.
157+
158+
Example:
159+
160+
```swift
161+
stackView.setRowsHidden(indexes: [0,1,2], isHidden: true, animated: true)
162+
```
163+
164+
Keep in mind: when you hide a rows the row still part of the stack and it's not removed, just hidden! If you get the list of rows by calling `rows` property of the `ScrollStack` you still see it.
165+
166+
#### Reload Rows
167+
168+
Reload rows method allows you to refresh the layout of the entire stack (using `layoutIfNeeded()`) while you have a chance to update a specific row's `contentView` (aka the view of the managed `UIViewController`).
169+
170+
There are three methods:
171+
172+
- `reloadRow(index:animated:completion:)`: reload a specific row at index.
173+
- `reloadRows(indexes:animated:completion:)`: reload a specific set of rows.
174+
- `reloadAllRows(animated:completion:)`: reload all rows.
175+
176+
If your `UIViewController` implements `ScrollStackContainableController` protocol you will get notified inside the class about this request, so you have the opportunity to refresh your data:
177+
178+
Example:
179+
180+
```swift
181+
class MyViewController: UIViewController {
182+
183+
private let scrollStackController = ScrollStackController()
184+
185+
@IBAction func someAction() {
186+
scrollStackController.stackView.reloadRow(0)
187+
}
188+
189+
}
190+
191+
// Your row 0 manages the GalleryVC, so in your GalleryVC implementation:
192+
193+
class GalleryVC: UIViewController, ScrollStackContainableController {
194+
195+
public func func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool) {
196+
// update your UI
197+
}
198+
199+
}
200+
```
201+
202+
#### Sizing Rows
203+
204+
You can control the size of your `UIViewController` inside a row of a `ScrollStack` in two ways:
205+
206+
- Creating contrains in your `UIViewController`'s view with Autolayout.
207+
- Implementing `ScrollStackContainableController` protocol in your `UIViewController` class and return a non `nil` value in `scrollStackRowSizeForAxis(:row:in:) -> ScrollStack.ControllerSize?` delegate method.
208+
209+
In both case `ScrollStack` class will use only one dimension depending by the active scroll axis to layout the view controller content into the stack (if scroll axis is `horizontal` you can control only the `height` of the row, if it's `vertical` only the `width`. The other dimension will be the same of the scroll stack itself.
98210

99-
#### Removing Rows

ScrollStackControllerDemo/Child View Controllers/GalleryVC.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ public class GalleryVC: UIViewController, ScrollStackContainableController {
3535
reloadData()
3636
}
3737

38-
public func reloadContentFromStackViewRow() {
39-
38+
public func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool) {
39+
4040
}
4141

4242
private func reloadData() {

ScrollStackControllerDemo/Child View Controllers/NotesVC.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ public class NotesVC: UIViewController, ScrollStackContainableController {
4343
super.updateViewConstraints()
4444
}
4545

46-
public func reloadContentFromStackViewRow() {
47-
46+
public func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool) {
47+
4848
}
4949

5050
public override func viewDidLoad() {

ScrollStackControllerDemo/Child View Controllers/PricingVC.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ public class PricingVC: UIViewController, ScrollStackContainableController {
6565
viewDidLayoutSubviews()
6666
}
6767

68-
public func reloadContentFromStackViewRow() {
69-
68+
public func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool) {
69+
7070
}
7171

7272
@IBAction public func addFee() {

ScrollStackControllerDemo/Child View Controllers/TagsVC.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ public class TagsVC: UIViewController, ScrollStackContainableController {
5252
return (isExpanded == false ? .fixed(170) : .fixed(170 + collectionView.contentSize.height + 20))
5353
}
5454

55-
public func reloadContentFromStackViewRow() {
56-
55+
public func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool) {
56+
5757
}
5858

5959
public override func viewDidLoad() {

ScrollStackControllerDemo/Child View Controllers/WelcomeVC.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ public class WelcomeVC: UIViewController, ScrollStackContainableController {
2323
return .fitLayoutForAxis
2424
}
2525

26-
public func reloadContentFromStackViewRow() {
27-
26+
public func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool) {
27+
2828
}
2929

3030
}

Sources/ScrollStackController/ScrollStack.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,25 @@ open class ScrollStack: UIScrollView, UIScrollViewDelegate {
7272
} as! [ScrollStackRow]
7373
}
7474

75+
/// Return all visible (partially or enterly) rows.
76+
public var visibleRows: [ScrollStackRow]? {
77+
return rows.enumerated().compactMap { (idx, item) in
78+
return (isRowVisible(index: idx).isVisible ? item : nil)
79+
}
80+
}
81+
82+
/// Return only entirly visible rows.
83+
public var enterlyVisibleRows: [ScrollStackRow]? {
84+
return rows.enumerated().compactMap { (idx, item) in
85+
return (isRowVisible(index: idx) == .entire ? item : nil)
86+
}
87+
}
88+
89+
/// Return `true` if no rows are into the stack.
90+
public var isEmpty: Bool {
91+
return rows.isEmpty
92+
}
93+
7594
/// Get the first row of the stack, if any.
7695
open var firstRow: ScrollStackRow? {
7796
return rows.first
@@ -583,7 +602,7 @@ open class ScrollStack: UIScrollView, UIScrollViewDelegate {
583602
}
584603

585604
rows.forEach {
586-
$0.askForCutomizedSizeOfContentView()
605+
$0.askForCutomizedSizeOfContentView(animated: animated)
587606
}
588607

589608
UIView.execute(animated: animated, {

Sources/ScrollStackController/ScrollStackRow.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ open class ScrollStackRow: UIView, UIGestureRecognizerDelegate {
176176
addSubview(contentView)
177177
addSubview(separatorView)
178178

179-
askForCutomizedSizeOfContentView()
179+
askForCutomizedSizeOfContentView(animated: false)
180180

181181
didUpdateContentViewContraints()
182182
didUpdateSeparatorViewContraintsIfNeeded()
@@ -247,7 +247,7 @@ open class ScrollStackRow: UIView, UIGestureRecognizerDelegate {
247247

248248
// MARK: - Sizing the Controller
249249

250-
internal func askForCutomizedSizeOfContentView() {
250+
internal func askForCutomizedSizeOfContentView(animated: Bool) {
251251
guard let customizableController = controller as? ScrollStackContainableController else {
252252
return // ignore, it's not implemented, use autolayout.
253253
}
@@ -264,6 +264,8 @@ open class ScrollStackRow: UIView, UIGestureRecognizerDelegate {
264264
case .fitLayoutForAxis:
265265
setupRowSizeToFitLayout()
266266
}
267+
268+
customizableController.reloadContentFromStackView(stackView: stackView!, row: self, animated: animated)
267269
}
268270

269271
private func setupRowToFixedValue(_ value: CGFloat) {

Sources/ScrollStackController/Support/ScrollStack+Protocols.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public protocol ScrollStackContainableController: UIViewController {
5252
func scrollStackRowSizeForAxis(_ axis: NSLayoutConstraint.Axis, row: ScrollStackRow, in stackView: ScrollStack) -> ScrollStack.ControllerSize?
5353

5454
/// Method is called when you call a `reloadRow` function on a row where this controller is contained in.
55-
func reloadContentFromStackViewRow()
55+
func reloadContentFromStackView(stackView: ScrollStack, row: ScrollStackRow, animated: Bool)
5656

5757
}
5858

0 commit comments

Comments
 (0)