So I implemented a proper TableView
with a search functionality and sectionIndexTitles
. Now, I am trying to implement a UICollectionView
and it is working so far, except that I can't easily have sectionIndexTitles
(the right scroll bar).
If I look at the Facebook Application, it looks like a UICollectionView
, but with indeed sectionIndexTitles
and a searchbar. I can't seem to find such functions for the UICollectionView
model.
Any ideas?!
Thanks!
I had a similar requirement (for a horizontal collection view) and ended up building an index view subclass myself.
I plan to open-source it but that will likely have to wait until next month, so here's a stub to get you started:
YMCollectionIndexView.h
@interface YMCollectionIndexView : UIControl
- (id) initWithFrame:(CGRect)frame indexTitles:(NSArray *)indexTitles;
// Model
@property (strong, nonatomic) NSArray *indexTitles; // NSString
@property (readonly, nonatomic) NSUInteger currentIndex;
- (NSString *)currentIndexTitle;
@end
YMCollectionIndexView.m
#import "YMCollectionIndexView.h"
@interface YMCollectionIndexView ()
@property (readwrite, nonatomic) NSUInteger currentIndex;
@property (strong, nonatomic) NSArray *indexLabels;
@end
@implementation YMCollectionIndexView
- (id) initWithFrame:(CGRect)frame indexTitles:(NSArray *)indexTitles {
self = [super initWithFrame:frame];
if (self) {
self.indexTitles = indexTitles;
self.currentIndex = 0;
// add pan recognizer
}
return self;
}
- (void)setIndexTitles:(NSArray *)indexTitles {
if (_indexTitles == indexTitles) return;
_indexTitles = indexTitles;
[self.indexLabels makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self buildIndexLabels];
}
- (NSString *)currentIndexTitle {
return self.indexTitles[self.currentIndex];
}
#pragma mark - Subviews
- (void) buildIndexLabels {
CGFloat cumulativeItemWidth = 0.0; // or height in your (vertical) case
for (NSString *indexTitle in self.indexTitles) {
// build and add label
// add tap recognizer
}
self.indexLabels = indexLabels;
}
#pragma mark - Gestures
- (void) handleTap:(UITapGestureRecognizer*)recognizer {
NSString *indexTitle = ((UILabel *)recognizer.view).text;
self.currentIndex = [self.indexTitles indexOfObject:indexTitle];
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
}
// similarly for pan recognizer
@end
In your view controller:
- (void)viewDidLoad {
[super viewDidLoad];
[self.collectionIndexView addTarget:self action:@selector(indexWasTapped:) forControlEvents:UIControlEventTouchUpInside];
// similarly for pan recognizer
}
- (void)indexWasTapped:(id)sender {
[self.collectionView scrollToIndexPath:...];
}
// similarly for pan recognizer
Have you found any solution?
I'm trying to implement the same features for UICollectionView.
So far for the sectionIndexTitles I'm using custom UITableView with the same sections as the original UICollectionView, but with empty cells. As a result I have a IndexTableView class
indexTableView = [[IndexTableView alloc] initWithFrame:CGRectZero];
[self.view addSubview:indexTableView];
...
indexTableView.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 40, 0, 40, CGRectGetHeight(self.view.frame));
indexTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
indexTableView.sectionHeaderHeight = 0;
indexTableView.backgroundColor = [UIColor clearColor];
I add IndexTableView on top of the UICollectionView, and got the same visual effect as an original UITableView.
Now I'm trying to link index selection and UICollectionView and make it work.
EDITED:
I've just added a UISearchBar to the UICollectionController
add following code to the your subclass of the UICollectionController
- (void)viewDidLoad
{
[super viewDidLoad];
...
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.collectionView.frame.size.width, 44)];
self.searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.searchBar.delegate = self;
[self.collectionView addSubview:self.searchBar];
[self.collectionView setContentOffset:CGPointMake(44, 0)];
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
if (section == 0) {
return UIEdgeInsetsMake(CGRectGetHeight(self.searchBar.frame), 6, 0, 6);
}
return UIEdgeInsetsMake(0, 6, 0, 6);
}
You can now simply use (as of iOS 10.3)
optional func indexTitles(for collectionView: UICollectionView) -> [String]?
Which expects an array like:
['A', 'B' ,'C']
as its return value.
You can provide this header by implementing and returning a value for the following function for UICollectionViewDataSource
collectionView:viewForSupplementaryElementOfKind:atIndexPath:
Note that the size of the header will be from the height value of the CGRect returned from UICollectionViewFlowLayoutDelegate method collectionView:layout:referenceSizeForHeaderInSection: