-
Notifications
You must be signed in to change notification settings - Fork 26
/
AMBTableViewController.h
416 lines (321 loc) · 17 KB
/
AMBTableViewController.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
//
// AMBTableViewController.h
// AMBTableViewController
//
// Created by Ernesto Rivera on 2014/05/07.
// Copyright (c) 2014-2017 CyberAgent Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import <UIKit/UIKit.h>
@class AMBTableViewSection;
/**
A controller that manages a UITableView using AMBTableViewSection to be configured.
- Based on Storyboards and Prototype Cells.
- Modularizes section code.
- Uses blocks instead of delegate methods.
- Avoids having section code separated through multiple methods.
- Sections and individual rows can be hidden/shown, added/removed.
- Support for dynamic height cells.
*/
@interface AMBTableViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
/// @name Properties
/// The managed table view.
@property (weak, nonatomic) IBOutlet UITableView * tableView;
/// The presented sections.
@property (strong, nonatomic) NSArray * sections;
/// @name Managing Sections
/// Insert a section into the sections array.
/// @param section The section to be inserted.
/// @param index The index to insert the section at.
- (void)insertSection:(AMBTableViewSection *)section
atIndex:(NSUInteger)index;
/// Remove a section.
/// @param section The section to be removed.
- (void)removeSection:(AMBTableViewSection *)section;
/// Remove the section at a given index.
/// @param index The index of the section to be removed.
- (void)removeSectionAtIndex:(NSUInteger)index;
/// Replace a section for another one.
/// @param sectionToReplace The section to be replaced.
/// @param section The replacing section.
- (void)replaceSection:(AMBTableViewSection *)sectionToReplace
withSection:(AMBTableViewSection *)section;
/// Replace a section at a given index for another one.
/// @param index The index of the section to be replaced.
/// @param section The replacing section.
- (void)replaceSectionAtIndex:(NSUInteger)index
withSection:(AMBTableViewSection *)section;
/// @name Configuring Animations
/// Reload section/row animation. By default `UITableViewRowAnimationNone`.
@property (nonatomic) UITableViewRowAnimation reloadAnimation;
/// Insert section/row animation. By default `UITableViewRowAnimationAutomatic`.
@property (nonatomic) UITableViewRowAnimation insertAnimation;
/// Insert section/row animation. By default `UITableViewRowAnimationFade`.
@property (nonatomic) UITableViewRowAnimation removeAnimation;
/// Execute a block while temporarily overriding reload, insert and remove animations.
/// @param changes The block to be executed.
/// @param animation The animation to be used while executing the changes.
- (void)applyChanges:(void (^)(void))changes
withAnimation:(UITableViewRowAnimation)animation;
/// Execute a block while temporarily overriding reload, insert and remove animations.
/// @param changes The block to be executed.
/// @param reloadAnimation The animation to be used while reloading sections/rows.
/// @param insertAnimation The animation to be used while inserting sections/rows.
/// @param removeAnimation The animation to be used while removing sections/rows.
- (void)applyChanges:(void (^)(void))changes
withReloadAnimation:(UITableViewRowAnimation)reloadAnimation
insertAnimation:(UITableViewRowAnimation)insertAnimation
removeAnimation:(UITableViewRowAnimation)removeAnimation;
/// @name Convenience Methods
/// Trigger [AMBTableViewSection update] on all sections.
- (void)updateAllSections;
/// Combine several section and row changes between [UITableView beginUpdates] and
/// [UITableView endUpdates].
/// @param changes The changes to be combined.
- (void)combineChanges:(void (^)(void))changes;
/// Retrieve the index path of the row containing a given subview.
/// @param subview A subview of the row.
- (NSIndexPath *)indexPathForRowWithSubview:(UIView *)subview;
/// Calculate the required height for a AMBResizableCell.
/// @param identifier The identifier of the AMBResizableCell who's height will be calculated.
/// @param text The text that the view should fit.
/// @param numberOfLines The maximum number of lines to be allowed or `0` for no limits.
/// Only implemented for UILabel resizableView's.
/// @discussion A cell instance of the given identifier will be cached to calculate the heights
/// of all future calculations. The original height of the loaded cell will be used as the
/// minimum height to be returned by the function.
/// @note Currently only suport for UILabel and UITextView objects is implemented.
- (CGFloat)heightForResizableCellWithIdentifier:(NSString *)identifier
text:(NSString *)text
limitedToNumberOfLines:(NSInteger)numberOfLines;
@end
/// @name AMBTableViewSection Blocks
/// A block used to return the name of the section.
/// @param section The section that whose title to return.
/// @return String to be used for the title of the section
typedef NSString * (^AMBTableViewSectionTitleBlock)(AMBTableViewSection * section);
/// A block where any aspect of the section can be changed and rows can set to be shown/hidden,
/// reloaded, etc.
/// @param section The section to be updated.
typedef void (^AMBTableViewSectionUpdateBlock) (AMBTableViewSection * section);
/// Calculate the height of the cell corresponding to a given section object.
/// @param object The object who's corresponing cell needs to be calculated.
/// @param indexPath The index path of the corresponding cell.
/// @return The desired height. When there is no [AMBTableViewSection cellHeightBlock] or the
/// block returns a negative height the default [UITableView rowHeight] is used.
typedef CGFloat (^AMBTableViewCellHeightBlock) (id object,
NSIndexPath * indexPath);
/// The Prototype Cell identifier that should be loaded for a given object.
/// @param object The object who's corresponing cell needs to be calculated.
/// @param indexPath The index path of the corresponding cell.
/// @return A Prototype Cell identifier.
/// @discussion Depending on the kind of object this method may never be called.
/// @see [AMBTableViewSection objects].
typedef NSString * (^AMBTableViewCellIdentifierBlock) (id object,
NSIndexPath * indexPath);
/// A block used to configure a cell for a given object and index path.
/// @param object The object who's corresponing cell will be configured.
/// @param cell The cell to be configured.
/// @param indexPath The index path of the corresponding cell.
typedef void (^AMBTableViewCellConfigurationBlock)(id object,
UITableViewCell * cell,
NSIndexPath * indexPath);
/**
An object that groups blocks of code to manage rows in a table view section.
Sections use an abstract list of objects to be managed.
- An object corresponds to a cell when it is not set to hidden.
- A non-hidden object gets a cell loaded by a given identifier unless the object is
already a UITableViewCell.
- If the object is a AMBCellIdentifier then cellIdentifierBlock is skipped for that cell.
- When presentsNoContentCell is set to `YES` all blocks are called with a `nil` object.
- Hidding/showing/inserting/removing objects automatically updates the corresponding table cells.
A section can be set to hidden, in which case it ignores its objects and returns `0` as its numberOfRows.
*/
@interface AMBTableViewSection : NSObject
/// @name Creating Sections
/// Create and return a new section.
/// @param objects An abstract list of objects to be presented by the section.
/// @param sectionUpdateBlock An optinal block to be called on update on
/// [AMBTableViewController updateAllSections] calls.
/// @param cellHeightBlock An optional block to be called on [UITableView tableView:heightForRowAtIndexPath:].
/// @param cellIdentifierBlock The block to be called when a cell needs to be loaded.
/// @param cellConfigurationBlock An optional block to be called to configure a loaded or reused cell.
+ (instancetype)sectionWithObjects:(NSArray *)objects
sectionUpdateBlock:(AMBTableViewSectionUpdateBlock)sectionUpdateBlock
cellHeightBlock:(AMBTableViewCellHeightBlock)cellHeightBlock
cellIdentifierBlock:(AMBTableViewCellIdentifierBlock)cellIdentifierBlock
cellConfigurationBlock:(AMBTableViewCellConfigurationBlock)cellConfigurationBlock;
/// @name Properties
/// Whether the section should be hidden or not. Default `NO`.
/// @discussion When set to `YES` the numberOfRows returns `0`.
@property(nonatomic, getter=isHidden) BOOL hidden;
/// Whether the section should present a special "No Content" cell when objects is empty. Default `NO`.
/// @discussion When set to `YES` the numberOfRows returns `1` and cellHeightBlock, cellIdentifierBlock and
/// cellConfigurationBlock will all be called with an `nil` object.
@property(nonatomic) BOOL presentsNoContentCell;
/// The number of rows that the section returns to [UITableView tableView:numberOfRowsInSection:].
@property (nonatomic, readonly) NSUInteger numberOfRows;
/// The AMBTableViewController assigned when the section is added to [AMBTableViewController sections].
@property (weak, nonatomic) AMBTableViewController * controller;
/// An optional block to be called on [UITableView tableView:titleForHeaderInSection:].
@property (copy, nonatomic) AMBTableViewSectionTitleBlock sectionTitleBlock;
/// An optinal block to be called on update on [AMBTableViewController updateAllSections] calls.
@property (copy, nonatomic) AMBTableViewSectionUpdateBlock sectionUpdateBlock;
/// An optional block to be called on [UITableView tableView:heightForRowAtIndexPath:].
@property (copy, nonatomic) AMBTableViewCellHeightBlock cellHeightBlock;
/// The block to be called when a cell needs to be loaded.
@property (copy, nonatomic) AMBTableViewCellIdentifierBlock cellIdentifierBlock;
/// An optional block to be called to configure a loaded or reused cell.
@property (copy, nonatomic) AMBTableViewCellConfigurationBlock cellConfigurationBlock;
/// @name Managing Objects
/// The list of objects that the section handles.
@property (strong, nonatomic) NSArray * objects;
/// The list of non-hidden objects. That is objects that have a corresping cell.
@property (strong, nonatomic, readonly) NSArray * visibleObjects;
/// An index set of all the currently hidden objects.
@property (strong, nonatomic, readonly) NSIndexSet * hiddenObjectsIndexSet;
/// @name Adding and Removing Objects
/// Add an object to objects.
/// @param object The object to be added.
- (void)addObject:(id)object;
/// Add some new objects to appended to the section objects.
/// @param objects The objects to be added.
- (void)addObjects:(NSArray *)objects;
/// Insert an object at a given index.
/// @param object The object to be inserted.
/// @param index The index where the object should be inserted.
- (void)insertObject:(id)object
atIndex:(NSUInteger)index;
/// Insert new objects at some given indexes.
/// @param objects The object to be inserted.
/// @param indexSet The indexes where the objects should be inserted.
- (void)insertObjects:(NSArray *)objects
atIndexes:(NSIndexSet *)indexSet;
/// Remove an object.
/// @param object The object to be removed.
- (void)removeObject:(id)object;
/// Remove an object at a given index.
/// @param index The index of the object to be removed.
- (void)removeObjectAtIndex:(NSUInteger)index;
/// Remove several objects.
/// @param objects The objects to be removed.
- (void)removeObjects:(NSArray *)objects;
/// Remove several objects at the given indexes.
/// @param indexSet The indexes of the objects to be removed.
- (void)removeObjectsAtIndexes:(NSIndexSet *)indexSet;
/// @name Moving Objects
/// Move an object to a given index.
/// @param object The object to move.
/// @param index The index to move the object to.
- (void)moveObject:(id)object
toIndex:(NSUInteger)index;
/// Move an object from a given index to a new one.
/// @param oldIndex The original object index.
/// @param index The index to move the object to.
- (void)moveObjectAtIndex:(NSUInteger)oldIndex
toIndex:(NSUInteger)index;
/// @name Hiding and Showing Objects
/// Whether an object is hidden.
/// @param object The subject object.
- (BOOL)isObjectHidden:(id)object;
/// Whether an object at a given index is hidden.
/// @param index The subject object index.
- (BOOL)isObjectAtIndexHidden:(NSUInteger)index;
/// Hide/show an object corresponding cell.
/// @param object The object to be hidden/shown.
/// @param hidden Whether to show or hide the object.
- (void)setObject:(id)object
hidden:(BOOL)hidden;
/// Hide/show an object at a given index.
/// @param index The index f the object to be hidden/shown.
/// @param hidden Whether to show or hide the object.
- (void)setObjectAtIndex:(NSUInteger)index
hidden:(BOOL)hidden;
/// Hide/show several objects.
/// @param objects The objects to be hidden/shown.
/// @param hidden Whether to show or hide the objects.
- (void)setObjects:(NSArray *)objects
hidden:(BOOL)hidden;
/// Hide/show several objects at given indexes.
/// @param indexSet The indexes of the object to be hidden/shown.
/// @param hidden Whether to show or hide the objects.
- (void)setObjectsAtIndexes:(NSIndexSet *)indexSet
hidden:(BOOL)hidden;
/// @name Update and Reload the Section
/// Update the section by calling its sectionUpdateBlock.
- (void)update;
/// Force the table view to fully reload the section.
/// @note Prefer setting sectionUpdateBlock and calling update when possible.
- (void)reload;
/// @name Update and Reload Specific Objects
/// Reload a given object's cell.
/// @param object The object who's cell should be reloaded.
- (void)reloadObject:(id)object;
/// Reload an object at a given index.
/// @param index The index object to be reloaded.
- (void)reloadObjectAtIndex:(NSUInteger)index;
/// Reload several objects.
/// @param objects The objects to be reloaded.
- (void)reloadObjects:(NSArray *)objects;
/// Reload several objects at given indexes.
/// @param indexSet The indexes of the objects to be reloaded.
- (void)reloadObjectsAtIndexes:(NSIndexSet *)indexSet;
/// Convenience method to either show and reload, or hide an object
/// depending on the evaluation of a condition.
/// @param index The index object to be shown/hidden.
/// @param reloadWhenTrue A condition that determines what to do with the object.
- (void)reloadOrHideObjectAtIndex:(NSUInteger)index
when:(BOOL)reloadWhenTrue;
/// @name Scrolling to Objects
/// Scroll to a given object.
/// @param object The object to be scrolled to.
/// @param scrollPosition The position to be scrolled to.
/// @param animated Whether to animate the scrolling.
- (void)scrollToObject:(id)object
atScrollPosition:(UITableViewScrollPosition)scrollPosition
animated:(BOOL)animated;
/// Scroll to an object at a given index.
/// @param index The index of the object to be scrolled to.
/// @param scrollPosition The position to be scrolled to.
/// @param animated Whether to animate the scrolling.
- (void)scrollToObjectAtIndex:(NSUInteger)index
atScrollPosition:(UITableViewScrollPosition)scrollPosition
animated:(BOOL)animated;
@end
/**
An object that can be used to populate a [AMBTableViewSection objects] while
directly specifying the cell to be loaded.
Useful for cells that require little or no configuration besides being loaded.
*/
@interface AMBCellIdentifier : NSObject
/// Create and return a new object.
/// @param string An existing Prototype Cell identifier.
+ (instancetype)identifierFromString:(NSString *)string;
/// The Prototype Cell identifier to be loaded.
@property (strong, nonatomic) NSString * string;
@end
/**
A protocol that when implemented by a UITableViewCell enables using
[AMBTableViewController heightForResizableCellWithIdentifier:text:limitedToNumberOfLines:]
to easily calculate dynamic-sized cells.
@note Currently only suport for UILabel and UITextView objects is implemented.
*/
@protocol AMBResizableCell <NSObject>
/// The label that determines the required height of the cell.
/// @discussion The original cell height is saved and used as the minimum height
/// to be used for the cell.
/// @note The label should be set to use flexible height and automatically
/// grow/shrink when its parent cell adjusts its height.
@property (weak, nonatomic) IBOutlet UIView * resizableView;
@end