Giphy
Setup
- Clone or download the repository.
- Run
pod install
inside the directory. - Define your Giphy API key at the top of
GIFModel.m
.
#define GIPHY_API_KEY @"{YOUR KEY HERE}"
Features
-
GIFs are interactive. Tapping a GIF will bring up a UIActivityViewController, where it can be saved, shared, etc.
-
Shows a single page of 100 results. This is specified by
kPageSize
inGIFModel.m
. Haven't implemented paging yet. -
The collection view layout is based on the size of the screen and its orientation. Images scale to width of the screen with the correct aspect ratio. The app shows a single GIF per row in portrait, and switches to two columns in landscape. The key layout code is in
sizeForItemAtIndexPath
. I've implementedviewWillTransitionToSize
to handle rotation events.
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
GIFModel *model = [self.images objectAtIndex:indexPath.item];
CGFloat width = 0.0;
// Use two columns if the device is in landscape
if (UIDeviceOrientationIsLandscape(UIDevice.currentDevice.orientation)) {
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)collectionViewLayout;
width = CGRectGetWidth(collectionView.frame) / 2.0 - layout.minimumInteritemSpacing;
} else {
width = CGRectGetWidth(collectionView.frame);
}
// Set the height of the item based on the image's aspect ratio
CGFloat height = width / (model.imageSize.width / model.imageSize.height);
return CGSizeMake(width, height);
}
-
Scrolling through collection view/GIFs should be smooth. I can't say this is always 60 FPS (that'd require a bit more work getting as much stuff off the main thread as possible), but things are pretty smooth. I've used PINRemoteImage to handle GIFs, which is what's used at Pinterest. PINRemoteImage decodes images off the main thread so that animation performance isn't affected. It also caches images for quick reuse later. I've kept the cache sizes at their defaults, but these could be tweaked to improve performance.
-
GIFs appear as they load, and offscreen GIFs are unloaded. When
cellForItemAtIndexPath
sets thegif
property on the cell, we either download the image or retrieve it from the cache insetGif:
inGIFCollectionViewCell.m
. Images are set to nil inprepareForReuse
, which unloads the images as cells are recycled. With more time, I could extend this to use theUICollectionViewDataSourcePrefetching
protocol, and begin fetching images for cells that are about to appear.
- (void)prepareForReuse
{
[super prepareForReuse];
self.imageView.image = nil;
}
- Search results are updated when the user taps search button. I've also implemented automatic searching as the user types, which is debounced to every 1.5 seconds.
- (void)textFieldDidChange:(UITextField *)textField
{
// Search when the text field changes. Debounce 1.5 seconds to prevent several searches.
__weak typeof(self) weakSelf = self;
[NSObject cancelPreviousPerformRequestsWithTarget:weakSelf selector:@selector(fetchImages:) object:nil];
[weakSelf performSelector:@selector(fetchImages:) withObject:textField.text afterDelay:1.5];
}
- The app layout supports any iOS device, including iPad, in landscape or portrait. I've implemented a couple of NSLayoutConstaints programmatically in
ViewController.m
.
[self.collectionView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
[self.collectionView.topAnchor constraintEqualToAnchor:self.textField.bottomAnchor].active = YES;[self.collectionView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor constant:kCollectionViewLeftRightPadding].active = YES;
[self.collectionView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor constant: -kCollectionViewLeftRightPadding].active = YES;