I need to be able to load images properly in both the landscape and portrait mode and for all devices.
Also I need a proper memory management while loading the images. right now my code loads all the images at once but in future I will add more images so need an optimized memory solution.
- (void)viewDidLoad {
[super viewDidLoad];
self.automaticallyAdjustsScrollViewInsets = NO;
self.navigationController.navigationBarHidden = YES;
_photoArray = [NSArray arrayWithObjects:#"image1.jpg",#"image2.jpg",#"image3.jpg",#"image4.jpg",#"image5.jpg",#"image6.jpg",#"image7.jpg",#"image8.jpg",#"image9.jpg", nil];
self.pageControl.numberOfPages = _photoArray.count;
CGSize screen = [[UIScreen mainScreen] bounds].size;
for(int i = 0; i < _photoArray.count; i++)
{
self.subScrollView = [[UIScrollView alloc] init];
self.subScrollView.frame = CGRectMake((i * screen.width), 0, screen.width, screen.height);
[self.subScrollView setMinimumZoomScale:1];
[self.subScrollView setZoomScale:1];
[self.subScrollView setMaximumZoomScale:3];
self.subScrollView.delegate = self;
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:_photoArray[i]]];
imgView.frame = self.subScrollView.bounds;
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.clipsToBounds = YES;
imgView.tag = i;
[self.subScrollView addSubview:imgView];
[_scrView addSubview:self.subScrollView];
if(i == _photoArray.count-1)
_scrView.contentSize = CGSizeMake(self.subScrollView.frame.origin.x + self.subScrollView.frame.size.width, screen.height);
}
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return [scrollView viewWithTag:self.pageControl.currentPage];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//page control
CGFloat pageWidth = self.scrView.frame.size.width;
self.pageControl.currentPage = (self.scrView.contentOffset.x +pageWidth/2)/pageWidth;
}
I think that the best option to optimize the memory is use a UICollectionView instead UIScrollView. Also you can use UIPageControl with UICollectionView.
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.imagesArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell == [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:#"image%d.jpg",indexPath.row]]];
[cell.addSubView:image];
return cell;
}
Related
I am build a media edit project that allow user do edit with several media.To meet this need,I push a UICollectionView in a UICollectionViewCell.
The inner UICollectionView load a movie's thumb images.
sample code:
- (void)setupUI
{
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.minimumInteritemSpacing = 0;
flowLayout.minimumLineSpacing = 0;
// flowLayout.itemSize = CGSizeMake(100, 200);
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
self.collectionView = collectionView;
collectionView.backgroundColor = [UIColor clearColor];
[self addSubview:collectionView];
collectionView.showsHorizontalScrollIndicator = NO;
collectionView.scrollEnabled = NO;
collectionView.userInteractionEnabled = NO;
// [collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.edges.equalTo(self);
// }];
collectionView.delegate = self;
collectionView.dataSource = self;
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cell"];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
PLog(#"count - %ld",self.videoItem.thumbnails.count);
return self.thumbImages.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
PLog(#"kkkkkkkkkkk,cell item %ld,cell address %#",indexPath.item,cell);
UIImage *image = self.thumbImages[indexPath.item];
if ([image isKindOfClass:[NSNull class]]) {
image = [UIImage imageWithColor:[UIColor blackColor]];
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[cell addSubview:imageView];
// imageView.userInteractionEnabled = YES;
[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(cell);
}];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(_videoItem.thumbWidth, CollectionHeight);
}
The outer UICollectionView data source from several different movie, custom UICollectionViewLayout
sample code:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = nil;
PDVideoItemCollectionViewCell *videoCell = [_collectionView dequeueReusableCellWithReuseIdentifier:#"reuse" forIndexPath:indexPath];
PLog(#"indexrow - %ld",indexPath.item);
if (videoCell.collectionView == nil) {
[videoCell setupUI];
}
videoCell.videoItem = [self.timelineItems objectAtIndex:indexPath.item];
videoCell.videoItem.videoCell = videoCell;
[videoCell reloadCollectionData];
PLog(#"cellll - %#",videoCell);
cell = videoCell;
cell.backgroundColor = MainBackgroundColor;
return cell;
}
Debug console log:
[PDVideoItem.m:172] image - <UIImage: 0x1268a3780>, {280, 158}--46
[PDVideoItem.m:172] image - <UIImage: 0x12689b800>, {280, 158}--47
[PDVideoItem.m:172] image - <UIImage: 0x12690a000>, {280, 158}--48
[PDVideoItem.m:172] image - <UIImage: 0x126821b60>, {280, 158}--49
[PDVideoItem.m:172] image - <UIImage: 0x1268a43d0>, {280, 158}--50
[PDVideoItem.m:184] done
[PDVideoItemCollectionViewCell.m:144] count - 51
[PDVideoItemCollectionViewCell.m:151] kkkkkkkkkkk,cell item 0,cell address <UICollectionViewCell: 0x12692de30; frame = (0 0; 112.5 63.2812); layer = <CALayer: 0x12691ff80>>
[PDVideoItemCollectionViewCell.m:151] kkkkkkkkkkk,cell item 1,cell address <UICollectionViewCell: 0x126930930; frame = (112.5 0; 112.5 63.2812); layer = <CALayer: 0x12692f310>>
[PDVideoItemCollectionViewCell.m:151] kkkkkkkkkkk,cell item 2,cell address <UICollectionViewCell: 0x1263aab60; frame = (225 0; 112.5 63.2812); layer = <CALayer: 0x12688f230>>
[PDVideoItemCollectionViewCell.m:151] kkkkkkkkkkk,cell
enter image description here
Situation description:2 movie = 2 outer UIcollectionViewCell = 2 inner UIcollectionView,total 82 thumbs = 82 inner UIcollectionViewCell
kkkkkkkkkkk log in collectionView: cellForItemAtIndexPath: method,count 25
Now get the problem that the inner UIcollectionViewCell seems do not ReUse,the memory will keep increase and UI load will be slow when I use UIPinchGestureRecognizer to do timeline scale.And the inner UICollectionView's delegate method collectionView: cellForItemAtIndexPath: never invoke when I do scroll action
Uh,Actually I think the main problem is I have generated all movies thumbs at first time,but because of inner collectionViewCell do not reuse,I couldn't generate thumb according to Item Indexpath.
This project refer to Apple's application iMovie a lot,maybe the applicate situation I describe is not clear,just download iMovie
Hope your good idea.
First you have a memory issue for the inner UICollectionView which that you add the UIImageView subview even if it's already added to the view's hierarchy here:
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[cell addSubview:imageView];
So you have to replace it with the following:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
PLog(#"kkkkkkkkkkk,cell item %ld,cell address %#",indexPath.item,cell);
UIImage *image = self.thumbImages[indexPath.item];
if ([image isKindOfClass:[NSNull class]]) {
image = [UIImage imageWithColor:[UIColor blackColor]];
}
UIImageView *imageView;
if ([cell viewWithTag: ImageView_TAG]) {
imageView = [[UIImageView alloc] initWithImage:image];
imageView.tag = ImageView_TAG
[cell addSubview:imageView];
} else {
imageView = [cell viewWithTag: ImageView_TAG]
imageView.image = image
}
// imageView.userInteractionEnabled = YES;
[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(cell);
}];
return cell;
}
Then for outer UICollectionView, you have to assign the collection view to the videoCell in collectionView:cellForItemAtIndexPath like:
videoCell.collectioView = collectioView
This will save your memory and avoid the increasing of the memory by effective usage of reusing cells
Good Luck :)
CollectionView horizontal scroll not working in ios 7 but it's working fine in ios 8 and 9. Is there any solution for this ?
The Code is here:
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.itemSize = CGSizeMake(330, 100);
collection = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0, 50.0, 350, 100) collectionViewLayout:layout];
collection.delegate = self;
collection.dataSource = self;
collection.backgroundColor = [UIColor greenColor];
collection.pagingEnabled = YES;
[collection registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.view addSubview:collection];
It now fits my needs, and could be useful for someone else, so here is my code:
I have tested In iOS7-8-9. Below example is for Default iPad. You Just need to change target settings and O.S Version.
https://github.com/philippeauriach/fullyhorizontalcollectionview
Please download it & let us know ur comments. Happy Coding!
If you want to add collection view onto the View then use below code. Below code into i have created CL View programmatically and It's also working correctly with Autolayout and iOS 7-8-9. Please implement below code and let us know ur comments.
.H File
#interface HorizontalCollectionViewController : UIViewController<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>{
NSIndexPath *visibleIndexPath;
}
#property (nonatomic, assign) NSInteger selectedCell;
#property (strong, nonatomic) IBOutlet UICollectionView *horizonCLView;
.M File
#import "HorizontalCollectionViewController.h"
static NSString * const CellIdentifier = #“horizonCell";
#interface HorizontalCollectionViewController ()
#end
#implementation HorizontalCollectionViewController
#synthesize horizonCLView;
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"view frame : %#",NSStringFromCGRect(self.view.frame));
[self.view layoutIfNeeded];
[self.view setNeedsLayout];
[self viewDidLayoutSubviews];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.itemSize = self.view.frame.size;
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[layout setMinimumInteritemSpacing:0.f];
[layout setMinimumLineSpacing:0.f];
layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
horizonCLView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
horizonCLView.dataSource = self;
horizonCLView.delegate = self;
horizonCLView.backgroundColor = [UIColor lightGrayColor];
horizonCLView.scrollEnabled = YES;
[horizonCLView setBounces:NO];
[horizonCLView setUserInteractionEnabled:YES];
[horizonCLView setPagingEnabled:YES];
[horizonCLView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CellIdentifier];
[self.view addSubview:horizonCLView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)viewWillAppear:(BOOL)animated{
//Select Current Image For Sare In Social Media
// currentImageIndex = selectedCell;
[horizonCLView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:selectedCell inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
CGRect visibleRect = (CGRect){.origin = self.horizonCLView.contentOffset, .size = self.horizonCLView.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
visibleIndexPath = [self.horizonCLView indexPathForItemAtPoint:visiblePoint];
// NSLog(#"visibleIndexPath.row in View will appear %ld",(long)visibleIndexPath.row);
//SelectedCell is a selected image from gallary view
NSLog(#"selectedCell in View will appear: %ld",(long)selectedCell);
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [dataAry count];
}
#pragma Here we set the frame of horizontal scrll view
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
// expand cell to fill the entire view
return collectionView.frame.size;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
self.title = [[self.dataAry objectAtIndex:indexPath.row] valueForKey:#“dataAryName"];
//imageVI.image = nil;
imageVI = (UIImageView *)[cell.contentView viewWithTag:100];
if (!imageVI){
imageVI = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height)];
imageVI.contentMode = UIViewContentModeScaleAspectFill;
imageVI.tag = 100;
imageVI.clipsToBounds = YES;
[cell.contentView addSubview:imageVI];
}
dispatch_async(dispatch_get_main_queue(), ^{
[asSetLib assetForURL:[NSURL URLWithString:[[self.dataAry objectAtIndex:indexPath.row] valueForKey:#"dataAryName"]] resultBlock:^(ALAsset *asset) {
// imageVI.image = [UIImage imageWithCGImage:asset.defaultRepresentation.fullScreenImage];
imageVI.image = [UIImage imageWithCGImage:asset.defaultRepresentation.fullResolutionImage];
NSLog(#"Preview view into album loaded successfully!");
} failureBlock:^(NSError *error) {
NSLog(#"An error occurred while loading image: %#", error.description);
}];
});
return cell;
}
Sudha, I think this issues in your code not an iOS7 issues.
Here, I have review two bug in ur code.
1)In this line you have give static width of collection view,
collection = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0, 50.0, 350, 100) collectionViewLayout:layout];
Instead Of it will be goes look like,
collection = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0, 50.0, self.view.bounds.size.width, 100) collectionViewLayout:layout];
Make sure your collection view width size always go with according to your view size.
2)Make sure, Your layout item size width higher then collection view width frame. Otherwise Scrolling was not effected.
layout.itemSize = CGSizeMake(self.view.bounds.size.width+10, 100);
3) Carefully use,
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
delegate method of collectionview layout size method.
4)Finally your code look like,
- (void)viewDidLoad {
[super viewDidLoad];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(self.view.bounds.size.width+10, 100);
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
collection = [[UICollectionView alloc] initWithFrame:CGRectMake(0.0, 50.0, self.view.bounds.size.width, 100) collectionViewLayout:layout];
collection.delegate = self;
collection.dataSource = self;
collection.backgroundColor = [UIColor greenColor];
collection.pagingEnabled = YES;
collection.scrollEnabled = YES;
collection.userInteractionEnabled = YES;
[collection registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.view addSubview:collection];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 1;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
return cell;
}
Happy Coding!
I've used a line of code after adding collectionView on view that its working fine in ios 7 also.
add this code after [self addSubview:self.collectionView];
here the code:
[self performSelector:#selector(update) withObject:nil afterDelay:1];
(void)update {
[self.collectionView setContentOffset:CGPointMake(1, 0)];
}
I created a UIView with a UICollectionView, and that UIView is added on a UIViewController. UIViewController using the delegate (photoDidTapped) of that UIView to determine is something was clicked/tapped. First row, is okay, means whole cell area is tappable. Second row, horizontal half of that is clickable. 3rd row, almost 10% horizontal of the cell is clickable and so on.
Code:
- (UICollectionView *)collectionView
{
if (!_collectionView) {
UICollectionViewFlowLayout *flowLayout=[[UICollectionViewFlowLayout alloc] init];
flowLayout.itemSize = CGSizeMake(THUMB_DIMENSION, THUMB_DIMENSION);
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:PHOTO_MARGIN];
_collectionView = [[UICollectionView alloc] initWithFrame:self.frame collectionViewLayout:flowLayout];
_collectionView.frame = CGRectMake(0, 0, SCREEN_WIDTH, self.frame.size.height);
_collectionView.backgroundColor = [UIColor clearColor];
_collectionView.delegate = self;
_collectionView.dataSource = self;
_collectionView.allowsSelection = YES;
_collectionView.alwaysBounceVertical = YES;
_collectionView.scrollEnabled = NO;
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
}
return _collectionView;
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
return (_photos.count > 9 ? 9 : _photos.count);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath; {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width, cell.frame.size.height)];
imgView.clipsToBounds = YES;
imgView.backgroundColor = RGB(250, 250, 250);
if (_photos.count) {
PhotoDM *photo = [_photos objectAtIndex:indexPath.row];
[imgView setImageWithURL:[NSURL URLWithString:photo.largeLink]
placeholderImage:[UIImage imageNamed:#"placeholder"]];
}
[cell addSubview:imgView];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"tapped: %ld", (long)indexPath.row);
if([delegate respondsToSelector:#selector(photoDidTapped:)])
[delegate performSelector:#selector(photoDidTapped:) withObject:[[NSNumber alloc] initWithInteger:indexPath.row] ];
}
Your code contains 2 problems.
1. If you create a subview, you should use self.bounds.
2. The view can be resized, after UICollectionView has been added. It means that you should configure autoresizingMask or NSLayoutConstrans. (UICollectionView can be out of view's bounds).
To debug this problem, you can create different background colors for the view, the collectionView, the viewController's view.
Hi friends is it possible to add a cover flow effect in uicollection view in horizontal layout.if possible means kindly tell me how to implement the effect.
Yes it is possible, You need to Implement your custom UICollectionViewFlowLayout.
Make a custom class which inherits UICollectionViewFlowLayout
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES; }
- (UICollectionViewScrollDirection)scrollDirection {
return UICollectionViewScrollDirectionVertical; }
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
UICollectionView *collectionView = [self collectionView];
UIEdgeInsets insets = [collectionView contentInset];
CGPoint offset = [collectionView contentOffset];
CGFloat minY = -insets.top;
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
// minY is Point where we implement this cover flow.
if (offset.y < minY) {
// Figure out how much we've pulled down
CGFloat deltaY = fabsf(offset.y - minY);
for (UICollectionViewLayoutAttributes *attrs in attributes) {
// Locate the header attributes
NSString *kind = [attrs representedElementKind];
if (kind == UICollectionElementKindSectionHeader) {
// This is header's height and y based on how much the user has scrolled down.
CGSize headerSize = [self headerReferenceSize];
CGRect headerRect = [attrs frame];
headerRect.size.height = MAX(minY, headerSize.height + deltaY);
headerRect.origin.y = headerRect.origin.y - deltaY;
[attrs setFrame:headerRect];
break;
}
}
}
return attributes; }
Now in your class where you allocate UICollectionView
CustomCoverFlowHeaderCollectionViewLayout *flow; flow = [[CustomCoverFlowHeaderCollectionViewLayout alloc] init]; [stretchyLayout setHeaderReferenceSize:CGSizeMake(320.0, 160.0)]; // Set our custom layout [collectionView setCollectionViewLayout: flow]; [collectionView setAlwaysBounceVertical:YES]; [collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:#"myCoverCollectionView"];
You are almost done
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath {
if (!header) {
header = [collectionView dequeueReusableSupplementaryViewOfKind:kind
withReuseIdentifier:#"myCoverCollectionView" forIndexPath:indexPath];
CGRect bounds;
bounds = [header bounds];
UIImageView *imageView;
imageView = [[UIImageView alloc] initWithFrame:bounds];
[imageView setImage:[UIImage imageNamed:#"background"]];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
[imageView setClipsToBounds:YES];
[imageView setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
[header addSubview:imageView];
}
return header; }
Here is a good project based on UICollectionView for you.
I have a UICollectionView that i set up in the viewDidLoad and add the images immediately after that. When the user scrolls to a certain point i try to add more images but The collection view won't load the new images
How do i reload or add more images to my scrollview
#pragma mark - New Retrieve
- (void) rwDataToPlist {
// Step1: Get plist file path
NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory ,NSUserDomainMask, YES);
NSString *documentsDirectory = [sysPaths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"news.plist"];
NSLog(#"Plist File Path: %#", filePath);
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
stuff = [[NSArray alloc] initWithContentsOfFile:filePath];
//NSLog(#"Stuff %#", stuff);
[self sortRetrievedData];
} else {
}
}
-(void)sortRetrievedData {
titles = [stuff valueForKey:kKeyTitle];
thumbMediaUrl = [stuff valueForKey:kKeyThumbUrl];
thumbWidth = [stuff valueForKey:kKeyThumbWidth];
thumbHeight = [stuff valueForKey:kKeyThumbHeight];
for(NSArray *array in titles) {
for (NSArray *realArray in array) {
titles = realArray;
}
}
for(NSArray *array in thumbMediaUrl) {
for(NSDictionary *dict in array) {
thumbMediaUrl = dict;
}
}
for(NSArray *array in thumbWidth) {
for(NSDictionary *dict in array) {
thumbWidth = dict;
}
}
for(NSArray *array in thumbHeight) {
for(NSDictionary *dict in array) {
thumbHeight = dict;
}
}
}
#pragma mark - Collection View
#pragma mark - Display Collection
-(void)displayCollection {
UIColor *myColor = [UIColor colorWithRed:(245.0 / 255.0) green:(245.0 / 255.0) blue:(245.0 / 255.0) alpha: 1];
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CGRect locOfScree = CGRectMake(0, 64, screenWidth, screenHeight - 44);
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
imageDisplayer = [[UICollectionView alloc] initWithFrame:locOfScree collectionViewLayout:layout];
[imageDisplayer setDataSource:self];
[imageDisplayer setDelegate:self];
UINib *nib = [UINib nibWithNibName:#"CollectionViewCell" bundle:nil];
[imageDisplayer registerNib:nib forCellWithReuseIdentifier:CellIdentifier];
[imageDisplayer setBackgroundColor:myColor];
[self.view insertSubview:imageDisplayer belowSubview:navBar];
//[self.view addSubview:imageDisplayer];
}
#pragma mark - Setup
- (void)setupData
{
self.imageURLStrings = [NSMutableArray array];
// Save image to docs directory so we can get a nice URL
// Not sure how to get the URL from an asset catalog off the top of my head
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"greyBurger.png"];
UIImage *image = [UIImage imageNamed:#"greyBurger"];
NSData *data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
// Populate our imageURLStrings array with many paths
for (NSInteger i = 0; i < NumberOfImages; i++)
{
[self.imageURLStrings addObject:path];
//NSLog(#"Path %#", path);
}
}
- (void)setupCollectionView
{
UINib *nib = [UINib nibWithNibName:#"CollectionViewCell" bundle:nil];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:CellIdentifier];
}
#pragma mark - UICollectionView Datasource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
//return [self.imageURLStrings count];
return [titles count];
//return 2;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
//NSLog(#"CELL FOR COUNT:%lu", [titles count]);
NSString *title = [titles objectAtIndex:indexPath.row];
cell.backgroundColor = [UIColor whiteColor];
NSString *imageUrl = [thumbMediaUrl objectForKey:title];
NSURL *thumbUrl = [NSURL URLWithString:imageUrl];
UIImageView *imageView = [[UIImageView alloc] init];
NSData *imageData = [NSData dataWithContentsOfURL:thumbUrl];
imageView.image = [UIImage imageWithData:imageData];
cell.backgroundView = imageView;
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
//cell.frame = CGRectMake(0, 0, 100, 100);
//cell.imageURLString = [self.imageURLStrings objectAtIndex:indexPath.item];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
NSString *title = [titles objectAtIndex:indexPath.row];
float width = [[thumbWidth objectForKey:title] floatValue];
float height = [[thumbHeight objectForKey:title] floatValue];
float imageWidth = (screenWidth / 2) - 3;
float scale = imageWidth / width;
float imageHeight = height * scale;
CGSize imageSize = CGSizeMake(imageWidth, imageHeight);
return imageSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray* attributesToReturn = [self layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn)
{
if (nil == attributes.representedElementKind)
{
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes* currentItemAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item < numColumns){
CGRect f = currentItemAttributes.frame;
f.origin.y = 0;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat YPointNew = fPrev.origin.y + fPrev.size.height + 10;
CGRect f = currentItemAttributes.frame;
f.origin.y = YPointNew;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
I have changed my code based on suggestions of The first two answers, now i have to to get the images to add to a running view. and make each column have their own independent height so there is a 2px spacing at each edge, This is what i tried for reloading data
-(void)refreshView {
[self rwDataToPlist];
[self.collectionView reloadData];
[self setupCollectionView];
}
With starting iOS6 itself Apple Introduced for UICollectionView. You can Use UICollectionView with Pull to Bottom Refresh to Achieve your Goal. Its look like UITableView Pull to Bottom Refresh.
Here Are Some Reference for UIcollectionView:
Source Code
Beginning UICollectionView
UICollectionView with StoryBoard
Once You create UICollectionView then You need to Add PulltoBottom Refresh for your UICollectionView like following code:
-(void)viewWillAppear:(BOOL)animated
{
[self.collectionView.infiniteScrollingView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite];
[self.collectionView addInfiniteScrollingWithActionHandler:^{
////(#"Infinitescroll");
#try {
int64_t delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//[self.dataSource addObjectsFromArray:tmp];
[self.collectionView performBatchUpdates:^{
} completion:nil];
[self.collectionView.infiniteScrollingView stopAnimating];
});
}
#catch (NSException *exception) {
}
}];
[super viewWillAppear:animated];
}
For Below code you must Add some files:
SVPulltoReferesh Link
A few suggestions / questions:
Not knowing the constraints of your particular problem, it sounds like you're trying to display some semblance of a grid of images, and load the "next page" of images when a user scrolls beyond a certain point. It seems like a UITableView or UICollectionView would be a more appropriate mechanism to do what you're trying to do. Both of those classes will handle lazy loading of images, pagination via a properly configured datasource, automatic contentSize adjustments, and will be blazing fast without mainThread freezes. They're also based on the MVC design pattern and will likely clarify some of the design in the code above.
The reason the UI/scrolling freezes when you load more images is likely due to reading both userDefaults and the image data itself from disk. Disk operations can be expensive, especially many at a time. If you must load the metadata and image files this way, consider doing this processing on a background thread via GCD's dispatch_async.
The reason the second set of images is not appearing is likely due to image frame or scrollView contentSize miscalculation. Consider debugging by adding a series of colored UIViews to the scrollView instead of UIImageViews, and consider hard coding the contentSize.height to something much larger than you need. Also, have you NSLogged the image frames and contentSize to make sure they match up?
Edit:
Here's a link to a quick sample project using a UICollectionView and a background thread for reading UIImage data from disk (which isn't really necessary anymore due to using UICollectionView):
https://github.com/alfiehanssen/SOImageGrid
Let me know if you have questions, hopefully I'm not totally off the mark in terms of your goals.
I used a UICollectionView as suggested in the first two answers and added CHTCollectionViewWaterfallLayout to it to allow the image spacing i wanted
My Code:
#pragma mark - Collection View
#pragma mark - Display Collection
-(void)displayCollection {
UIColor *myColor = [UIColor colorWithRed:(245.0 / 255.0) green:(245.0 / 255.0) blue:(245.0 / 255.0) alpha: 1];
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
CGRect locOfScree = CGRectMake(0, 44, screenWidth, screenHeight - 44);
CHTCollectionViewWaterfallLayout *layout = [[CHTCollectionViewWaterfallLayout alloc] init];
layout.sectionInset = UIEdgeInsetsMake(2, 2, 2, 2);
layout.headerHeight = 0;
layout.footerHeight = 0;
layout.minimumColumnSpacing = 2;
layout.minimumInteritemSpacing = 2;
//UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
imageDisplayer = [[UICollectionView alloc] initWithFrame:locOfScree collectionViewLayout:layout];
imageDisplayer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[imageDisplayer setDataSource:self];
[imageDisplayer setDelegate:self];
UINib *nib = [UINib nibWithNibName:#"CollectionViewCell" bundle:nil];
[imageDisplayer registerNib:nib forCellWithReuseIdentifier:CellIdentifier];
[imageDisplayer setBackgroundColor:myColor];
[self.view insertSubview:imageDisplayer belowSubview:navBar];
//[self.view addSubview:imageDisplayer];
imageDisplayer = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
imageDisplayer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imageDisplayer.dataSource = self;
imageDisplayer.delegate = self;
imageDisplayer.backgroundColor = [UIColor whiteColor];
[imageDisplayer registerClass:[CHTCollectionViewWaterfallCell class]
forCellWithReuseIdentifier:CellIdentifier];
}
#pragma mark - Setup
- (void)setupCollectionView
{
UINib *nib = [UINib nibWithNibName:#"CollectionViewCell" bundle:nil];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:CellIdentifier];
}
#pragma mark - UICollectionView Datasource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
//return [self.imageURLStrings count];
return [titles count];
//return 2;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
/*
CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
*/
CHTCollectionViewWaterfallCell *cell =
(CHTCollectionViewWaterfallCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier
forIndexPath:indexPath];
NSString *title = [titles objectAtIndex:indexPath.row];
cell.backgroundColor = [UIColor whiteColor];
NSString *imageUrl = [thumbMediaUrl objectForKey:title];
NSURL *thumbUrl = [NSURL URLWithString:imageUrl];
UIImageView *imageView = [[UIImageView alloc] init];
NSData *imageData = [NSData dataWithContentsOfURL:thumbUrl];
imageView.image = [UIImage imageWithData:imageData];
cell.backgroundView = imageView;
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
NSString *title = [titles objectAtIndex:indexPath.row];
float width = [[thumbWidth objectForKey:title] floatValue];
float height = [[thumbHeight objectForKey:title] floatValue];
float imageWidth = (screenWidth / 2) - 3;
float scale = imageWidth / width;
float imageHeight = height * scale;
CGSize imageSize = CGSizeMake(imageWidth, imageHeight);
return imageSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray* attributesToReturn = [self layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn)
{
if (nil == attributes.representedElementKind)
{
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes* currentItemAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item < numColumns){
CGRect f = currentItemAttributes.frame;
f.origin.y = 0;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat YPointNew = fPrev.origin.y + fPrev.size.height + 10;
CGRect f = currentItemAttributes.frame;
f.origin.y = YPointNew;
currentItemAttributes.frame = f;
return currentItemAttributes;
}