Powered By Blogger
Showing posts with label Objective-C. Show all posts
Showing posts with label Objective-C. Show all posts

Monday, March 10, 2014

UICollectionView with dynamic image height

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"
B. You can download these files from CHTCollectionViewWaterfallLayout .
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