By Xmartlabs SRL.
TokenRow is a row extension for Eureka. It includes a CLTokenInputView which allows the user to select, add and remove tokens.
TokenRow includes two rows with similar functionality but their options are displayed differently:
- TokenAccessoryRow: displays a collection view as the
inputAccessoryView
of the cell. The user will be able to scroll horizontally to select the desired token - TokenTableRow: displays a
UITableView
directly below the cell for the user to choose the desired option.
form +++ Section()
<<< TokenAccessoryRow<String>() {
$0.placeholder = "Choose from collection view"
$0.options = ["Peter Schmeichel", "David de Gea", "Oliver Kahn", "Fabien Barthez", "Tim Howard", "Gianluigi Buffon"]
}
+++ Section()
<<< TokenTableRow<String>() {
$0.placeholder = "Choose from table"
$0.options = ["Peter Schmeichel", "David de Gea", "Oliver Kahn", "Fabien Barthez", "Tim Howard", "Gianluigi Buffon"]
}
To see what you can customize have a look at the Customization section.
- Eureka 5.x
- CLTokenInputView which is a token view pod
- iOS 9.3+
- Xcode 10.2+
- If you want to contribute please feel free to submit pull requests.
- If you have a feature request please open an issue.
- If you found a bug or need help please check older issues before submitting an issue..
Before contributing check the CONTRIBUTING file for more info.
If you use TokenRow in your app we would love to hear about it! Drop us a line on twitter.
Follow these steps to run Example project:
- Clone TokenRow repository
- Run
pod install
in theTokenRow/Example
folder - Open Example workspace in that folder
CocoaPods is a dependency manager for Cocoa projects.
To install TokenRow, simply add the following line to your Podfile:
pod 'TokenRow'
The value of a token row (i.e. TokenAccessoryRow or TokenTableRow) must conform to the TokenSearchable protocol. This way you can have classes or structs as the values of this rows and not just Strings. The TokenSearchable protocol is defined as follows:
public protocol TokenSearchable: Hashable {
var displayString: String { get }
func contains(token: String) -> Bool
var identifier: NSObject { get }
}
And here is a brief explanation for each of them:
displayString
: Will be used to get the String to be displayed as token in the token viewcontains(token: String) -> Bool
is used to filter the options for a given search string.identifier
: Is an identifier for the token and should be unique among all options
Note that the value also has to conform to
Hashable
protocol which in turn requiresEquatable
TokenRow includes an extension on String
that makes it conform to TokenSearchable
so that you can use any row with String as value. To make a class conform to this protocol you could do something like the following:
final class User {
var id: Int = 0
var name: String = ""
var avatar: String?
// conform to Hashable
var hashValue: Int {
return id
}
}
// conform to Equatable
func == (lhs: User, rhs: User) -> Bool {
return lhs.id == rhs.id
}
extension User: TokenSearchable {
func contains(token: String) -> Bool {
return name.contains(token)
}
var identifier: NSObject {
return id
}
var displayString: String {
return name
}
}
Many things of this row are very similar to the SuggestionRow and the GooglePlacesRow. You might find useful examples in those projects as well.
There are several parts of the TokenRow that you can change. First of all, if you want to change the view that contains the tokens then you should have a look at CLTokenInputView.
A thing you must do for each of these rows is provide the options from which the user can choose a token. The conventional way is to specify an array of options to the options
variable of the row:
<< TokenAccessoryRow<String>() {
$0.options = ["Peter Schmeichel", "David de Gea", "Oliver Kahn", "Fabien Barthez", "Tim Howard", "Gianluigi Buffon"]
}
But you could also provide the options overriding getTokensForString
. For example you could get the tokens asynchronously over a network call and reload the options after the response comes in.
For example:
row.getTokensForString = { [weak self, row] string in
guard let me = self else { return nil }
Alamofire.SessionManager.default.request("https://api.github.com/search/users?q=\(text)&per_page=5")
.responseCollection(completionHandler: { (response: DataResponse<[User]>) in
switch response.result {
case let .success(value):
row.cell.filteredTokens = value
row.cell.reloadOptions()
case let .failure(error):
print(error)
}
})
return []
}
It is as simple as that (at least if you are familiar with Alamofire). You can see a working example of this in the Examples project.
TokenAccessoryRow uses a generic TokenCollectionCell
cell whose generic parameter is the UICollectionViewCell class used in the inputAccessoryView.
-
If you just want to change minor things of the collection view cells (you most probably will want to) then the
customizeCollectionViewCell
callback is for you. This block is called in the delegate'scollectionView:cellForItemAtIndexPath:
method. -
If you want to change the layout of the collectionView then you can use/modify/override the
collectionViewLayout
attribute in thecellSetup
method when declaring the row. Have a look at the examples for this. -
If you want to change something about the collectionView (e.g. its height, backgroundColor) then you can also do that in the
cellSetup
method. Just edit anything on thecollectionView
variable of your cell. -
If you want to change the collection view cell of the inputAccessoryView drastically then there is nothing easier than creating your own row (
CustomAccessoryRow
) with your ownMyCollectionViewCell
:
final class CustomAccessoryRow<T: TokenSearchable>: _TokenRow<T, CollectionTokenCell<T, MyCollectionViewCell<T>>>, RowType {
required init(tag: String?) {
super.init(tag: tag)
}
}
Note: Your custom
MyCollectionViewCell
has to conform toEurekaTokenCollectionViewCell
TokenTableRow uses a generic TokenTableCell
cell whose generic parameter is the UITableViewCell class used to create the cells displayed in a UITableView with the suggested options.
-
If you just want to change minor things of the cells that display the options then you can use the
customizeTableViewCell
callback on the cell. You should define it in thecellSetup
method. This callback will be called in the correspondingtableView:cellForRowAtIndexPath:
method. -
You can customize attributes of the
tableView
that is displayed with the options. You should do this incellSetup
and keep in mind that the frame of the tableView is reset each time the tableView is displayed. -
If you want to change the cells of the options table view then there is nothing easier than creating your own row (
MyTokenTableRow
) with your ownMyTableViewCell
:
final class MyTokenTableRow<T: TokenSearchable>: _TokenRow<T, TableTokenCell<T, MyTableViewCell<T>>>, RowType {
required public init(tag: String?) {
super.init(tag: tag)
}
}
You could also change TableTokenCell
for any class you want to represent the TokenRow cell.
Note: Make sure your cell conforms to
EurekaTokenTableViewCell
This can be found in the CHANGELOG.md file.