iOS: How can I change the orientation of a UICollectionViewCell? - ios

I have a UICollectionViewController that I load when a user turns their iPad so as to put it into landscape orientation. The problem I’m having is that my UICollectionViewCells are still loading as if it were in portrait orientation. I set the UICollectionViewController to landscape inside Interface Builder, and I’m using a custom cell class that I’ve called CollectionViewCell. Each cell contains just an image and a label.
Is there something that I should be doing either in Interface Builder or in my code? I tried using CGAffineTransformationMakeRotation, but that was no help. If anyone else has encountered this before, I would be extremely grateful! Thanks very much!
Here’s a bit of the code for reference:
-(void)viewDidLoad
{
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
return listArray.count;
}
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
{
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"devices" forIndexPath:indexPath];
cell.statusImage.image=[UIImage imageNamed:#"Default.png"];
cell.name.text=#"HEY !!!!!";
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(320, 420);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(50, 20, 50, 20);
}

In case anyone else has had this problem, here is how I solved it.
I was initially not allowing autorotation, and instead was just registering for orientationChanged notifications using NSNotificationCenter. This worked great except that it was preventing my second view from realizing that it needed to load in landscape mode.
So instead of that, I’ve created a class for the tabBar that my main view is embedded in, and I return NO for the shouldAutoRotate method in that class and in every other view except for the one which I want to load in landscape mode. I’m still using the orientationChanged notifications in my main view’S controller, since it is embedded in the tabBar. But I’m just using autorotation when returning to the main view.
If anyone has any questions, let me know. Hope it helps!

Related

How to customise UICollectionView Cell to show image grid as shown in attachment?

I want to show images as shown in the attachment. How can I do this using storyboard and objective c?
Based on the image count, the cell size needs to be adjusted.
EDIT
This answer applies to the original question with a single layout based on a large first image and smaller latter images.
This is really easy ... I did not bother with iOS versions and what I give below needs a lot of additional work, but at least it will give you the idea.
The storyboard
In the storyboard I really just set up two items in the collection view. One large and one small picture. You could easily do it with one, here I use two as then I can load the image in storyboard and need not bother with configuring the cells.
Hopefully the image below will help you understand what I mean. Also note the horizontal scrolling.
The collection view
This is bare bones. Of course it needs work. Especially I do NO cell configuration but dequeue and return the cell straight without any configuration. You need to configure each cell by loading the image that should be displayed for it.
The two cell types I define in storyboard are called imgLarge and imgSmall. Note I use the same as item identifier as well.
The most important thing here, that really makes it work, is the last message, where I return two different sizes for the two different cells.
#import "TestCollectionViewController.h"
#interface TestCollectionViewController () < UICollectionViewDataSource, UICollectionViewDelegateFlowLayout >
#end
#implementation TestCollectionViewController
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
self.collectionView.collectionViewLayout.invalidateLayout;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 10;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if ( indexPath.row )
{
return [collectionView dequeueReusableCellWithReuseIdentifier:#"imgSmall" forIndexPath:indexPath];
}
else
{
return [collectionView dequeueReusableCellWithReuseIdentifier:#"imgLarge" forIndexPath:indexPath];
}
}
#pragma mark <UICollectionViewDelegate>
- ( CGSize ) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat h = collectionView.bounds.size.height;
if ( indexPath.row )
{
return CGSizeMake( h / 2, h / 2 );
}
else
{
return CGSizeMake ( h, h );
}
}
#end
This is actually the second version. The first version just used constants here. Since they are calculated, to make it work, you need to set all the spacing and insets to 0 in storyboard.
The result
Voila!
I mentioned that this is the second version. The previous one looked slightly different as you can see below. I kept the image, for the code of the earlier one just look at the history of this post.

UICollectionView cell does not showing

I have defined an UI for my App. There is a UICollectionView which is 100% defined in Main.StoryBoard. I have a fixed number of cells and each cell image has an image in it. I have setup the number of cell and image for each cell in Main.StoryBoard. However, when I launched the App, the UICollectionView is empty. It does not show any cell. What is wrong? Do I have to define a class for this UICollectionView? Do I have to write any ObjectiveC Code?
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 5; // put your array count
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell;
cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"GIVEYOURCELL_IDENTITIFER" forIndexPath:indexPath];// same identifier storyboard cell
UIImageView *thumbail = (UIImageView*) [cell viewWithTag:YOURCELLIMAGETAG]; // give tag here that you put in cell with imageview
thumbail.image = [UIImage imageNamed:#"ImageName"];// give your image here
return cell;
}
Main Point give UICollectionViewDataSource, UICollectionViewDelegate Delegates in your .h file and also from storyboard to your viewController.

CollectionView dequeCell with removing subviews from cell makes view appear slow

I have code:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 30;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:REUSE_IDENTIFIER forIndexPath:indexPath];
[[cell subviews]
makeObjectsPerformSelector:#selector(removeFromSuperview)];
[cell addSubview:someView];
return cell;
}
Above code gets executed in viewWillAppear
If I make the above code executed 30 times, the view appearance is really slow.
Due to cell reuse, I need to make a call to removeFromSuperView. Otherwise stale wrong data is displayed on the cell.
I am not able to figure out what could be causing the slowness??
Can you provide hints?
Your appearance is slow because you are iterating through all the subviews within the cell and removing from superview. This is a very expensive process and should not be done in the cellForItemAtIndexPath method of the collectionView data source/ Infact this should never be done. If you need to display relevant content you need to access the instance of the cell and update the properties of the UI elements within the cell.

cellForItemAtIndexPath: firing in iOS7 but not iOS6

When recently adding a UICollectionView with a custom UICollectionViewFlowLayout subclass, the collectionView:cellForItemAtIndexPath: method is only being called on iOS7, and not on iOS6. In other words, everything works great in iOS7 but my custom collectionView items are not showing up in iOS6. Interestingly, the cells appear to be there (the collectionView scrolls), but all items are empty with a white background.
The collectionView was set up in a .xib file, dataSource and delegate were attached, and UICollectionViewDataSource and UICollectionViewDelegateFlowLayout were added after the #interface call in the view controller .h file.
The collectionView item size, section inset, line spacing, and inter-item spacing are all being set in the custom flow layout init method.
Some code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionView.collectionViewLayout = [[TFSpringFlowLayout alloc] init];
[self.collectionView registerClass:[TFWorkoutCell class] forCellWithReuseIdentifier:CellIdentifier];
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
// This method is returning a value > 0
return _workouts.count;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// This is being called on iOS7, but is never being called on iOS6
...removed for clarity
return cell;
}
EDIT: Issue Solved. My custom Flow Layout included some iOS7-specific overrides utilizing the new UIDynamicAnimator class. These were not causing a crash, but were preventing the cells from being drawn in iOS6.
Here is what the issue was for me, in case anybody else runs into this problem in the future.
My custom UICollectionViewFlowLayout contained several method overrides to implement iOS7's new UIKit Dynamics. These did not cause the application to crash, but prevented the cells from being drawn in iOS6.
Here is the offending code:
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
return [self.dynamicAnimator itemsInRect:rect];
}
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath];
}
And the simple change required for the fix:
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
if ([UIDynamicAnimator class])
return [self.dynamicAnimator itemsInRect:rect];
else
return [super layoutAttributesForElementsInRect:rect];
}
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
if ([UIDynamicAnimator class])
return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath];
else
return [super layoutAttributesForItemAtIndexPath:indexPath];
}
Adding an if/else statement to check for iOS6 or iOS7 and only returning the appropriate response fixed the issue for me. Hope this helps someone else!

iOS 6 CollectionView Dynamically change Layout

I'm kinda newbie in UICollectionView and I'm working in a project that dynamically changes the UICollectionViewLayout in a given action.
My CollectionView has 6 sections, each of them with 10 elements. Those Cells are basically an UIImageView and my Custom Layout called StackViewLayout stacks all elements for each section (something like Apple's Photos.app).
If the user selects the element of the stack (for all sections), the UICollectionView dynamically changes the layout to the UICollectionViewFlowLayout, so all the elements can be viewed as grid.
My problem is that when user selects a stack, no matter which section, when the Layout is changed do Flow Layout, all sections are displayed in the grid, instead of displaying the elements for the selected section (stack), which is the behavior I wanted.
Is there any way to show only the Flow Layout for the selected section in the Custom Layout?
Here is my Controller Implementation snippet code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadStackLayout]; // stack all sections at first load.
}
#pragma mark - UICollectionView Data Source Methods
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 6;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 10;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
// custom UICollectionViewCell, which will hold an image.
CVCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
cell.imageView.image = _images[indexPath.row];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
// element size.
return CGSizeMake(100,100);
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (isStacked)
{
[self loadFlowLayout]; //HERE I WANT TO LOAD FLOW LAYOUT ONLY FOR THE SECTION OF THE SELECTED ITEM!
} else
{
// to implement.
}
}
// HERE IS THE METHOD THAT CALLS MY CUSTOM LAYOUT IN ORDER TO STACK THE ELEMENTS FOR EACH SECTION IN COLLECTION VIEW. IT IS WORKING AS IT SHOULD.
-(void)loadStackLayout
{
if (([self.collectionView.collectionViewLayout isKindOfClass:[UICollectionViewFlowLayout class]]))
{
isStacked = YES;
[self.collectionView setCollectionViewLayout:[[StackViewLayout alloc] init] animated:YES];
}
}
// HERE IS THE METHOD THAT CALLS MY FLOWLAYOUT IN ORDER TO UN-STACK THE ELEMENTS AND SHOW THEM IN A GRID. CURRENTLY IT IS SHOWING ALL SECTIONS IN THE GRID.
-(void)loadFlowLayout
{
if (([self.collectionView.collectionViewLayout isKindOfClass:[StackViewLayout class]]))
{
isStacked = NO;
[self.collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];
}
}
I think you can probably do it by having an if clause in your numberOfItemsInSection: method, to return 0 for any section that's not the selected one. Obviously, you'll need to keep track of the selected section to do this.

Resources