I want to develop an iOS app that takes all of the articles from my wordpress blog and lays them out properly. Every article has a title, an image and some content. For the first screen I want to make something like a customized UITableView, but I am not sure if this is the proper way to implement it.
http://a2.mzstatic.com/us/r30/Purple2/v4/5c/70/05/5c7005b2-ab76-33ab-e32f-5f7e861ef5e9/screen568x568.jpeg
Here is the kind of thing I want to do without the search bar. But every article would have its image layed out this way and the have its title (no need for a content preview) under the image. If I use a UITableView I will have a "separation" between all the images which is not exactly the way it is done here. Do you know how I could achieve something like this ? Would I have to create my graphical objects programmatically or is this feasible with the storyboard/interface builder tools?
You should use customized UITableViewCell. Here are the resources:
https://developer.apple.com/library/ios/documentation/userexperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html
http://www.idev101.com/code/User_Interface/UITableView/customizing.html
http://www.appcoda.com/customize-table-view-cells-for-uitableview/
You can create CustomCell class with XIB that is inherited from UITableViewCell. We will just add category in tableview class .m file in following way. I think this is the easiest method which an be applied for custom cell creation.
#interface UITableViewCell(NIB)
#property(nonatomic,readwrite,copy) NSString *reuseIdentifier;
#end
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 30;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier=#"cell";
CustomCell *cell=[tableView dequeueReusableCellWithIdentifier:identifier];
if(cell==nil)
{
NSLog(#"New Cell");
NSArray *nib=[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell=[nib objectAtIndex:0];
cell.reuseIdentifier=identifier;
}else{
NSLog(#"Reuse Cell");
}
cell.lbltitle.text=[NSString stringWithFormat:#"Level %d",indexPath.row];
id num=[_arrslidervalues objectAtIndex:indexPath.row];
cell.slider.value=[num floatValue];
return cell;
}
#end
For this kind of thing, UICollectionView is the best. Exact same delegate as UITableView, just more flexible and configurable. You can have square cells, you can set cell width, you can scroll left or right etc. It is used in the screenshot above, and instagram etc. Here's how to implement it.
In .h :
#interface MyViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
In .m :
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
UICollectionView *myCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 320, 480) collectionViewLayout:flowLayout];
[myCollectionView setDelegate:self];
[myCollectionView setDataSource:self];
[myCollectionView setIndicatorStyle:UIScrollViewIndicatorStyleBlack];
[myCollectionView setScrollIndicatorInsets:UIEdgeInsetsMake(0, 0, 0, -4)];
[myCollectionView setBackgroundColor:[UIColor whiteColor]];
[myCollectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"CustomCell"];
[self.view addSubview:myCollectionView];
Then for the delegate methods:
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
Related
I've a strange behavior with UICollectionView.
In Figure 1 is shown the correct behavior when the user scroll up the collection: the items goes under header view.
[FIGURE 1]
When I reload Items after a search, some items goes over header during scroll.
I've no idea about the cause...
Any ideas or suggestions?
Thanks.
EDIT
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), CGRectGetWidth([UIScreen mainScreen].bounds) * 0.612f);
}
What worked for me is to call reloadData() instead of trying to reload with animation (reloadSections()).
In my case, I had a show/hide button to toggle the number of rows in section between item count and 0 (expand the content of the section).
When I replaced
collectionView?.reloadSections([section])
with
collectionView?.reloadData()
I no longer had the issue.
My working code for UICollectionView along with HeaderView inside UIViewController:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 20;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor blueColor];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(100, 100);
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"header" forIndexPath:indexPath];
return view;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeMake(self.view.frame.size.width, 100);
}
Storyboard:
Output:
Please check this. Hope this will help you in some other way.
You can try to set sectionHeadersPinToVisibleBounds = true property on your UICollectionViewFlowLayout. Because every UICollectionView has own layout.
Apple doc
A Boolean value indicating whether headers pin to the top of the collection view bounds during scrolling.
Maybe it will help. Add this code into viewDidLoad.
(self.yourCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).sectionHeadersPinToVisibleBounds = true
After trying many solutions in my case that works,
collectionView.clipsToBounds = true
How do I implement the layout showed in the image using UICollectionView?
Thanks in advance.
First:
- you have to create a UICollectionReusableView class for section:
ex: ReusableView.h
#interface ReusableView : UICollectionReusableView
#property (weak, nonatomic) IBOutlet UIImageView *headerImage; // example of header content
#end
ReusableView.m
#implementation ReusableView
- (void)awakeFromNib {
// Initialization code
}
#end
-in ReusableView.xib you have to delete the default view and add the UICollectionReusableView from ObjectLibrary and the you add your image or label or whatever and in AttributeInspector on identifier you have to write your IdentifierName (the same things you have to make for cell)
for cell you have to use the UICollectionTableViewCell class and follow the same steps from UICollectionReusableView.
Second:
in ViewController.h you have to use some delegates: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
in ViewController.m you have to use this methods from delegation, but first in viewDidLoad method you have to implement this:
[yourCollectionView registerNib:[UINib nibWithNibName:#"ReusableView" bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"CollectionReusable"]; //collection identifier is: #"CollectionReusable"
[yourCollectionView registerNib: [UINib nibWithNibName:#"CollectionViewCell" bundle:nil] forCellWithReuseIdentifier:#"CollectionCell"];
for section you have to implement this methods from delegate:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
{
return CGSizeZero;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section; // here you return number of sections
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
headerView = nil;
headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"CollectionReusable" forIndexPath:indexPath];
[headerView.headerImage setImage:[UIImage imageNamed:[listOfSymbolsObjects objectAtIndex:indexPath.section]]];
return headerView;
}
-for cells you have to implement this methods from delegates:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
Hope it helps you ! :)
All,
I am adding a UICollectionView to a UIView but it's failing to load cells because it seems that this:
[self.buttonsCollectionView registerNib:[UINib nibWithNibName:#"AccountMenuCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:#"AccountMenuCell"];
Is getting loaded after it hits the delegates for the UICollectionView. Normally this would be placed in viewDidLoad but is not available in a UIView.
- (AccountMenuCollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
AccountMenuCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"AccountMenuCell" forIndexPath:indexPath];
[cell.accountMenuButton setTitle:#"Deposit" forState:UIControlStateNormal];
return cell;
}
Any guidance?
EDIT:
So I am using a view from the storyboard initially and then adding a subview which is Account Menu. Within this view I have a Collection View.
Try to use with the default method and instantiate your Cell inside of the cellForItem...
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
AccountMenuCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"AccountMenuCell" forIndexPath:indexPath];
[cell.accountMenuButton setTitle:#"Deposit" forState:UIControlStateNormal];
return cell;
}
and .. verify with Breakpoints if your code is running..
I am using a UICollectionView to produce a grid of cells say total of 10 i.e. 0-9.
Now, I want to insert a new cell in the grid on click of one of the cells.
so I have added the following line of code [_collectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:10 inSection:0]]]; inside the function didSelectItemAtIndexPath.
So now, if I set indexPathForItem: as 10 (i.e. insert at last) then I get 'Assertion failure' error on this line. If I set `indexPathForItem:' anything between 0-9 then I get 'EXC_BAD_ACCESS...' error on this line.
This is my complete code implementing UICollectionView:
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
_collectionView=[[UICollectionView alloc] initWithFrame:CGRectMake(0, 97.5, self.view.frame.size.width, self.view.frame.size.height-67.5) collectionViewLayout:layout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[_collectionView setBackgroundColor:[UIColor whiteColor]];
[self.view addSubview:_collectionView];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return 35;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.layer.borderWidth=.5f;
cell.layer.borderColor=[UIColor blackColor].CGColor;
if(indexPath.item<31)
{
_dayNumber = [[UILabel alloc] initWithFrame:CGRectMake(30, 30, 15, 15)];
_dayNumber.font = [UIFont systemFontOfSize:12];
_dayNumber.text = [NSString stringWithFormat:#"%ld",(indexPath.item + 1)];
[cell addSubview:_dayNumber];
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout: (UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(self.view.frame.size.width/7, self.view.frame.size.width/7);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout: (UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex: (NSInteger)section
{
return 0.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 0.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout: (UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath
{
[_collectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:0 inSection:0]]];
}
Any help?
Well,
first let's consider this method,
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return 35; // returning constant value means that you can't add or remove cells later
}
so let me change this to
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return self.itemsCount;
}
declare itemsCount property in your class interface, like this
#interface YourClass ()
#property (nonatomic) NSInteger itemsCount;
#end
initialize it in loadView or init method,
_itemsCount = 35; // or whatever you want, initial count
now we can insert/delete items, right ? when we call insertItemAtIndexPaths all we have to do is updating actual data before that call, (for example self.itemsCount++, [self.myItems addObject:newItem] )
here is changes in your code
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
self.itemsCount++; // updating data
[_collectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:0 inSection:0]]];
}
One last important thing, in cellForItemAtIndexPath don't alloc init any kind of view and add as subview on cell, this code every time creates UILabels on cell, if you want custom view on cell (like an imageview, button, etc ..) you should subclass UICollectionViewCell and create this stuff in it's init method, here is how it will look like
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
YourCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
cell.layer.borderWidth = 0.5;
cell.layer.borderColor = [UIColor blackColor].CGColor;
cell.dayNumber.font = [UIFont systemFontOfSize:12];
cell.dayNumber.text = [NSString stringWithFormat:#"%d",(indexPath.row + 1)];
return cell;
}
assuming you also changed this line,
[_collectionView registerClass:[YourCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
note that YourCell is a subclass of UICollectionViewCell and has property dayNumber
Apple has a great guide about collection views. I recommend to read it.
Good luck.
I am trying to add UICollectionViewControllers inside UIView class.
I cant add the controls.
CGRect viewframes=CGRectMake(0,400,self.view.bounds.size.width,
self.view.bounds.size.height/2);
self.button=[[view2 alloc]initWithFrame:viewframes];
self.button.backgroundColor=[UIColor grayColor];
[self.view addSubview:self.button];
Add UICollectionView control to your xib and set outlet of that and also add it's delegate methods UICollectionViewDataSource and UICollectionViewDelegate to .h file .
Add below code to your .m file
#pragma mark Collection View Methods
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(10, 10, 10, 10);
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [urlArray count];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(140, 140);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
GalleryCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.tag=indexPath.row;
return cell;
}
If you are using custom cell and you want to reload Collection view than add below code
[YourCollectionview registerNib:[UINib nibWithNibName:#"GalleryCell" bundle:nil] forCellWithReuseIdentifier:#"cell"];
[YourCollectionview reloadData];