IOS : UICollectionView inside UIScrollView index not incremented - ios

Hello people of stackoverflow,
Currently working on an App where I have a user profile that looks like this
http://i.imgur.com/H1N0ouX.jpg (sorry I dont have enough reputation to post the image)
Header View is a picture of the user.
Tab View is 2 tabs, one with a collectionview, the other with a tableview.
All those views are nested inside a scrollView
My problem is that when I scroll that view (collection view height set programmaticaly depending on number of elements), the collection view's index does not increment. Only the 6 first items are loaded in in the visible cells index of the collection view.
I need to segue from the collectionview's items to the item's detail view.
How can I use the scrollView delegate to know where my collection view is at.
I've looked at those threads :
iOS 7 Collection View inside Scroll View
How to implement non-scrollable UICollectionView inside UIScrollView?
But none gave me the answer I was looking for.
I also tried looking at scrollViewDidEndDecelerating and setting my collection view scroll offset according to the scroll view offset, but I could not make it work.
Any advices?
Thanks
EDIT :
Hello and thanks for your answer,
To answer your question, I can scroll my collectionview, since it is inside a scroll view, I set my collectionview height during viewdidload (based on number of elements)
my problem is, I can click on the first 6 items , and display details (via a segue) but after that, selection is not recognized as the index is not refreshed for my collection view. I can scroll all the way to the bottom of my collection view (I scroll via the scrollView).
My collectionView has user interaction enabled checked, as I said, I can select the first 6 items, and then selection is not recognized.
I understand the UICollectionViewFlowLayout issue, but where do I write this line ? in the viewDidLoad? or in delegate funcs of CollectionView ?
If you need more information, I can copy some code or show you the layout of the view in storyboard
Thanks in advance.
EDIT 2 :
images , storyboard : layout of my view
http://i.gyazo.com/c491786507db2effc702d910020515a2.png
code, here are the datasource funcs of the collectionView
http://gyazo.com/3730caeb2b2a40fef9efec559171744f
delegate func of the collection view
http://i.gyazo.com/81fc9443b4367ecbd304e608ab0cc864.png
EDIT3:
Okay so basically this is what I want to reproduce,
tab view in the middle with multiples tabs with collection view, all this scrollable.
What I cant understand, is if I set my topView as the header of the CollectionView, I can't switch tabs like I want since its inside the header.
ViewController with TalbeView and CollectionView tabs like Google+ in IOS

Hi First of all I need more detail about your question but I am assuming that you want your UICollectionView scrollable and actually its not scrolling.
So could you check following points :-
UserEnableInteraction for collection view should be enabled.
And also check what is the value you gave for UICollectionViewFlowLayout because just consider if You have total 5 elements to show and your UICollectionViewFlowLayout size is like it can show all five items in visible cell index then it doesn't scroll so you need to increase the size of UICollectionViewFlowLayout to make it scroll.
e.g
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(148, 148)];
And if you want then you can get the help from UIScrollViewDelegate method like
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate)
{
// do your job
}
}

set delegates and Datasource in .h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource , UITableViewDelegate ,
UIScrollViewDelegate , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout>
You can do that .m
in ViewDidLoad:-
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
UICollectionView *collectionView =[[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout ];
collectionView.frame = CGRectMake(5, 61, 365, 678);
collectionView.delegate = self;
collectionView.dataSource = self;
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.view addSubview:collectionView];
And then Call her delegates method :-
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [arrImages count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
[self createCell:cell forTableview:collectionView];
[self fillCell:cell cellForRowAtIndex:indexPath];
return cell;
}
//- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
//{
// return CGSizeMake(50, 50);
//}

Related

Self Sizing Collection View Cell in iOS

I implemented UICollection view cell with Auto Layout. It works fine.
But my cell height is dynamic so cell should be change its height as per constraint set.
but height is not changed in any case.
My Code
- (void)viewDidLoad {
[super viewDidLoad];
UICollectionViewFlowLayout *flowlayout = (UICollectionViewFlowLayout*)_col.collectionViewLayout;
flowlayout.estimatedItemSize = CGSizeMake(self.view.frame.size.width - 30, 600);
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
FirstCell *cell = [_col dequeueReusableCellWithReuseIdentifier:#"FirstCell" forIndexPath:indexPath];
return cell;
}
Storyboard
Simulator
All labels are multi lined
Help me to solve this
thanks for your time
Please follow below thing to achieve self sizing collection cell.
1) Same as table cells, use constraints or override -sizeThatFits:.
2) Override -[UICollectionReusableView preferredLayoutAttributesFittingAttributes:] to adjust layout attributes determined by the UICollectionViewLayout.
3) New estimatedItemSize property on UICollectionViewFlowLayout, equivalent to estimatedRowHeight on UITableView.
There are no self-sizing collection view cells in iOS before iOS 10. (Apple has claimed in WWDC videos that this feature exists, but it doesn't.)
You have to implement the delegate method collectionView:layout:sizeForItemAtIndexPath to provide a size for each cell. It can call systemLayoutSizeFittingSize: to use the internal constraints to do that, if you like; but the runtime will not magically do it for you.

iOS 8 Auto cell height - didSelectRowAtIndexPath causes UItableview to jump to top

I'm currently updating an app to iOS8, and am replacing my own cell height calculations. I have a tableview with a bunch of custom cells. Each cell when selected will present/push a new view onto the navigationController. When the tableview is populated with these cells, and the user selects one near the bottom of the table, the tableview jumps to the top right before the new view is presented. This is very distracting to the user. I'm trying using self sizing cells introduced in iOS 8 here (in the viewDidLoad):
self.tableView.estimatedRowHeight = 60.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;
Here's the code for when a cell is selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIViewController *selectedViewController = [[UIStoryboard storyboardWithName:#"Trip" bundle:nil] instantiateViewControllerWithIdentifier:#"TripDetail"];
DetailViewController *destViewController = (id)selectedViewController;
[destViewController setData:self.dataStore];
[self.navigationController pushViewController:selectedViewController animated:YES];
}
Does anyone know why this is happening? And how I can make it stop?
It's a known issue. The tableView is calling its delegate to get an estimated height for the rows, which is causing the table to scroll.
You can wait to see if it's fixed in the next update, or implement tableView:estimatedHeightForRowAtIndexPath: (as a workaround for now) and return a cached height. Since the estimate will be the actual height, the table won't jump.
This happen's when the table delegate was tapped "didSelectRowAtIndexPath:"
because the delegate method "numbersOfSectionsInTableView" && "numbersOfRowsInSection" will get called. its like reloading the table.
You can fix that jumping state with this method "heightForRowAtIndexPath:" however you'll have to disregard your auto sizing.

Is it possible to have a fixed uitableview Header while using sections?

This question should not be mixed up with this here.. These are two different things.
There is a good example how to use a UITableView Header on SO.
This all works fine and the main header is fixed on top as long as the style is set to plain.
But if I use sections, the main header no longer sticks to top and moves away while scrolling to the bottom.
In this method, I am returning the header for each section.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
In this method I am setting the height for the header section above:
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
In this method, I am setting the real table header.
- (void)viewWillAppear:(BOOL)animated {
...
self.recordTableView.tableHeaderView = headerView;
}
Is it even possible having a fixed table header, while using sections?
What is an alternative solution to this please?
If you want a UITableViewController (static cells/keyboard handling) and have a fixed header then you should use Containment. You can do this from a Storyboard by setting up a UIViewController with your fixed header and then using a Container View to embed the UITableViewController.
Once you have your containing view setup, you right-click drag from the Container View to the View Controller you want to embed - the UITableViewController in this case.
You can access and get a reference to the contained View Controller (the UITableViewController) from the Container View Controller by implementing the prepareForSegue:sender: method.
There’s no way to maintain the header of a tableView fixed, but
an useful approach when you need a unique header, is to use a UIViewController rather than a UITableViewController, and set the header (UIView) out from the tableView.
Something like this:
If you want to keep the class as a UITableViewController you can add your header as a subview to the tableview's superview. You will have to also push the tableview top inset down so your headerview doesnt hide the table.
Here is a sample code to put inside your tableViewController subclass (This example assumes your tableview controller is inside a navigation controller, so it pushes the view to below the navigation bar):
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.automaticallyAdjustsScrollViewInsets = NO;
}
-(void)addHeaderView{
CGFloat yPosition = self.navigationController.navigationBar.frame.origin.y + self.navigationController.navigationBar.frame.size.height;
mainHeaderView = [[UIView alloc] init];
const CGFloat mainHeaderHeight = 44;
[mainHeaderView setFrame:CGRectMake(0, yPosition, self.view.frame.size.width, mainHeaderHeight)];
mainHeaderView.backgroundColor = [UIColor redColor];
[self.tableView.superview addSubview:mainHeaderView];
[self.tableView setContentInset:UIEdgeInsetsMake(yPosition + mainHeaderHeight, self.tableView.contentInset.left, self.tableView.contentInset.bottom, self.tableView.contentInset.right)];
}
I haven't done this, but the first thing I would think to try is to place my tableview in a UIView and make my own header there in that UIView. Seems a trivial matter to make that view appear to be the header of the table and it would certainly stay put.

Programmatically setting the height of a UIView subview inside a cell of a UICollectionViewController?

Inside the reusable view of my cell, I have a UIView.
Then, I have this method in the controller
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// .. set value for CGFloat backgroundHeight
[cell addSubview:cell.backgroundView];
CGRect f = cell.backgroundView.frame;
f.size.height = backgroundHeight;
cell.backgroundView.frame = f;
}
But the UIView's height remains the same as specified in the Layout Rectangle.
What should I try next?
Your problem here lies in the fact that you are attempting to use the cell's backgroundView.
Firstly, you cannot add the cell's backgroundView as a subview. You simply assign a UIView to it with :
cell.backgroundView = yourView;
Secondly, if you read the docs, it clearly states :
Use this property to assign a custom background view to the cell. The background view is placed behind the content view and its frame is automatically adjusted so that it fills the bounds of the cell.
This means, no matter what frame you try to set for the backgroundView it will automatically adjust and fill the entire cell. Now, I haven't actually tried it, but you might be able to override this by subclassing. Though, i'll mention here, I am unsure.
Back to your problem, if you really want a UIView that you can control, you will need to create a UIView and then add it as a subview. Using the cell's backgroundView is not the solution.
It just seems like useless, what you'r approaching with the UICollectionViewCell's backgroundView .
By the Doc
backgroundView The view that provides the background appearance.
#property (nonatomic, retain) UIView *backgroundView; Discussion The
view (if any) in this property is positioned underneath all of the
other content and sized automatically to fill the entire bounds of the
collection view. The background view does not scroll with the
collection view’s other content. The collection view maintains a
strong reference to the background view object.
This property is nil by default, which displays the background color
of the collection view.
the backgroundView is just nothing but the cell, so what you'r upto do is doesn't effect . seems like directly changing the Cell's height.
the best solution is to just ignore the backgroundView property all
together. Instead, make the collection view’s background clear, and
implement your own View; just throw a view behind the
collection view.
Kindly check this blog, this would be helpful for you.
You can manage the Layout height With sizeForItemAtIndexPath
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(view.frame.size.width, view.frame.size.height);
}
here you can manage spacing
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(5,5,0,5);
}
Controlling UICollectionViewCells is just the same as UITableViewCell. What you need to do is create a UICollectionViewCell subclass. These can seem confusing to start with but are really pretty simple to set up.
The first thing is to add any additional properties you might need like additional UIImageViews, UILabels etc. Now, we need to make sure all objects are instantiated but only once so this happens in
- (id)initWithFrame:(CGRect)frame
As well as instantiating an adding subviews to self.contentView set any global or default properties such as font, color etc. You can't set a frame relative to self.contentView yet though because self.contentView has zero size until layoutSubviews.
Now, create a method:
-(void)layoutSubviews
{
[super layout subviews];
...
[self.backgroundView setFrame: myFrame]; // in this case
}
The [super layoutSubviews] is important to set self.contentView's frame from the delegate cell layout methods. This method is called every time the cell comes into view or changes in any way (which is often). What you need to do now is set the various frames of things based on self.contentView.frame or self.frame. Also, you can set any conditional properties like hiding icons depending on a state etc.
To answer the question, you do not need to add self.backgroundView because it is already there. What you do need to do is set the frame in layoutSubviews as above but you need a UICollectionViewCell subclass in order to do that.
To use the custom cell you just need to include your new .h file and swap UICollectionViewCell for your new classname in the
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
method like:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
return cell;
}
Do it like below, as you can not modify only height in frame you have to define new frame using CGRectMake function, after this you will also require to change the cell height also otherwise your view will be displayed in that much portion only.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// .. set value for CGFloat backgroundHeight
[cell addSubview:cell.backgroundView];
CGRect frame = CGRectMake(cell.backgroundView.frame.origin.x, cell.backgroundView.frame.origin.y, cell.backgroundView.frame.size.width, backgroundHeight);
cell.backgroundView.frame = frame;
}

What the method should I use when collectionview and button in the same view in IOS?

I am new to IOS , and I use the Xcode5.
I want to create a view like the following picture.
Can I add a View , and add the button and the collectionView cell in to the View , and add the imageView and two label which below the imageView in to collectionView cell ?
or does there has other method to implement the view like the picture ?
---------------------------------------EDIT------------------------------------------------
I have modify the xib file like the following picture.
I add the collectionView below two button , but how to add the label below image like the following first picture ?
you can add the top two buttons to the collectionView headerView using following method
// The view that is returned must be retrieved from a call to -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView *headerView = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"headerView" forIndexPath:indexPath];
if (kind == UICollectionElementKindSectionHeader) {
[headerView addSubview:YOURBUTTON1];
[headerView addSubview:YOURBUTTON2];
}
return headerView;
}
Yes you can implement it like you want fairly easily.
You have a couple of options, you can either use a UICollectionView and just pop it where you want it to go on top of your UIViewController along with the buttons.
The other option is to use a UIContainerView to contain your UICollectionViewController and manage it through the corresponding view controller to manage the data/delegate.
luckily I have 2 such examples handy from something I was testing recently.
Above: UICollectionView in a UIViewController with the buttons
Below: A UICollectionViewController embedded in a UIContainerView

Resources