Make UITableViewCell contains a UICollectionView - ios

I got a problem to make uitablveiewcell contains a uicollectionview.The tableview setting is:
_tableViewOfSend = ({
TPKeyboardAvoidingTableView *tableView = [[TPKeyboardAvoidingTableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.backgroundColor = [UIColor whiteColor];
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
tableView.delegate = self;
tableView.dataSource = self;
tableView.estimatedRowHeight = 200;
tableView.rowHeight = UITableViewAutomaticDimension;
[tableView registerClass:[TopicWriteTextCell class] forCellReuseIdentifier:kTextCell];
[tableView registerClass:[TopicWriteImageCell class] forCellReuseIdentifier:kImageCell];
[self.view addSubview:tableView];
tableView;
});
and I added some constraints:
[_tableViewOfSend autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_navBar withOffset:1];
[_tableViewOfSend autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:self.view];
[_tableViewOfSend autoPinEdge:ALEdgeRight toEdge:ALEdgeRight ofView:self.view];
[_tableViewOfSend autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.view];
The tableviewcell also add constrains for self-sizing. In my demo, i just used for presenting images.So i add an UICollectionView in it.
UICollectionViewLeftAlignedLayout *layout = [[UICollectionViewLeftAlignedLayout alloc] init];
layout.minimumLineSpacing = 5;
layout.minimumInteritemSpacing = 5;
CGFloat widthOfScreen = [UIScreen mainScreen].bounds.size.width;
CGFloat cellWidth =(widthOfScreen - 20 - 5 * 2) / 3;
NSLog(#"cell height%f", cellWidth);
layout.itemSize = CGSizeMake(cellWidth, cellWidth);
_imageCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, widthOfScreen, cellWidth*2 + 10) collectionViewLayout:layout];
_imageCollectionView.delegate = self;
_imageCollectionView.dataSource = self;
_imageCollectionView.scrollEnabled = NO;
_imageCollectionView.backgroundColor = [UIColor colorWithRed:0.6 green:1 blue:0.6 alpha:0.5];
[_imageCollectionView registerClass:[TopicWriteImageCCell class] forCellWithReuseIdentifier:kImageCellIndentify];
[self.contentView addSubview:_imageCollectionView];
And the add the constraints for the UICollectionView:
[_imageCollectionView autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.contentView];
[_imageCollectionView autoPinEdge:ALEdgeLeft toEdge:ALEdgeLeft ofView:self.contentView withOffset:10];
[_imageCollectionView autoPinEdge:ALEdgeRight toEdge:ALEdgeRight ofView:self.contentView withOffset:-10];
[_imageCollectionView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.contentView];
I just set the itemsize for a fixed value. The UICollectionViewCell only add a ImageView. and also add the left/top/right/bottom constraints. The item number is 5. In my opinion, I have fixed the itemsize, and add all needed constrains, it should be show 5 items with right height. But there is only 3 items, and the height is not right. It seems the cell didn't self-sizing.
Can anyone help?

Related

UICollectionView: Apply dynamic width for each cell according to UIButton's text width

I know there is a lot similar topics about this problem. Although, I have tried them out first without solving my problem.
As below screenshot showed, I try to apply a horizontal scroll view with UICollectionView. And each cell contains a UIButton with dynamic text length.
The problem is the width for some of cell is wrong/short. I try the solution to get each NSString text size first, then set it in sizeForItemAt delegate method. However it is not working well, the text is still shrinking even I have added a padding value manually CGSize sizeWithPadding = CGSizeMake(size.width + 30, 40).
After quite of hours searching and test, still no idea how to make this right. Please any advice is welcomed.
Data source = NSString array
[NSMutableArray arrayWithObjects:#"All", #"Computer programming", #"Taylor Swift", #"Movies", #"Airplane", #"Basketball", #"Iron man", #"Football", #"ABC", #"Gong Fu", #"Dong Hua", nil]
A UIView as container of the collectionView.
- (void)setViews {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.minimumLineSpacing = CGFLOAT_MAX;
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
self.collectionView.translatesAutoresizingMaskIntoConstraints = false;
self.collectionView.backgroundColor = UIColor.systemBackgroundColor;
_collectionView.dataSource = self;
_collectionView.delegate = self;
[_collectionView registerClass:MenuBarCell.class forCellWithReuseIdentifier:menuBarCellID];
[self addSubview:self.collectionView];
[self.collectionView.topAnchor constraintEqualToAnchor:self.topAnchor].active = true;
[self.collectionView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor].active = true;
[self.collectionView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor].active = true;
[self.collectionView.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = true;
}
# pragma mark - collectionView dataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _menuBarArray.count;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MenuBarCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:menuBarCellID forIndexPath:indexPath];
NSString *model = _menuBarArray[indexPath.item];
[cell configure:model];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size = [self.menuBarArray[indexPath.item] sizeWithAttributes:NULL];
NSLog(#"size: width = %f", size.width);
CGSize sizeWithPadding = CGSizeMake(size.width + 30, 40);
return sizeWithPadding;
}
My UICollectionView custom cell
- (void)setViews {
[super setViews];
self.contentView.backgroundColor = UIColor.systemYellowColor;
// create buttons
_button = [UIButton buttonWithType:UIButtonTypeCustom];
_button.translatesAutoresizingMaskIntoConstraints = false;
_button.layer.cornerRadius = 15;
_button.layer.masksToBounds = true;
[_button setBackgroundColor:[UIColor colorWithWhite:0.92 alpha:1]];
[_button setTitleColor:UIColor.labelColor forState:UIControlStateNormal];
[_button setTitleColor:UIColor.buttonTitleHighlighted forState:UIControlStateHighlighted];
[self.contentView addSubview:_button];
// set constraints
[_button.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor].active = true;
[_button.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor].active = true;
[_button.widthAnchor constraintEqualToAnchor:self.contentView.widthAnchor].active = true;
[_button.heightAnchor constraintLessThanOrEqualToAnchor:self.contentView.heightAnchor].active = true;
}
- (void)configure: (NSString *)model {
[_button setTitle:model forState:UIControlStateNormal];
}
Few things wrong...
Get rid of sizeForItemAtIndexPath method -- you want to use auto-sizing cells.
Next, you don't show your code for constraining the "container" view, but I assume it's something like this:
- (void)viewDidLoad {
[super viewDidLoad];
menuBarView = [MenuBarView new];
menuBarView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:menuBarView];
UILayoutGuide *g = [self.view safeAreaLayoutGuide];
[NSLayoutConstraint activateConstraints:#[
[menuBarView.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0],
[menuBarView.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],
[menuBarView.topAnchor constraintEqualToAnchor:g.topAnchor constant:4.0],
[menuBarView.heightAnchor constraintEqualToConstant:42.0],
]];
}
Your UICollectionViewFlowLayout should be along these lines:
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
// spacing between cells
layout.minimumLineSpacing = 8.0;
// prevents last cell from being cut-off
layout.minimumInteritemSpacing = layout.minimumLineSpacing;
// must have an estimated size
// inconsequential, but needs to be less than expectd
layout.estimatedItemSize = CGSizeMake(10, 10);
And configure your cell class like this:
// I don't know what your super-class is...
//[super setViews];
self.contentView.backgroundColor = UIColor.systemYellowColor;
// create buttons
_button = [UIButton buttonWithType:UIButtonTypeCustom];
_button.translatesAutoresizingMaskIntoConstraints = false;
_button.layer.cornerRadius = 15;
_button.layer.masksToBounds = true;
// give the button a little top / leading / bottom / trailing "padding"
_button.contentEdgeInsets = UIEdgeInsetsMake(8, 20, 8, 20);
[_button setBackgroundColor:[UIColor colorWithWhite:0.92 alpha:1]];
[_button setTitleColor:UIColor.labelColor forState:UIControlStateNormal];
[_button setTitleColor:UIColor.whiteColor forState:UIControlStateHighlighted];
[self.contentView addSubview:_button];
// set constraints
UIView *g = self.contentView;
[NSLayoutConstraint activateConstraints:#[
[_button.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0],
[_button.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],
[_button.topAnchor constraintEqualToAnchor:g.topAnchor constant:2.0],
[_button.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:-2.0],
]];
Result should look like this (I gave the "container" view a blue background so we can see it):

auto-sizing UICollectionView in UITableView with pure code

I am trying to create one UITableView with header and UITableViewCell header is fixed size. and in each UITableViewCell I will create one UICollectionView. the UICollectionViewCell height is not fixed. so Here I want UICollectionViewCell is auto-sizing in UICollectionView and UICollectionView is auto-sizing in UITableViewCell.
But The height is not auto-sizing after implementation. Could you help me on this.
TableView init:
- (UITableView *)tableView
{
if (_tableView == nil) {
CGFloat top = 20;
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
_tableView.delegate = self;
_tableView.separatorStyle = 0;
_tableView.dataSource = self;
_tableView.estimatedRowHeight = 200;
_tableView.sectionHeaderHeight = 40;
_tableView.rowHeight = UITableViewAutomaticDimension;
_tableView.backgroundColor = [UIColor whiteColor];
}
return _tableView;
}
UICollectionView in UITableViewCell Init:
_collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:flowLayout];
_collectionView.delegate = self;
_collectionView.dataSource = self;
_collectionView.bounces = NO;
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.showsVerticalScrollIndicator = NO;
_collectionView.backgroundColor = [UIColor whiteColor];
_collectionView.translatesAutoresizingMaskIntoConstraints = NO;
[_collectionView registerClass:[KCollectionViewCell class] forCellWithReuseIdentifier:#"KCollectionViewCell"];
[self.contentView addSubview:_collectionView];
[_collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.bottom.equalTo(self.contentView);
make.left.equalTo(self.contentView).offset(20);
make.right.equalTo(self.contentView).offset(-20);
}];
UICollectionViewCell init:
-(void)initUI{
self.label = [[UILabel alloc] init];
self.label.text = #"aaaaaaaaaaaaaaaa";
self.label.textColor = XUIColorMain;
self.label.textAlignment = NSTextAlignmentCenter;
self.label.layer.borderColor =[UIColor orangeColor].CGColor;
self.label.clipsToBounds = YES;
[self.label sizeToFit];
}
- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
UICollectionViewLayoutAttributes *attributes = [super preferredLayoutAttributesFittingAttributes:layoutAttributes];
CGRect frame = [self.label.text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 30) options:(NSStringDrawingUsesLineFragmentOrigin) attributes:[NSDictionary dictionaryWithObjectsAndKeys:self.label.font,NSFontAttributeName, nil] context:nil];
frame.size.width += 10;
frame.size.height = 30;
attributes.frame = frame;
return attributes;
}

cellForRowAtIndexPath and sizeToFit reduces label width when scrolling

I've a custom cell with labels init in a UITableViewCell.
In my cellForRowAtIndexPath method after setting label content i call sizeToFit on the label to get the correct width and height, but when i scroll in my TableView, the label width reduce on each cells, every time i scroll.
Anyone for help ?
Thanks
My custom UITableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
CGRect viewBounds = self.contentView.bounds;
// marge
CGFloat margin = 20;
self.excuse_date = [[UILabel alloc] initWithFrame:CGRectMake(5, 10, 300, 30)];
self.excuse_date.textColor = [UIColor blackColor];
self.excuse_date.font = [UIFont fontWithName:#"Arial" size:12.0f];
[self addSubview:self.excuse_date];
static CGFloat dateWidth = 130;
self.excuse_date.frame = CGRectMake(viewBounds.size.width-dateWidth-35, margin, dateWidth, 20);
CGRect dateFrame = self.excuse_date.frame;
self.excuse_date.textAlignment = NSTextAlignmentRight;
// setup excuse_auteur
self.excuse_auteur = [[UILabel alloc] init];
self.excuse_auteur.font = [UIFont fontWithName:#"Helvetica" size:13];
self.excuse_auteur.textColor = [UIColor darkGrayColor];
self.excuse_auteur.textAlignment = NSTextAlignmentLeft;
self.excuse_auteur.frame = CGRectMake(margin, margin, viewBounds.size.width-dateWidth-(margin*2), 20);
[self addSubview:self.excuse_auteur];
// setup excuse_texte
self.excuse_texte = [[UILabel alloc] initWithFrame:CGRectMake(20, CGRectGetMaxY(dateFrame)+margin/2, viewBounds.size.width - (margin*3), 200)];
self.excuse_texte.lineBreakMode = NSLineBreakByWordWrapping;
self.excuse_texte.numberOfLines = 0;
self.excuse_texte.font = [UIFont fontWithName:#"Helvetica" size:17];
self.excuse_texte.autoresizingMask = UIViewAutoresizingNone;
[self addSubview:self.excuse_texte];
CGRect textFrame = self.excuse_texte.frame;
// setup up image
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"up-small"]];
self.img = imageView;
[self addSubview:self.img];
imageView.frame = CGRectMake(20, CGRectGetMaxY(textFrame)+margin/2, 20, 20);
// setup up
self.up = [[UILabel alloc] initWithFrame:CGRectMake(45, CGRectGetMaxY(textFrame)+margin/2+2, viewBounds.size.width - margin*2, 20)];
self.up.font = [UIFont fontWithName:#"Helvetica" size:11];
self.up.textColor = [UIColor darkGrayColor];
self.up.textAlignment = NSTextAlignmentLeft;
[self addSubview:self.up];
}
return self;
}
My cellForRowAtIndexPath method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
BBExcuse *excuse = [self.list objectAtIndex:indexPath.row];
static NSString *cellIdentifier = #"Cell";
// Similar to UITableViewCell, but
BBTableViewCell *cell = (BBTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[BBTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.excuse_texte.text = excuse.excuse_texte;
// #TODO problem here ?
[cell.excuse_texte sizeToFit];
cell.excuse_auteur.text = excuse.excuse_auteur;
cell.excuse_date.text = excuse.excuse_date;
cell.up.text = [NSString stringWithFormat:#"%#", excuse.up];
cell.img.frame = CGRectMake(20, CGRectGetMaxY(cell.excuse_texte.frame)+20/2, 20, 20);
cell.up.frame = CGRectMake(45, CGRectGetMaxY(cell.excuse_texte.frame)+20/2+2, 20, 20);
// setup up
return cell;
}
Ok solved by removing sizeToFit and specify height and width in cellForRowAtIndexPath
cell.excuse_texte.text = excuse.excuse_texte;
NSString *str = excuse.excuse_texte;
UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont systemFontOfSize:17];
gettingSizeLabel.text = str;
gettingSizeLabel.numberOfLines = 0;
gettingSizeLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(260.0f, 9999.0f);
CGSize theSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];
// on resize sans sizetofit
cell.excuse_texte.frame = CGRectMake(cell.excuse_texte.frame.origin.x, cell.excuse_texte.frame.origin.y, cell.excuse_texte.frame.size.width, theSize.height);

Row height of the uitableview in differing gradually

I have two uitableviews in a view controller. First table is set on a uiscrollview programatically and the other table on self.view from storyboard. I have set the rowHeight for both the table as 45. But gradually the height of one table keeps increasing as the rows increase like the screenshot I have shown.
Code goes like this :
scrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(130, 45, self.view.frame.size.width-130, self.view.frame.size.height-45)];
scrollview.backgroundColor = [UIColor colorWithRed:0.42 green:0.27 blue:0.60 alpha:1.0];
tableGradeValue = [[UITableView alloc] initWithFrame:CGRectMake(0, 35, self.view.frame.size.width, self.view.frame.size.height-75) style:UITableViewStylePlain];
tableGradeValue.delegate = self;
tableGradeValue.dataSource = self;
self.tableCourse.delegate = self;
self.tableCourse.dataSource = self;
tableGradeValue.rowHeight = 45;
scrollview.bounces = NO;
for(int i = 0; i< [res6Keys count]; i++)
{
CGFloat y = i * 150;
UILabel *lblCell = [[UILabel alloc] initWithFrame:CGRectMake(y, 1, 140, 31)];
lblCell.tag = i+1;
[scrollview addSubview:lblCell];
lblCell.backgroundColor = [UIColor clearColor];
lblCell.textColor = [UIColor colorWithRed:0.93 green:0.92 blue:0.96 alpha:1.0];
lblCell.text = [res6Keys objectAtIndex:i];
}
[scrollview addSubview:tableGradeValue];
scrollview.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:scrollview];
And the other tableview is set from storyboard normally and the rowHeight is 45.
I don't know wether this was the problem. But strangely I got the answer. I dint give #property and #synthesis to the table which was over the scrollview. I now gave property and synthesis and it got working.

Adding uiTextView before uiScrollView

I want the textview to be before the scrollview inside my tablecell like this, so that the scrollview scrolls and the titles stays put.
[Title goes here] - it does not move with the scrollview
---------------------
| |
| ScrollView |
| |
---------------------
This is my code, the textView appears behind the scrollview.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MainCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MainCell"];
}
NSInteger numberOfViews = 10;
UIScrollView *vwScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 1280, 200)];
for (int i = 0; i < numberOfViews; i++) {
CGFloat xOrigin = i * 250;
UITextView *titleView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 1280, 20)];
titleView.text = #"Title";
[titleView setFont:[UIFont fontWithName:#"HelveticaBold" size:32]];
UIView *awesomeView = [[UIView alloc] initWithFrame:CGRectMake(xOrigin, 0, 250, 180)];
awesomeView.backgroundColor = [UIColor colorWithRed:0.5/i green:0.5/i/10 blue:0.5 alpha:1];
[awesomeView.layer setBorderColor:[UIColor whiteColor].CGColor];
[awesomeView.layer setBorderWidth:10.5f];
awesomeView.layer.shadowPath = [UIBezierPath bezierPathWithRect:awesomeView.bounds].CGPath;
[cell.contentView addSubview:titleView];
[vwScroll addSubview:awesomeView];
}
vwScroll.contentSize = CGSizeMake(250 * numberOfViews, 200);
[cell.contentView addSubview:vwScroll];
return cell;
}
Why cant you just set the frame of your titleView to, say, (0,0,width,titleHeight) and then set the frame of your scrollView to (0,titleHeight,width,cellHeight-titleHeight).
This will just place the title at the top part of the cell, setting it's height to whatever you make titleHeight to be, and will put the scrollView at the bottom part of the cell, setting it's height to the rest of the cell.

Resources