Hi,
Dear readers,
I had successfully used UICollectionView with dynamic heights of images which fetches data from NSURL string. iOS 6.0 and later versions can use "UICollectionView" to make a model like "Water Flow" or "Pinterest Layout".
Please see below steps to have it in your application.
=======================================================================
*** STEP 1 :
A. Include these two files into your project source directory.
1.) " CHTCollectionViewWaterfallLayout.h"
2.) " CHTCollectionViewWaterfallLayout.m"
C. Import
"ImageIO.framework" into project.
=======================================================================
*** STEP 2:
A) Generate two class files “CategoryCell.h” and “CategoryCell.m” for UICollectionViewCell.
#import "FXImageView.h"
@interface CategoryCell : UICollectionViewCell
@property (nonatomic, strong) UIButton *btnPhoto;
@property (nonatomic, strong) FXImageView *photoView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIView *bottomView;
#import "CategoryCell.h"
const CGFloat kTMPhotoQuiltViewMargin = 5;
@implementation CategoryCell
@synthesize photoView = _photoView;
@synthesize titleLabel = _titleLabel;
@synthesize btnPhoto = _btnPhoto;
@synthesize bottomView = _bottomView;
#pragma mark - Accessors
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, self.contentView.bounds.size.width, 30.0)];
_titleLabel.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
_titleLabel.backgroundColor = [UIColor clearColor];
_titleLabel.textColor = WHITE_COLOR;
if (IS_IPAD) {
_titleLabel.font = FONT_BOLD(14.0);
}
else
{
_titleLabel.font = FONT_BOLD(12.0);
}
_titleLabel.textAlignment = NSTextAlignmentCenter;
}
return _titleLabel;
}
- (UIView *)bottomView {
if (!_bottomView) {
_bottomView = [[UIView alloc] initWithFrame:CGRectMake(0.0, self.contentView.bounds.size.height - 30.0, self.contentView.bounds.size.width, 30.0)];
_bottomView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
_bottomView.backgroundColor = BLACK_COLOR;
_bottomView.alpha = 0.6;
}
return _bottomView;
}
- (FXImageView *)photoView {
if (!_photoView) {
_photoView = [[FXImageView alloc] initWithFrame:self.contentView.bounds];
_photoView.asynchronous = YES;
_photoView.contentMode = UIViewContentModeScaleAspectFit;
_photoView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_photoView.backgroundColor = CLEAR_COLOR;
_photoView.layer.shadowOpacity = 2.0;
_photoView.layer.shadowColor = LIGHT_GRAY_COLOR.CGColor;
_photoView.layer.shadowRadius = 2.0;
_photoView.layer.shadowOffset = CGSizeMake(-0.5, 0.5);
}
return _photoView;
}
- (UIButton *)btnPhoto{
if (!_btnPhoto) {
_btnPhoto = [UIButton buttonWithType:UIButtonTypeCustom];
_btnPhoto.frame = self.contentView.bounds;
_btnPhoto.contentMode = UIViewContentModeScaleAspectFill;
_btnPhoto.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_btnPhoto.backgroundColor = CLEAR_COLOR;
_btnPhoto.layer.shadowOpacity = 5.0;
_btnPhoto.layer.shadowColor = LIGHT_GRAY_COLOR.CGColor;
_btnPhoto.layer.shadowRadius = 5.0;
_btnPhoto.layer.shadowOffset = CGSizeMake(-1.0, 1.0);
}
return _btnPhoto;
}
#pragma mark - Life Cycle
#if !__has_feature(objc_arc)
- (void)dealloc {
[_photoView removeFromSuperview];
_photoView = nil;
[_titleLabel removeFromSuperview];
_titleLabel = nil;
[super dealloc];
}
#endif
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self.contentView addSubview:self.photoView];
[self.contentView addSubview:self.btnPhoto];
[self.bottomView addSubview:self.titleLabel];
[self.contentView addSubview:self.bottomView];
}
return self;
}
@end
========================================================================
*** STEP 3:
#import <ImageIO/ImageIO.h>
#import "CHTCollectionViewWaterfallLayout.h"
#define CELL_WIDTH 150.0
#define CELL_IDENTIFIER @"GCCategoryCell"
#import "CategoryCell.h"
@interface CategoryViewController () <UICollectionViewDataSource, CHTCollectionViewDelegateWaterfallLayout>
{
NSMutableArray *cellHeights;
NSMutableArray *arrCategory;
UICollectionView *collectionView;
CGFloat cellWidth;
}
@property (nonatomic, strong) NSMutableArray *cellHeights;
@property (nonatomic, strong) NSMutableArray * arrCategory;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic) CGFloat cellWidth;
@implementation CategoryViewController
@synthesize cellHeights;
@synthesize arrCategory;
@synthesize collectionView;
@synthesize cellWidth;
- (void)viewDidLoad
{
self.arrCategory = [[NSMutableArray alloc] init];
self.cellWidth = CELL_WIDTH; // Default if not setting runtime attribute
CHTCollectionViewWaterfallLayout *layout = [[CHTCollectionViewWaterfallLayout alloc] init];
layout.sectionInset = UIEdgeInsetsMake(0.0, 10, 10, 5.0);
layout.headerHeight = 0;
layout.footerHeight = 0;
if (IS_IPAD) {
layout.minimumColumnSpacing = 30;
layout.minimumInteritemSpacing = 30;
}
else
{
layout.minimumColumnSpacing = 5;
layout.minimumInteritemSpacing = 5;
}
CGRect frame;
if (IS_IPAD) {
frame = CGRectMake(0, lblTitle.frame.size.height, self.view.frame.size.width, self.view.frame.size.height-36.0);
}
else
{
frame = CGRectMake(0, lblTitle.frame.size.height, self.view.frame.size.width, self.view.frame.size.height-(Appdel.objTab.frame.size.height + 36.0));
}
self.collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout];
self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
self.collectionView.backgroundColor = [UIColor clearColor];
[self.collectionView registerClass:[GCCategoryCell class] forCellWithReuseIdentifier:CELL_IDENTIFIER];
[self.view addSubview:self.collectionView];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self updateLayoutForOrientation:[UIApplication sharedApplication].statusBarOrientation];
}
#pragma mark --------------------------
#pragma mark Accessors
#pragma mark --------------------------
- (NSMutableArray *)cellHeights
{
if (!cellHeights)
{
cellHeights = [[NSMutableArray alloc] init];
}
return cellHeights;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation
duration:duration];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
[self updateLayoutForOrientation:toInterfaceOrientation];
}
}
- (void)updateLayoutForOrientation:(UIInterfaceOrientation)orientation
{
CHTCollectionViewWaterfallLayout *layout = (CHTCollectionViewWaterfallLayout *)self.collectionView.collectionViewLayout;
layout.columnCount = UIInterfaceOrientationIsPortrait(orientation) ? 2 : 3;
}
========================================================================
*** STEP 4:
// Call this method first to fill height array after you objects list
-(void)fillHeightArray
{
for (NSMutableDictionary *dictGCCatInfo in self.arrCategory)
{
NSNumber *width = [NSNumber numberWithFloat:200];
NSNumber *height = [NSNumber numberWithFloat:200];
NSString *urlString = [dictGCCatInfo valueForKey:@"Photo"];
NSURL *imageFileURL = [NSURL URLWithString:urlString];
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((__bridge CFURLRef)imageFileURL, NULL);
if (imageSource) {
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:NO], (NSString *)kCGImageSourceShouldCache, nil];
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (__bridge CFDictionaryRef)options);
if (imageProperties) {
width = (NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);
height = (NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);
CFRelease(imageProperties);
}
}
CFRelease(imageSource); // Added
CGSize size = CGSizeMake([width floatValue], [height floatValue]);
[self.cellHeights addObject:[NSValue valueWithCGSize:size]];
}
[self.collectionView reloadData];
}
#pragma mark -----------------------------
#pragma mark UICollectionViewDataSource
#pragma mark -----------------------------
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [arrCategory count];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView1 cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CategoryCell *cell = (CategoryCell *)[collectionView1 dequeueReusableCellWithReuseIdentifier:CELL_IDENTIFIER
forIndexPath:indexPath];
NSString *urlString = [[arrCategory objectAtIndex:indexPath.row] valueForKey:@"Photo"];
if (urlString)
{
[cell.photoView setProcessedImage:nil];
//set image
[cell.photoView setImageWithContentsOfURL:[NSURL URLWithString:urlString]];
}
else
{
[cell.photoView setImage:[UIImage imageNamed:@"no-image.png"]];
}
[cell.photoView setTag:indexPath.row];
[cell.btnPhoto setTag:indexPath.row];
cell.titleLabel.text = [[arrCategory objectAtIndex:indexPath.row] valueForKey:@"GiftCertificateCatName"];
[cell.btnPhoto addTarget:self action:@selector(btnCategoryClicked:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
#pragma mark ------------------------------------
#pragma mark CHTCollectionViewDelegateWaterfallLayout
#pragma mark ------------------------------------
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize size = [[self.cellHeights objectAtIndex:indexPath.row] CGSizeValue];
return size;
}
Hope, you will fully enjoy this post about UICollectionView.
Best Regards,
Nilesh M. Prajapati