Skip to content

Commit 8cb00ec

Browse files
Update README.
1 parent f18395b commit 8cb00ec

File tree

1 file changed

+128
-1
lines changed

1 file changed

+128
-1
lines changed

README.md

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,128 @@
1-
# accordion-table
1+
# AccordionTable
2+
3+
A wrapper for a diffable data source which facilitates collapsible table view sections. You may want to disable floating headers (see [demo](https://github.com/nashysolutions/MeltingList) app).
4+
5+
<img src="https://user-images.githubusercontent.com/64097812/150280515-64bbcc1b-ba85-4c56-bd4a-0b77be008e8c.gif" width="300"/>
6+
7+
## Implementation
8+
9+
The following steps are for a typical table view implementation.
10+
11+
### Prepare a model
12+
13+
<details>
14+
<summary>Example</summary>
15+
16+
```swift
17+
struct Food: Hashable {
18+
let id: UUID
19+
let title: String
20+
let items: [Item] // rows
21+
}
22+
23+
struct Item: Hashable {
24+
let id: UUID
25+
let title: String
26+
}
27+
```
28+
</details>
29+
30+
### Prepare an instance of `AccordionTable`.
31+
32+
<details>
33+
<summary>Show me</summary>
34+
35+
```swift
36+
let tableDataSource = UITableViewDiffableDataSource<Food, Item>(
37+
tableView: tableView,
38+
cellProvider: cellProvider
39+
)
40+
41+
let diffableTableManager = AccordionTable<Food, Item>(
42+
dataSource: tableDataSource,
43+
headerProvider: headerProvider
44+
)
45+
```
46+
</details>
47+
48+
> The `AccordionTable` type also has an `enabledFeatures` parameter.
49+
50+
### Prepare a table view delegate.
51+
52+
<details>
53+
<summary>Show me</summary>
54+
55+
```swift
56+
class TypicalTableViewDelegate: NSObject, UITableViewDelegate {
57+
58+
let tableManager: AccordionTable<Food, Item>
59+
60+
init(_ tableManager: AccordionTable<Food, Item>) {
61+
self.tableManager = tableManager
62+
}
63+
64+
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
65+
tableManager.viewForHeader(in: tableView, at: section)
66+
}
67+
68+
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
69+
tableManager.selectRowIfNeeded(in: tableView, at: indexPath)
70+
}
71+
72+
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
73+
guard let isSelected = tableManager.toggleSelectedStateForRow(at: indexPath) else {
74+
return
75+
}
76+
if !isSelected {
77+
tableView.deselectRow(at: indexPath, animated: true)
78+
}
79+
}
80+
81+
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
82+
tableManager.saveDeselectedStateForRow(at: indexPath)
83+
}
84+
85+
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
86+
return 0 // your header height
87+
}
88+
}
89+
```
90+
</details>
91+
92+
### Map your data
93+
94+
```swift
95+
let data = [Food: [Item]]()
96+
```
97+
98+
## Usage
99+
100+
To reload the data, call the following on your instance of `AccordionTable`.
101+
102+
```swift
103+
func update(with data: [Food, [Item]], animated: true)
104+
```
105+
106+
> On initial load, pass `animated: false`.
107+
108+
To programmatically select a row.
109+
110+
```swift
111+
diffableTableManager.saveSelectedStateForRow(at: indexPath)
112+
tableView.selectRow(at: indexPath, animated: animated, scrollPosition: scrollPosition)
113+
```
114+
115+
To programmatically deselect a row.
116+
117+
```swift
118+
diffableTableManager.saveDeselectedStateForRow(at: indexPath)
119+
tableView.deselectRow(at: indexPath, animated: animated)
120+
```
121+
122+
## Side Note
123+
124+
Consider avoiding any user interface state management in your model structures (and hashable implementation), such as `isHighlighted`, as this will be destroyed per snapshot (use a backing store instead, such as a `Set` or `key/value` collection - see [demo](https://github.com/nashysolutions/MeltingList) app).
125+
126+
If your user interface is reloading more rows/sections than it should, it is likely the hashable implementation to blame. It seems each row must be unique within the entire dataset (not just within the section it belongs). Use GUID's on your dataset to achieve this. Alternatively, at the row level, make a reference to the section in which that row belongs (be careful of retain cycle when using classes) and use that in the hashable implementation of the row.
127+
128+
> If you need to use `reloadItems(_ identifiers: [ItemIdentifierType])` then you will need to use class's for your model.

0 commit comments

Comments
 (0)