Skip to content

Commit b98e5c8

Browse files
committed
Merge tag '1.0.1' into develop
1.0.1
2 parents b15ef47 + 88f2b7c commit b98e5c8

5 files changed

Lines changed: 168 additions & 47 deletions

File tree

README.md

Lines changed: 162 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# ScrollStackController
22
Create complex scrollable layout using `UIViewController` and simplify your code!
33

4-
[![Version](https://img.shields.io/cocoapods/v/OwlKit.svg?style=flat)](http://cocoadocs.org/docsets/ScrollStackController)
5-
[![License](https://img.shields.io/cocoapods/l/OwlKit.svg?style=flat)](http://cocoadocs.org/docsets/ScrollStackController)
6-
[![Platform](https://img.shields.io/cocoapods/p/OwlKit.svg?style=flat)](http://cocoadocs.org/docsets/ScrollStackController)
7-
[![CI Status](https://travis-ci.org/malcommac/OwlKit.svg)](https://travis-ci.org/malcommac/ScrollStackController)
8-
![Twitter Follow](https://img.shields.io/twitter/follow/danielemargutti.svg?label=Follow&style=flat-square)
4+
[![Version](https://img.shields.io/cocoapods/v/ScrollStackController.svg?style=flat)](http://cocoadocs.org/docsets/ScrollStackController)
5+
[![Platform](https://img.shields.io/cocoapods/p/ScrollStackController.svg?style=flat)](http://cocoadocs.org/docsets/ScrollStackController)
6+
[![License](https://img.shields.io/cocoapods/l/ScrollStackController.svg?style=flat)](http://cocoadocs.org/docsets/ScrollStackController)
7+
[![danielemargutti.com](https://img.shields.io/badge/HomePage-danielemargutti.com-brightgreen)
8+
](https://www.danielemargutti.com)
9+
[![Twitter Follow](https://img.shields.io/twitter/follow/danielemargutti?label=Follow%20Me&style=social)](https://twitter.com/danielemargutti)
910

1011
ScrollStackController was created and maintaned by [Daniele Margutti](https://twitter.com/danielemargutti)[Web Site](https://www.danielemargutti.com)
1112

@@ -18,12 +19,23 @@ You can think of it as `UITableView` but with several differences:
1819
- **Powered by AutoLayout since the beginning**; it uses a combination of `UIScrollView + UIStackView` to offer an animation friendly controller ideal for fixed and dynamic row sizing.
1920
- **You don't need to struggle yourself with view recycling**: suppose you have a layout composed by several different screens. There is no need of view recycling but it cause a more difficult managment of the layout. With a simpler and safer APIs set `ScrollStackView` is the ideal way to implement such layouts.
2021

22+
### Main Features
23+
24+
25+
| | Features Highlights |
26+
|--- |--------------------------------------------------------------------------------- |
27+
| 🕺 | Create complex layout without the boilerplate required by view recyling of `UICollectionView` or `UITableView`. |
28+
| 🧩 | Simplify your architecture by thinking each screen as a separate-indipendent `UIVIewController`. |
29+
| 🌈 | Animate show/hide and resize of rows easily! |
30+
|| Compact code base, less than 1k LOC with no external dependencies. |
31+
| 🎯 | Easy to use and extensible APIs set. |
32+
| 🧬 | It uses standard UIKit components at its core. No magic, just a combination of `UIScrollView`+`UIStackView`. |
33+
| 🐦 | Fully made in Swift 5 from Swift ❥ lovers |
34+
2135
<a name="index"/>
2236

2337
## Table of Contents
2438

25-
- [Main Features](#mainfeatures)
26-
- [System Requirements](#systemrequirements)
2739
- [When to use `ScrollStackController` and when not](#whentousescrollstackcontrollerandwhennot)
2840
- [How to use it](#howtouseit)
2941
- [Adding Rows](#addingrows)
@@ -38,34 +50,15 @@ You can think of it as `UITableView` but with several differences:
3850
- [Working with dynamic UICollectionView/UITableView/UITextView](#workingwithdynamicuicollectionviewuitableviewuitextview)
3951
- [Rows Separator](#rowsseparator)
4052
- [Tap On Rows](#taponrows)
53+
- [Get the row/controller](#utilsmethods)
54+
- [Set Row Insets](#setrowinsets)
55+
- [Change ScrollStack scrolling axis](#changescrollaxis)
56+
- [Subscribe to Events](#rowevents)
57+
- [Example App](#exampleapp)
4158
- [Installation](#installation)
59+
- [System Requirements](#systemrequirements)
4260
- [Author & License](#authorlicense)
4361

44-
<a name="mainfeatures"/>
45-
46-
### Main Features
47-
48-
49-
| | Features Highlights |
50-
|--- |--------------------------------------------------------------------------------- |
51-
| 🕺 | Create complex layout without the boilerplate required by view recyling of `UICollectionView` or `UITableView`. |
52-
| 🧩 | Simplify your architecture by thinking each screen as a separate-indipendent `UIVIewController`. |
53-
| 🌈 | Animate show/hide and resize of rows easily! |
54-
|| Compact code base, less than 1k LOC with no external dependencies. |
55-
| 🎯 | Easy to use and extensible APIs set. |
56-
| 🧬 | It uses standard UIKit components at its core. No magic, just a combination of `UIScrollView`+`UIStackView`. |
57-
| 🐦 | Fully made in Swift 5 from Swift ❥ lovers |
58-
59-
<a name="systemrequirements"/>
60-
61-
### System Requirements
62-
63-
- iOS 11+
64-
- Xcode 10+
65-
- Swift 5+
66-
67-
[↑ Back To Top](#index)
68-
6962
<a name="whentousescrollstackcontrollerandwhennot"/>
7063

7164
### When to use `ScrollStackController` and when not
@@ -82,6 +75,8 @@ If you have a long list of rows you may experience delays.
8275

8376
So, `ScrollStackController` is generally not appropriate for screens that contain many views of the same type, all showing similar data (in these cases you should use `UITableView` or `UICollectionView`).
8477

78+
![Demo Project](https://media.giphy.com/media/fAi3hyXNalzd4SkVgI/giphy.gif)
79+
8580
[↑ Back To Top](#index)
8681

8782
<a name="howtouseit"/>
@@ -90,7 +85,16 @@ So, `ScrollStackController` is generally not appropriate for screens that contai
9085

9186
The main class of the package is `ScrollStack`, a subclass of `UIScrollView`. It manages the layout of each row, animations and keep a strong reference to your rows.
9287

93-
However usually you don't want to intantiate this control directly but by calling the `ScrollStackController` class.
88+
This is an overview of the architecture:
89+
90+
![](./Resources/architecture.png)
91+
92+
- `ScrollStackController `: is a subclass of `UIViewController`. You would to use it and add as a child controller of your view controller. This allows you to manage any child-controllers related events for each row you will add to the stack controller.
93+
- `ScrollStack`: the view of the `ScrollStackController ` is a `ScrollStack`, a subclass of `UIScrollView` with an `UIStackView` which allows you to manage the layout of the stack. You can access to it via `scrollStack` property of the controller.
94+
- Each row is a `ScrollStackRow`, which is a subclass of `UIView`. Inside there are two views, the `contentView` (a reference to managed `UIViewController`'s `view`) and the `separatorView`. A row strongly reference managed view controller, so you don't need to keep a strong reference by your own.
95+
- Separator view are subclass of `ScrollStackSeparator` class.
96+
97+
As we said, usually you don't want to intantiate a `ScrollStack` control directly but by using the `ScrollStackController` class.
9498
It's a view controller which allows you to get the child view controller's managment for free, so when you add/remove a row to the stack you will get the standard UIViewController events for free!
9599

96100
This is an example of initialization in a view controller:
@@ -102,6 +106,8 @@ class MyViewController: UIViewController {
102106

103107
override func viewDidLoad() {
104108
super.viewDidLoad()
109+
110+
stackController.view.frame = contentView.bounds
105111
contentView.addSubview(stackController.view)
106112
}
107113

@@ -111,7 +117,7 @@ class MyViewController: UIViewController {
111117
Now you are ready to use the `ScrollStack` control inside the `stackController` class.
112118
`ScrollStack` have an extensible rich set of APIs to manage your layout: add, remove, move, hide or show your rows, including insets and separator management.
113119

114-
Each row managed by `ScrollStack` is a subclass of `ScrollStackRow`: it strongly reference a parent `UIViewController` class where you content is placed. `UIViewController`'s `view` will be the `contentView` of the row.
120+
Each row managed by `ScrollStack` is a subclass of `ScrollStackRow`: it strongly reference a parent `UIViewController` class where you content is placed. `UIViewController`'s `view` will be the `contentView` of the row itself.
115121

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

@@ -183,7 +189,7 @@ An example:
183189

184190
```swift
185191
let newVC: UIViewController = ...
186-
stackView.replaceRow(index: 1, withRow: galleryVC, animated: true) {
192+
stackView.replaceRow(index: 1, withRow: newVC, animated: true) {
187193
print("Gallery controller is now in place!!")
188194
}
189195
```
@@ -248,7 +254,7 @@ class MyViewController: UIViewController {
248254
private let scrollStackController = ScrollStackController()
249255

250256
@IBAction func someAction() {
251-
scrollStackController.stackView.reloadRow(0)
257+
scrollStackController.scrollStack.reloadRow(0)
252258
}
253259

254260
}
@@ -470,14 +476,126 @@ Transition between highlights state will be animated automatically.
470476

471477
[↑ Back To Top](#index)
472478

479+
<a name="utilsmethods"/>
480+
481+
### Get the row/controller
482+
483+
**Get the (first) row which manage a specific view controller type**
484+
You can get the first row which manage a specific view controller class using `firstRowForControllerOfType<T: UIViewController>(:) -> ScrollStackRow?` function.
485+
486+
```swift
487+
let tagsVC = scrollStack.firstRowForControllerOfType(TagsVC.self) // TagsVC instance
488+
```
489+
490+
**Get the row which manage a specific controller instance**
491+
To get the row associated with a specific controller you can use `rowForController()` function:
492+
493+
```swift
494+
let row = scrollStack.rowForController(tagsVC) // ScrollStackRow
495+
```
496+
497+
<a name="setrowinsets"/>
498+
499+
### Set Row Insets
500+
501+
To set an insets for a specific row you can use `setRowInsets()` function:
502+
503+
```example
504+
let newInsets: UIEdgeInsets = ...
505+
scrollStack.setRowInsets(index: 0, insets: newInsets)
506+
```
507+
508+
You can also use `setRowsInsets()` to set multiple rows.
509+
510+
Moreover by setting `.rowInsets` in your `ScrollStack` class you can set a default insets value for new row added.
511+
512+
<a name="changescrollaxis"/>
513+
514+
### Change ScrollStack scrolling axis
515+
516+
In order to change the axis of scroll for your `ScrollStack` instances you can set the `axis` property to `horizontal` or `vertical.
517+
518+
<a name="rowevents"/>
519+
520+
### Subscribe to Row Events
521+
522+
You can listen when a row is removed or added into the stack view by subscribing the `onChangeRow` property.
523+
524+
```swift
525+
scrollStackView.onChangeRow = { (row, isRemoved) in
526+
if isRemoved {
527+
print("Row at index \(row.index) was removed"
528+
} else {
529+
print("A new row is added at index: \(row.index). It manages \(type(of: row.controller))")
530+
}
531+
}
532+
```
533+
534+
You can also subscribe events for events about row visibility state changes by setting the `stackDelegate`. Your destination object must therefore conforms to the `ScrollStackControllerDelegate ` protocol:
535+
536+
Example:
537+
538+
```swift
539+
class ViewController: ScrollStackController, ScrollStackControllerDelegate {
540+
541+
func viewDidLoad() {
542+
super.viewDidLoad()
543+
544+
self.scrollStack.stackDelegate = self
545+
}
546+
547+
func scrollStackDidScroll(_ stackView: ScrollStack, offset: CGPoint) {
548+
// stack did scroll
549+
}
550+
551+
func scrollStackRowDidBecomeVisible(_ stackView: ScrollStack, row: ScrollStackRow, index: Int, state: ScrollStack.RowVisibility) {
552+
// Row did become partially or entirely visible.
553+
}
554+
555+
func scrollStackRowDidBecomeHidden(_ stackView: ScrollStack, row: ScrollStackRow, index: Int, state: ScrollStack.RowVisibility) {
556+
// Row did become partially or entirely invisible.
557+
}
558+
559+
}
560+
```
561+
562+
`ScrollStack.RowVisibility` is an enum with the following cases:
563+
564+
- `partial`: row is partially visible.
565+
- `entire`: row is entirely visible.
566+
- `hidden`: row is invisible and hidden.
567+
- `offscreen`: row is not hidden but currently offscreen due to scroll position.
568+
569+
[ Back To Top](#index)
570+
571+
<a name="systemrequirements"/>
572+
573+
### System Requirements
574+
575+
- iOS 11+
576+
- Xcode 10+
577+
- Swift 5+
578+
579+
[ Back To Top](#index)
580+
581+
<a name="exampleapp"/>
582+
583+
### Example App
584+
585+
`ScrollStackController` comes with a demo application which show how easy you can create complex scrollable layoyut and some of the major features of the library.
586+
587+
You should look at it in order to implement your own layout, create dynamically sized rows and dispatch events.
588+
589+
[ Back To Top](#index)
590+
473591
<a name="installation"/>
474592

475593
### Installation
476594

477-
`ScrollStackContainer` can be installed with CocoaPods by adding pod 'ScrollStackContainer' to your Podfile.
595+
`ScrollStackController` can be installed with CocoaPods by adding pod 'ScrollStackController' to your Podfile.
478596

479597
```ruby
480-
pod 'ScrollStackContainer'
598+
pod 'ScrollStackController'
481599
```
482600

483601
It also supports `Swift Package Maneger` aka SPM.
@@ -488,15 +606,18 @@ It also supports `Swift Package Maneger` aka SPM.
488606

489607
### Author & License
490608

491-
`ScrollStackContainer` is developed and maintained by:
609+
`ScrollStackController` is developed and maintained by:
492610

493611
- Daniele Margutti ([danielemargutti.com](http://www.danielemargutti.com) - [@danielemargutti](http://www.twitter.com/danielemargutti) on twitter)
494612

495613
I fully welcome contributions, new features, feature requests, bug reports, and fixes. Also PR are accepted!
496614

497-
`ScrollStackContainer` is released under the MIT License.
615+
`ScrollStackController` is released under the MIT License.
616+
617+
The following library was originally inspired by two great works:
498618

499-
It was originally inspired by [`AloeStackView`](https://github.com/airbnb/AloeStackView) by Airbnb.
619+
- [`AloeStackView`](https://github.com/airbnb/AloeStackView) by the engineering team at AirBnb
620+
- [`ScrollingStackViewController`](https://github.com/justeat/ScrollingStackViewController) by the engineering team at JustEat
500621

501622
[ Back To Top](#index)
502623

Resources/architecture.png

27.2 KB
Loading

ScrollStackControllerDemo/ViewController.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class ViewController: UIViewController {
1515
private var stackController = ScrollStackViewController()
1616

1717
public var stackView: ScrollStack {
18-
return stackController.stackView
18+
return stackController.scrollStack
1919
}
2020

2121

@@ -83,7 +83,7 @@ class ViewController: UIViewController {
8383
extension ViewController: TagsVCProtocol {
8484

8585
func toggleTags() {
86-
let index = stackView.rowForController(tagsVC)!.index
86+
let index = stackView.gitrowForController(tagsVC)!.index
8787
tagsVC.isExpanded = !tagsVC.isExpanded
8888
stackView.reloadRow(index: index, animated: true)
8989
}

Sources/ScrollStackController/ScrollStackViewController.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ open class ScrollStackViewController: UIViewController {
3737
// MARK: Public Properties
3838

3939
/// Inner stack view control.
40-
public let stackView = ScrollStack()
40+
public let scrollStack = ScrollStack()
4141

4242
/// Displays the scroll indicators momentarily.
4343
open var automaticallyFlashScrollIndicators = false
@@ -55,9 +55,9 @@ open class ScrollStackViewController: UIViewController {
5555
// MARK: View Lifecycle
5656

5757
open override func loadView() {
58-
view = stackView
58+
view = scrollStack
5959
// monitor remove or add of a row to manage the view controller's hierarchy
60-
stackView.onChangeRow = { [weak self] (row, isRemoved) in
60+
scrollStack.onChangeRow = { [weak self] (row, isRemoved) in
6161
guard let `self` = self else {
6262
return
6363
}
@@ -69,7 +69,7 @@ open class ScrollStackViewController: UIViewController {
6969
super.viewDidAppear(animated)
7070

7171
if automaticallyFlashScrollIndicators {
72-
stackView.flashScrollIndicators()
72+
scrollStack.flashScrollIndicators()
7373
}
7474
}
7575

0 commit comments

Comments
 (0)