Compose is a data driven library that will help compose your complex and dynamic Views.
We built Compose so we could easy manage and A/B test our complex views.
That instead of dealing with many dataSources and delegates methods, we could focus on delivering shine and new components. Instead of switching indexPaths
we could change each component position as we wished.
The protocol ComposingUnit is at the center of this library. Any class or struct can conform to it, and it has few properties and methods that needs to be implemented. It should store all data that will be presented by this unit.
A unit also is responsible for selecting which UIView will render it's data, and once an UIView is dequeued from a container, it is also the unit job to bind that data to the view.
A ComposingContainer is an UIView that knows how do display an array of ComposingUnit
s. We provide two containers in the framework: ComposingCollectionView
and ComposingTableView
. Both have automatic detection of inserts/updates/deletes of ComposingUnits they are displaying.
So, for you to get an example, after creating some units we could easly compose our view like this:
units.add {
let topSeparator = LoginUnits.SpacerUnit(id: "top", height: 14)
let header = LoginUnits.HeaderUnit()
return [topSeparator, header]
}
units.add {
let username = LoginUnits.UsernameUnit(current: viewState.username, callback: updateUsername(newUsername:))
let password = LoginUnits.PasswordUnit(current: viewState.password, callback: updatePassword(newPassword:))
return [username, password]
}
let continueButton = LoginUnits.ContinueButtonUnit(enabled: viewState.validData, callback: doTryLogin)
units.append(continueButton)
collectionView.state = units
Here, we can clearly see (and change if we want) the order each unit will be added to the array. Also, if any unit needed some business logic to check if it should be added to the array, we could easily do something like this:
units.add(manyIfLet: state.description) { text in
let header = DetailViewUnits.HeaderDescriptionUnit(header: "Description")
let description = DetailViewUnits.DescriptionUnit(text: text, expanded: state.descriptionExpanded)
return [header, description]
}
So, if state.description
is not nil, then we should display an header and description units. There are many operators for conditional checks, conditional closures, if/let unwrappers and more.
If you got interested, there are many working examples inside the Example project.
To run the example project, clone the repo, and open the xcode Project from the Example directory.
Compose is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod "Compose"
You can find all documentation about Compose here: Documentation
Bruno Bilescky, brunogb@gmail.com
Compose is available under the MIT license. See the LICENSE file for more info.