I have a CollectionView. Here is the implementation for my CollectionView.
- (void)setupCollectionView{
self.flowLayout = [[UICollectionViewFlowLayout alloc] init];
[self.flowLayout setSectionInset:UIEdgeInsetsMake(0, 20, 0, 0)];
self.flowLayout.itemSize = CGSizeMake(150, 35);
self.flowLayout.minimumLineSpacing = 20;
[self.flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.vwCollectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, self.vwQuickReplyContainer.frame.size.width, self.vwQuickReplyContainer.frame.size.height) collectionViewLayout:self.flowLayout];
self.vwCollectionView.backgroundColor = [UIColor clearColor];
[self.vwCollectionView registerNib:[UINib nibWithNibName:#"QuickrepliesCell" bundle:nil] forCellWithReuseIdentifier:#"QuickrepliesCell"];
[self.vwQuickReplyContainer addSubview:self.vwCollectionView];
self.vwQuickReplyContainer.hidden = YES;
[self.vwCollectionView setShowsHorizontalScrollIndicator:NO];
[self.vwCollectionView setDataSource:self];
[self.vwCollectionView setDelegate:self];
[self.vwCollectionView reloadData];
}
Here I set the minimumLineSpacing to set the minimum spacing between successive columns. According to this documentation, I understand that value represents the minimum spacing between successive columns for a horizontally scrolling grid. I was also set the space between my cells. Here is the outcomes of doing that .
But to get more looking good. I want to change my cell's width according to its content's size. So I've updated my cell's frame like this.
- (QuickrepliesCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
self.cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"QuickrepliesCell" forIndexPath:indexPath];
QuickReply *model = [[QuickReply alloc]initWithDictionary:self.quickRepliesArr[indexPath.row] error:nil];
self.cell.lblOpion.text = model.title;
CGFloat width = [self.cell.lblOpion.text sizeWithFont:WWLATOREGULAR(15)].width;
self.cell.frame = CGRectMake(self.cell.frame.origin.x, self.cell.frame.origin.y, width + 24, self.cell.frame.size.height);
return self.cell;
}
Here is the outcomes after updating the cell's width..
I don't know the reason why the space between my cells was changed after changing the cell's size. Can anyone advice on this? thanks.
Instead of setting the itemSize property of the layout to fixed size, implement the collectionView:layout:sizeForItemAtIndexPath: layout delegate method.
Then you can set the proper size of each item.
To achieve it, you need to calculate and change item size in collectionView:layout:sizeForItemAtIndexPath:
- (QuickrepliesCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
self.cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"QuickrepliesCell" forIndexPath:indexPath];
QuickReply *model = [[QuickReply alloc]initWithDictionary:self.quickRepliesArr[indexPath.row] error:nil];
self.cell.lblOpion.text = model.title;
return self.cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
QuickReply *model = [[QuickReply alloc]initWithDictionary:self.quickRepliesArr[indexPath.row] error:nil];
CGFloat width = [model.title sizeWithFont:WWLATOREGULAR(15)].width;
return CGSizeMake(width + 24, 35);
}
Related
I am working on a custom keyboard app and have encountered a difficult problem. I have inquired about some documents, but unfortunately did not find the answer. I want to ask everyone to help me.
The problem is this, when I type in the keyboard, the input results will be displayed in the candidate column.I use the UICollectionView to create the candidate column.
- (void)createCandideteColection {
if (!_collectionView) {
CGFloat height = self.frame.size.height-pinyinHeight-lineHeight;
CGFloat y = pinyinHeight+lineHeight;
CGFloat showButtonH = height;
CGFloat candidateShowWidth = self.frame.size.width - showButtonH;
UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flow.minimumInteritemSpacing = 20;
flow.minimumLineSpacing = 20;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, y, candidateShowWidth, height) collectionViewLayout:flow];
_collectionView.backgroundColor = [UIColor whiteColor];
_collectionView.dataSource = self;
_collectionView.delegate = self;
_collectionView.bounces = NO;
_collectionView.showsHorizontalScrollIndicator = NO;
[_collectionView registerClass:[GZCandidateCell class] forCellWithReuseIdentifier:#"candidateCell"];
[self addSubview:_collectionView];
}
}
Sets the frame of the cell, _data changes with the input (each time a text is entered, _data changes once, and [collectionView reloadData] is called once).The width of the cell changes with the number of characters entered.
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
NSString *str = _data[indexPath.row];
CGFloat height = self.frame.size.height-pinyinHeight-lineHeight;
CGFloat width = str.length * 20 + 10;
return CGSizeMake(width, height);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
GZCandidateCell *cell = (GZCandidateCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"candidateCell" forIndexPath:indexPath];
NSString *str = _data[indexPath.row];
[cell setTitleText:str];
return cell;
}
Assign titleLabel value, titleLabel size will be recalculate when calling [cell setTitleText:str].
when [collectionView removeFromSuperview] is called, collectionView will be destroyed,but there is little memory that cannot be released.Every time the input is completed and the collectionView is removed, some memory will not be released and will become a larger number after it is accumulated.
The reason why I will eventually locate this problem on the collectionView is because I don't create this collectionView, the memory does not grow.
Get input data and show on the collectionView,and tabBar is the candidate column I mentioned above:
if (!_textKeyboard) {
_textKeyboard = [[GZQwertyKeyboard alloc] initWithFrame:CGRectMake(0, navigaitonHeight, SCREEN_WIDTH, height) andKeyboardType:type];
_textKeyboard.backgroundColor = Color_background_kb;
[self.view addSubview:_textKeyboard];
}
__weak KeyboardViewController *weakSelf = self;
__weak GZQwerty *getdata = [GZQwerty defaultQwerty]; //init qwerty
_textKeyboard.sendSelectedStr = ^(NSString *text) {
if (!weakSelf.tabBar) {
[weakSelf addCandidateBarView];
}
int asciiCode = [text characterAtIndex:0];
[getdata sendInput:asciiCode complation:^(NSString *compontText, NSArray *candiateArray) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.tabBar changeShowText:candiateArray];
});
}];
};
Call [weakSelf addCandidateBarView] to create the tabBar.Call [weakSelf.tabBar changeShowText:candiateArray] to modify the data source of the collectionView and refresh the collectionView.Like this:
- (void)changeShowText:(NSArray*)textArr {
_data = textArr;
if (!_collectionView) {
[self createCandideteColection];
}
[_collectionView reloadData];
[_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
When the keyboard is typed, if changeShowText: is not called, the memory is stable and there is no memory growth.
So, can anyone help me? Is there a better way than collectionView or how to avoid memory growth?Is it caused by repeated changes to the width of the cell?
For some reason, when I'm on the first page of UICollectionView,
it shows the images from the second page.
And I also noticed that the page isn't centered....
I manually set the
pageControl.numberOfPages = 3
So I have three pages of images.
And each page displays 8 items (well...ideally).
This is in ViewDidLoad:
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
[layout setSectionInset:UIEdgeInsetsMake(10, 10, 15, 10)];
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.collectionView setCollectionViewLayout:layout];
self.collectionView = [[UICollectionView alloc] initWithFrame:keyboardRect collectionViewLayout:layout];
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
self.collectionView.pagingEnabled = true;
self.collectionView.alwaysBounceHorizontal = true;
self.collectionView.contentSize = CGSizeMake(keyboardRect.size.width , keyboardRect.size.height);
self.collectionView.showsHorizontalScrollIndicator = false;
UINib *cellNib = [UINib nibWithNibName:#"TopCell" bundle:nil];
[self.collectionView registerNib:cellNib forCellWithReuseIdentifier:#"cellIdentifier"];
[self.collectionView registerClass:[TopCollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.collectionView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:self.collectionView];
When I tried to increase left and right inset from
[layout setSectionInset:UIEdgeInsetsMake(10, 10, 15, 10)];
It just made things worse. It'd only look okay on the first page,
but then the second and third pages would look off.
And here are some of my code:
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.Images count];
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(70, 70);
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView* )collectionView {
return 3;
}
Thank you in advance!
If you want to show only one section images in each page, then you have to modify
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath method.
You have to return a more generic size.
CGSize returnSize = CGSizeMake(screenWidth / 2 - insets, screenWidth / 2 - insets)
Here inset represents the interItemSpacing for each item. screenWidth is collectionView width.
If you want use the horizontal style of collectionView,you need to custom layout.
Here are some sample code you can use, and I have uploaded custom layout code on github.
FCEmoticonViewLayout *layout = [[FCEmoticonViewLayout alloc]init];
layout.itemSize = CGSizeMake(itemWidht, itemWidht);
layout.itemSpacing = 15;
layout.lineSpacing = 15;
layout.numberOfColumn = 5;
layout.numberOfRow = 2;
self.collectionView.collectionViewLayout = layout;
https://gist.github.com/Heisenbean/a0de38c1379a9d6a83f09ba6cafcb03c
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.
Alright so lets say I have UICollection with 20 cells That scrolls horizontally with paging enabled and can fit 9 cells on each page, when I make it 10 cells instead of creating a second page it moves just enough to fit the 10th cell on the page. I want it to display the 10th cell on its own page when I scroll over.
Also i have tried changing the collectionview.contentsize but for some reason it stays the same no matter what i do.
Here is my code -
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(82, 119);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(20, 10, 50, 10);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
customCell *cell= (customCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
return (UICollectionViewCell*)cell;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 20;
}
- (void)viewDidLoad {
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
_collectionView=[[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[_collectionView setBackgroundColor:[UIColor lightGrayColor]];
[layout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
_collectionView.pagingEnabled = YES;
layout.minimumInteritemSpacing = 15;
layout.minimumLineSpacing = 25;
[_collectionView setContentInset:UIEdgeInsetsMake(65, 0, 0, 0)];
_collectionView.allowsMultipleSelection = YES;
[self.view addSubview:_collectionView];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
You can't force the collection view to completely scroll to a new page like that unfortunately.
Instead, just calculate the number of cells required to fill out the page and add empty ones to the end of your dataset.
For example, if you've got 19 items in your NSArray of data, add another 8 to bring the total up to 27.
In your collectionView:numberOfItemsInSection: delegate, do something like:
return (dataArray.count % 9 == 0) ? dataArray.count : ((dataArray.count/9|0)+1)*9;
// 17 returns 18
// 19 returns 27
Just make sure you perform a contingency operation in cellForItemAtIndexPath to display a blank cell (since your dataset won't actually contain data for that item).
This is a duplicate of this question. I'm asking again because the accepted answer is not working and no one's providing more explanation on how the supposed correct answer works.
So here's the situation: I want to display the collection view into one single row. To do this, I applied a custom UICollectionViewFlowLayout to the collection view and set the scrolling to horizontal. Everything is working fine, except for section header disappeared.
To remedy this, I implemented this function:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeMake(350, 35);
}
Now the header is shown, but the problem is it is displayed to the left of the cells, instead of the usual top.
I stumbled upon the link above while searching for a solution, but like I've said, the accepted answer is not working at all and I could not find other solutions about this situation. So can anyone help me here?
we can do that by using the delegate method -
(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
and keeping the left inset to minus value of width of supplementary view and managing the top inset
Have you tried using the header with something like this?
First: set it up in viewDidLoad...
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.headerReferenceSize = CGSizeMake(self.collectionView.bounds.size.width, 30);
// add any other setup you need
[self.collectionView setCollectionViewLayout:flowLayout];
Second: add header view ...
#define LABEL_TAG 128
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:
UICollectionElementKindSectionHeader withReuseIdentifier:#"SectionHeader" forIndexPath:indexPath];
UILabel *label = (UILabel *)[headerView viewWithTag:LABEL_TAG];
if (!label) {
label = [[UILabel alloc] initWithFrame:CGRectInset(headerView.bounds, 5, 5)];
label.tag = MY_HEADER_LABEL_TAG;
label.font = [UIFont boldSystemFontOfSize:12];
label.textColor = [UIColor redColor];
[headerView addSubview:label];
}
label.text = [NSString stringWithFormat:#"Section %d", indexPath.section];
return headerView;
}