I have a lot of section and items. When I touch button in cell it create cell with 4 items in 1 cell (like expanded table) touch again cell disappear.
I found WaterfallCollectionView and there I can change height of items.
What is the best way to achieve this???
Structure like:
----- -----
| +| | +| and other rows
| | | |
----- -----
When I touch my button (+) it should be like:
----- ----- -----
| -| |__|__| | +|
| | | | | | |
----- ----- -----
A new cell create with 4 UIImageView's inside 1 cell ( if 4 elements in 1 cell, if more create more cell). If 1 element create this cell but image will be in the top left corner.
Where in cells should be my info (like expanded table)
Is it better to create different type of cells?
I tried something out where a UICollectionViewCell is made to expand by changing its own size. The new 'cells' that pop out when you tap on a cell are not really new cells, but subviews of the original cell. Essentially it works something like this:
Use UICollectionView with a UICollectionViewFlowLayout.
The UICollectionView's delegate conforms to UICollectionViewDelegateFlowLayout and implements -collectionView:layout:sizeForItemAtIndexPath: to recognize unique cell sizes.
The UICollectionView's delegate implements -collectionView:didSelectCellAtIndexPath: where it adjusts the cell's size to reveal or hide the subviews that look like new cells.
A custom object representing the cell's contents and a custom UICollectionViewCell subclass are used to make it easier to perform and keep track of expansion.
I created an example project here which has a cells that expand to show a number's divisors. It looks something like this:
The project is pretty rough and uncommented, and the transition happens without animation, but if you find this approach interesting and cannot follow the code I can clean it up a bit.
And here's the code dump...
CollectionViewController.h
#import <UIKit/UIKit.h>
#interface CollectionViewController : UIViewController
#end
CollectionViewController.m
#import "CollectionViewController.h"
#import "CellDataItem.h"
#import "CollectionViewCell.h"
#interface CollectionViewController () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
#property (strong, nonatomic) UICollectionView *collectionView;
#property (strong, nonatomic) NSMutableArray *cellData;
#end
NSString *const kCollectionViewCellIdentifier = #"Cell";
#implementation CollectionViewController
- (NSMutableArray *)cellData
{
if (!_cellData) {
NSInteger countValues = 20;
_cellData = [[NSMutableArray alloc] initWithCapacity:countValues];
for (NSInteger i = 0; i < countValues; i++) {
CellDataItem *item = [[CellDataItem alloc] init];
item.number = #(arc4random() % 100);
[_cellData addObject:item];
}
}
return _cellData;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor grayColor];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = [CollectionViewCell sizeWithDataItem:nil];
layout.minimumInteritemSpacing = [CollectionViewCell margin];
layout.minimumLineSpacing = layout.minimumInteritemSpacing;
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero
collectionViewLayout:layout];
_collectionView.backgroundColor = [UIColor darkGrayColor];
_collectionView.dataSource = self;
_collectionView.delegate = self;
[self.view addSubview:_collectionView];
[_collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:kCollectionViewCellIdentifier];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
self.collectionView.frame = CGRectMake(0.0f, 0.0f, self.view.bounds.size.width, layout.itemSize.height);
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.cellData.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCollectionViewCellIdentifier
forIndexPath:indexPath];
cell.dataItem = [self.cellData objectAtIndex:indexPath.row];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return [CollectionViewCell sizeWithDataItem:[self.cellData objectAtIndex:indexPath.row]];
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell *cell = (CollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
[cell toggleExpansion];
[collectionView reloadData];
}
#end
#import <Foundation/Foundation.h>
#interface CellDataItem : NSObject
#property (strong, nonatomic) NSNumber *number;
#property (nonatomic, readonly) NSArray *divisors;
#property (nonatomic, getter = isExpanded) BOOL expanded;
#end
CellDataItem.m
#import "CellDataItem.h"
#interface CellDataItem ()
#property (strong, nonatomic) NSArray *divisors;
#end
#implementation CellDataItem
+ (NSArray *)divisorsForNumber:(NSNumber *)number
{
NSMutableArray *divisors = [NSMutableArray arrayWithObjects:#(1), number, nil];
float root = pow(number.doubleValue, 0.5);
if (root == roundf(root)) {
[divisors addObject:[NSNumber numberWithInteger:(NSInteger)root]];
}
NSInteger maxDivisor = (NSInteger)root;
for (NSInteger divisor = 2; divisor < maxDivisor; divisor++) {
float quotient = number.floatValue / (float)divisor;
if (quotient == roundf(quotient)) {
[divisors addObject:[NSNumber numberWithInteger:divisor]];
[divisors addObject:[NSNumber numberWithInteger:(NSInteger)quotient]];
}
}
return [divisors sortedArrayUsingSelector:#selector(compare:)];
}
- (void)setNumber:(NSNumber *)number
{
if (_number == number) {
return;
}
_number = number;
self.divisors = [self.class divisorsForNumber:_number];
}
#end
CollectionViewCell.h
#import <UIKit/UIKit.h>
#class CellDataItem;
#interface CollectionViewCell : UICollectionViewCell
+ (CGFloat)margin;
+ (CGSize)sizeWithDataItem:(CellDataItem *)dataItem;
#property (strong, nonatomic) CellDataItem *dataItem;
- (void)toggleExpansion;
#end
#interface ChildView : UIView
- (UILabel *)labelAtIndex:(NSInteger)index;
- (void)clearLabels;
#end
CollectionViewCell.m
#import "CollectionViewCell.h"
#import <QuartzCore/QuartzCore.h>
#import "CellDataItem.h"
#interface CollectionViewCell ()
#property (strong, nonatomic) NSMutableArray *childViews;
#property (strong, nonatomic) UILabel *numberLabel;
#end
NSInteger const kCollectionViewCellSplitCount = 4;
CGFloat const kCollectionViewCellMargin = 20.0f;
CGSize const kCollectionViewCellDefaultSize = {200.0f, 200.0f};
#implementation CollectionViewCell
+ (CGFloat)margin
{
return kCollectionViewCellMargin;
}
+ (CGSize)sizeWithDataItem:(CellDataItem *)dataItem
{
if (dataItem && dataItem.isExpanded) {
CGSize size = kCollectionViewCellDefaultSize;
NSInteger childViewsRequired = [self childViewsRequiredForDataItem:dataItem];
size.width += childViewsRequired * ([self margin] + size.width);
return size;
} else {
return kCollectionViewCellDefaultSize;
}
}
+ (NSInteger)childViewsRequiredForDataItem:(CellDataItem *)dataItem
{
return (NSInteger)ceilf((float)dataItem.divisors.count / (float)kCollectionViewCellSplitCount);
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_numberLabel = [[UILabel alloc] init];
_numberLabel.textAlignment = NSTextAlignmentCenter;
_numberLabel.layer.borderColor = [UIColor blackColor].CGColor;
_numberLabel.layer.borderWidth = 1.0f;
_numberLabel.backgroundColor = [UIColor whiteColor];
[self.contentView addSubview:_numberLabel];
}
return self;
}
- (void)setDataItem:(CellDataItem *)dataItem
{
if (_dataItem == dataItem) {
return;
}
_dataItem = dataItem;
self.numberLabel.text = [NSString stringWithFormat:#"%i", dataItem.number.integerValue];
if (!dataItem.expanded) {
[self collapse];
} else if (dataItem.expanded) {
[self expand];
}
}
- (void)collapse
{
for (ChildView *view in self.childViews) {
view.hidden = YES;
}
}
- (void)expand
{
NSInteger childViewsRequired = [self.class childViewsRequiredForDataItem:self.dataItem];
while (self.childViews.count < childViewsRequired) {
ChildView *childView = [[ChildView alloc] init];
[self.childViews addObject:childView];
[self.contentView addSubview:childView];
}
NSInteger index = 0;
for (ChildView *view in self.childViews) {
view.hidden = !(index < childViewsRequired);
if (!view.hidden) {
[view clearLabels];
}
index++;
}
for (NSInteger i = 0; i < self.dataItem.divisors.count; i++) {
NSInteger labelsPerChild = 4;
NSInteger childIndex = i / labelsPerChild;
NSInteger labelIndex = i % labelsPerChild;
[[[self.childViews objectAtIndex:childIndex] labelAtIndex:labelIndex] setText:[NSString stringWithFormat:#"%i", [[self.dataItem.divisors objectAtIndex:i] integerValue]]];
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat const unitWidth = kCollectionViewCellDefaultSize.width;
CGFloat const unitHeight = kCollectionViewCellDefaultSize.height;
CGFloat const margin = [self.class margin];
self.numberLabel.frame = CGRectMake(0.0f, 0.0f, unitWidth, unitHeight);
for (NSInteger i = 0; i < self.childViews.count; i++) {
ChildView *view = [self.childViews objectAtIndex:i];
view.frame = CGRectMake((i + 1) * (margin + unitWidth), 0.0f, unitWidth, unitHeight);
}
}
- (NSMutableArray *)childViews
{
if (!_childViews) {
_childViews = [[NSMutableArray alloc] init];
}
return _childViews;
}
- (void)toggleExpansion
{
self.dataItem.expanded = !self.dataItem.isExpanded;
if (self.dataItem.isExpanded) {
[self expand];
} else {
[self collapse];
}
}
#end
#interface ChildView ()
#property (strong, nonatomic) NSMutableArray *labels;
#end
#implementation ChildView
- (id)init
{
if ((self = [super init])) {
self.backgroundColor = [UIColor lightGrayColor];
}
return self;
}
- (UILabel *)labelAtIndex:(NSInteger)index
{
if (!self.labels) {
self.labels = [NSMutableArray array];
}
while (self.labels.count <= index) {
UILabel *label = [[UILabel alloc] init];
label.textAlignment = NSTextAlignmentCenter;
label.layer.borderColor = [UIColor blackColor].CGColor;
label.layer.borderWidth = 1.0f;
[self.labels addObject:label];
[self addSubview:label];
}
return [self.labels objectAtIndex:index];
}
- (void)clearLabels
{
for (UILabel *label in self.labels) {
label.text = nil;
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat labelWidth = self.bounds.size.width * 0.5f;
CGFloat labelHeight = self.bounds.size.height * 0.5f;
for (NSInteger i = 0; i < self.labels.count; i++) {
UILabel *label = [self.labels objectAtIndex:i];
NSInteger x = i % 2;
NSInteger y = i / 2;
label.frame = CGRectMake(x * labelWidth, y * labelHeight, labelWidth, labelHeight);
}
}
#end
If you want expandable cells you have to insert the new cells inside the collection view by calling insertItemsAtIndexPaths: on your collection view.
It is not trivial as you have to shift all your index paths, update the number of items in the section to reflect the newly added cells, etc. If you are looking for something simple then the Waterfall example is good. If you want a more complex / configurable solution then you have to rock your own custom layout. That's what I did.
Related
I want to make an animation that when you scroll the tabbar, the indicator view follow and when it touch on the text of the tab, that text change color only the part it being touched.
Example like in the picture below.
How can I achieve this ? I have been racking my brain the whole day and no solution come to mind.
https://i.stack.imgur.com/ZrkZy.png
[PageCollectionViewCell.h]//You can change this cell with your favorite style.
#interface PageCollectionViewCell : UICollectionViewCell
/**
title Label
*/
#property (nonatomic, strong) UILabel *pageLabel;
/**
itemWidth
*/
#property (nonatomic, assign) CGFloat itemWidth;
#end
[PageCollectionViewCell.m]
#import "PageCollectionViewCell.h"
#interface PageCollectionViewCell ()
/**
title lab Margin
*/
#property (nonatomic, assign) CGFloat inset;
/**
border color
*/
#property (nonatomic, strong) UIColor *hexColor;
#end
#implementation PageCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.inset = 5;
self.hexColor = [UIColor orangeColor];
[self configSubView];
}
return self;
}
- (void)configSubView {
UILabel *pageLabel = [[UILabel alloc] init];
[pageLabel setTextColor:self.hexColor];
pageLabel.layer.borderColor = self.hexColor.CGColor;
pageLabel.layer.borderWidth = 2;
[pageLabel setTextAlignment:NSTextAlignmentCenter];
pageLabel.clipsToBounds = YES;
[self addSubview:pageLabel];
self.pageLabel = pageLabel;
[pageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self).insets(UIEdgeInsetsMake(self.inset, self.inset, self.inset, self.inset));
}];
self.pageLabel = pageLabel;
}
#pragma mark - set selected status
- (void)setSelected:(BOOL)isSelected {
[self.pageLabel setTextColor:isSelected ? UIColor.whiteColor : self.hexColor];
self.pageLabel.backgroundColor = isSelected ? self.hexColor : UIColor.clearColor;
}
- (void)setItemWidth:(CGFloat)itemWidth {
self.pageLabel.layer.cornerRadius = (itemWidth - 2 * self.inset) / 2;
}
#end
[ViewViewController.m]
#import "ViewViewController.h"
#import "PageCollectionViewCell.h"
static NSString *kCellID = #"cellID";
#interface ViewViewController ()<UICollectionViewDelegate, UICollectionViewDataSource>
#property (nonatomic, strong) NSArray *arr;//page color
#property (nonatomic, strong) UICollectionView *pageCollectionView;
#property (nonatomic, assign) CGFloat itemWidth;//itemWidth
#property (nonatomic, strong) UIScrollView *pageScrollView;
#end
#implementation ViewViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
self.itemWidth = 40;
self.arr = [NSArray arrayWithObjects:[UIColor blueColor],[UIColor redColor],[UIColor yellowColor],[UIColor orangeColor],[UIColor greenColor], nil];
[self configNavigationBar];
[self configPageView];
}
- (void)configNavigationBar {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.itemSize = CGSizeMake(self.itemWidth, self.itemWidth);
flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
flowLayout.minimumLineSpacing = 0;
UICollectionView *pageCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.itemWidth * self.arr.count, NavigationBar_Height) collectionViewLayout:flowLayout];
pageCollectionView.dataSource = self;
pageCollectionView.delegate = self;
pageCollectionView.backgroundColor = UIColor.clearColor;
[pageCollectionView registerClass:[PageCollectionViewCell class] forCellWithReuseIdentifier:kCellID];
self.navigationItem.titleView = pageCollectionView;
NSIndexPath *firstIndexpath = [NSIndexPath indexPathForItem:0 inSection:0];
[pageCollectionView selectItemAtIndexPath:firstIndexpath animated:YES scrollPosition:UICollectionViewScrollPositionBottom];
self.pageCollectionView = pageCollectionView;
}
- (void)configPageView {
//define in pch file
CGFloat navigationBar_height = self.navigationController.navigationBar.frame.size.height;
CGFloat statusBar_height = [UIApplication sharedApplication].statusBarFrame.size.height;
CGFloat homeIndicator_Height = (statusBar_height > 20.0 ? 34.0 : 0.0);
CGFloat screen_width = self.view.frame.size.width;
UIScrollView *pageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, navigationBar_height + statusBar_height, screen_width, self.view.frame.size.height - navigationBar_height - statusBar_height - homeIndicator_Height)];
pageScrollView.pagingEnabled = YES;
pageScrollView.delegate = self;
pageScrollView.showsVerticalScrollIndicator = NO;
pageScrollView.showsHorizontalScrollIndicator = NO;
pageScrollView.contentSize = CGSizeMake(screen_width * self.arr.count, 0);
[self.view addSubview:pageScrollView];
self.pageScrollView = pageScrollView;
for (NSInteger index = 0; index < self.arr.count; index++) {
UIView *pageView = [[UIView alloc] initWithFrame:CGRectMake(index * self.pageScrollView.frame.size.width, 0, self.pageScrollView.frame.size.width, self.pageScrollView.frame.size.height)];
pageView.backgroundColor = self.arr[index];
[self.pageScrollView addSubview:pageView];
}
}
#pragma mark - UICollectionViewDelegate, UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.arr.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PageCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
cell.pageLabel.text = [NSString stringWithFormat:#"%ld", (long)indexPath.item + 1];
cell.itemWidth = self.itemWidth;
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
CGFloat screen_width = self.view.frame.size.width;
[self.pageScrollView setContentOffset:CGPointMake(indexPath.item * screen_width, 0) animated:YES];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (!scrollView.isDragging && !scrollView.isDecelerating) {
return;
}
CGFloat screen_width = self.view.frame.size.width;
NSIndexPath *currentIndexpath = [NSIndexPath indexPathForItem:((scrollView.contentOffset.x - screen_width / 2) / screen_width) + 1 inSection:0];
[self.pageCollectionView selectItemAtIndexPath:currentIndexpath animated:YES scrollPosition:UICollectionViewScrollPositionBottom];
}
#end
i am doing feedback form using UITableview in that using custom checkbox for selection.In a UITableviewcell i placed four static buttons for options like,Very
Good,Good,Average,Below Average.
What i want is,i want to select only one button checked in a row, if i select another button checked automatically previous selected button should be unchecked.
Example: In same row suppose if i select Very Good first again i selected Average , previous selected Very Good should be unchecked.
Check My code Below for reference:
This is in cellforrowatindexpath
[cell.R1_BTN setImage:[UIImage imageNamed:#"Touch_G.png"] forState:UIControlStateNormal];
[cell.R1_BTN addTarget:self action:#selector(BtnClicked:) forControlEvents:UIControlEventTouchUpInside];
cell.R1_BTN.tag=1;
Click event here..
-(void)BtnClicked:(id)sender
{
//Need Code Here..
}
updated code for reference..
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [GNM count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [GNM objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([[NM objectAtIndex:section] isKindOfClass:[NSArray class]])
{
return [[NM objectAtIndex:section] count];
}
else
{
return 1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
FeedBackFormTVC *cell = [FeedBack_TV dequeueReusableCellWithIdentifier:#"ListCell" forIndexPath:indexPath];
cell.FBName_LBL.text = [[NM objectAtIndex:indexPath.section] isKindOfClass:[NSArray class]]
? [[NM objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]
: [NM objectAtIndex:indexPath.section];
// below for assigning code action event..
....
....
...
}
I tried using Tags,but i didn't get what i want, pls help me.. thanks in Advance.
I think that you should use model to set for UITableViewCell. Your model's .h file like :
#import <Foundation/Foundation.h>
typedef enum : NSInteger {
UNKNOWN = 0,
VERY_GOOD = 1,
GOOD = 2,
AVERAGE = 3,
BELOW_AVERAGE = 4
}RangeMark;
#interface CellModel : NSObject
#property(nonatomic, assign) RangeMark range;
#end
.m file like:
#import "CellModel.h"
#implementation CellModel
#end
than you should init a table cell with .xib file looks like:
and its .h file like :
#import <UIKit/UIKit.h>
#import "CellModel.h"
#interface TableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *veryGoodButton;
#property (weak, nonatomic) IBOutlet UIButton *goodButton;
#property (weak, nonatomic) IBOutlet UIButton *averageButton;
#property (weak, nonatomic) IBOutlet UIButton *belowAverageButton;
- (void)setupCellWithModel:(CellModel*)model;
#end
its .m file like :
#import "TableViewCell.h"
#implementation TableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)setupCellWithModel:(CellModel *)model {
if(model.range == VERY_GOOD) {
self.veryGoodButton.backgroundColor = [UIColor greenColor];
}
else if(model.range == GOOD) {
self.goodButton.backgroundColor = [UIColor blueColor];
}
else if(model.range == AVERAGE) {
self.averageButton.backgroundColor = [UIColor yellowColor];
}
else if(model.range == BELOW_AVERAGE) {
self.belowAverageButton.backgroundColor = [UIColor redColor];
}
}
- (void)prepareForReuse {
[super prepareForReuse];
self.veryGoodButton.backgroundColor = [UIColor lightGrayColor];
self.goodButton.backgroundColor = [UIColor lightGrayColor];
self.averageButton.backgroundColor = [UIColor lightGrayColor];
self.belowAverageButton.backgroundColor = [UIColor lightGrayColor];
}
#end
Finally your view controller .h file should look like :
#import <UIKit/UIKit.h>
#import "TableViewCell.h"
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
and .m file should look like :
#import "ViewController.h"
#interface ViewController () <UITableViewDelegate, UITableViewDataSource>{
NSMutableArray<CellModel*> *modelList;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 600;
self.tableView.rowHeight = UITableViewAutomaticDimension;
modelList = [NSMutableArray<CellModel*> new];
for (int i=0; i<50; i++) {
CellModel *cellModel = [[CellModel alloc] init];
cellModel.range = UNKNOWN;
[modelList addObject:cellModel];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
TableViewCell *cell = (TableViewCell*)[tableView dequeueReusableCellWithIdentifier:#"TableViewCell"];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
[cell setupCellWithModel:[modelList objectAtIndex:indexPath.row]];
cell.veryGoodButton.tag = indexPath.row;
cell.goodButton.tag = indexPath.row;
cell.averageButton.tag = indexPath.row;
cell.belowAverageButton.tag = indexPath.row;
[cell.veryGoodButton addTarget:self action:#selector(veryGood:) forControlEvents:UIControlEventTouchUpInside];
[cell.goodButton addTarget:self action:#selector(good:) forControlEvents:UIControlEventTouchUpInside];
[cell.averageButton addTarget:self action:#selector(average:) forControlEvents:UIControlEventTouchUpInside];
[cell.belowAverageButton addTarget:self action:#selector(belowAverage:) forControlEvents:UIControlEventTouchUpInside];
return cell;
return nil;
}
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return modelList.count;
}
- (void) veryGood:(UIButton*)sender {
[modelList objectAtIndex: sender.tag].range = VERY_GOOD;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.tag inSection:0] withCellModel:[modelList objectAtIndex: sender.tag]];
}
- (void) good:(UIButton*)sender {
[modelList objectAtIndex: sender.tag].range = GOOD;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.tag inSection:0] withCellModel:[modelList objectAtIndex: sender.tag]];
}
- (void) average:(UIButton*)sender {
[modelList objectAtIndex: sender.tag].range = AVERAGE;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.tag inSection:0] withCellModel:[modelList objectAtIndex: sender.tag]];
}
- (void) belowAverage:(UIButton*)sender {
[modelList objectAtIndex: sender.tag].range = BELOW_AVERAGE;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.tag inSection:0] withCellModel:[modelList objectAtIndex: sender.tag]];
}
- (void)setCellDynamicly:(NSIndexPath*)indexPath withCellModel:(CellModel*)cellModel {
TableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
[cell prepareForReuse];
[cell setupCellWithModel:cellModel];
}
#end
that s all :)
At the end app looks like :
yes this will be a solution for you, at least I hope like this :)
first of all create a custom button .h file like this :
#import <UIKit/UIKit.h>
#interface CustomButton : UIButton
#property (assign) NSInteger sectionTag;
#property (assign) NSInteger rowTag;
#end
custom button .m file like this :
#import "CustomButton.h"
#implementation CustomButton
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
#end
then I changed a few things in TableViewCell .h file like this :
#import <UIKit/UIKit.h>
#import "CellModel.h"
#import "CustomButton.h"
#interface TableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet CustomButton *veryGoodButton;
#property (weak, nonatomic) IBOutlet CustomButton *goodButton;
#property (weak, nonatomic) IBOutlet CustomButton *averageButton;
#property (weak, nonatomic) IBOutlet CustomButton *belowAverageButton;
#property (weak, nonatomic) IBOutlet UILabel *itemLabel;
- (void)setupCellWithModel:(CellModel*)model;
#end
TableViewCell .m file like this :
#import "TableViewCell.h"
#implementation TableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (void)setupCellWithModel:(CellModel *)model {
if(model.range == VERY_GOOD) {
self.veryGoodButton.backgroundColor = [UIColor greenColor];
}
else if(model.range == GOOD) {
self.goodButton.backgroundColor = [UIColor blueColor];
}
else if(model.range == AVERAGE) {
self.averageButton.backgroundColor = [UIColor yellowColor];
}
else if(model.range == BELOW_AVERAGE) {
self.belowAverageButton.backgroundColor = [UIColor redColor];
}
[self.itemLabel setText:model.itemText];
}
- (void)prepareForReuse {
[super prepareForReuse];
self.veryGoodButton.backgroundColor = [UIColor lightGrayColor];
self.goodButton.backgroundColor = [UIColor lightGrayColor];
self.averageButton.backgroundColor = [UIColor lightGrayColor];
self.belowAverageButton.backgroundColor = [UIColor lightGrayColor];
}
and its .xib like this :
on the other side, there is only one change on CellModel .h file like this :
#import <Foundation/Foundation.h>
typedef enum : NSInteger {
UNKNOWN = 0,
VERY_GOOD = 1,
GOOD = 2,
AVERAGE = 3,
BELOW_AVERAGE = 4
}RangeMark;
#interface CellModel : NSObject
#property(nonatomic, assign) RangeMark range;
#property(nonatomic, copy) NSString* itemText;
- (id)initWith:(NSString*)itemText withRangeMark:(RangeMark)range;
#end
and its .m file like this :
#import "CellModel.h"
#implementation CellModel
- (id)initWith:(NSString*)itemText withRangeMark:(RangeMark)range {
self = [super init];
if(self) {
self.itemText = itemText;
self.range = range;
}
return self;
}
#end
finally view controller .h file same but .m like this :
#import "ViewController.h"
#interface ViewController () <UITableViewDelegate, UITableViewDataSource>{
NSMutableArray *modelList;
NSMutableArray<NSString*> *sectionTitleList;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 600;
self.tableView.rowHeight = UITableViewAutomaticDimension;
sectionTitleList = [NSMutableArray<NSString*> new];
[sectionTitleList addObject:#"RESERVATION"];
[sectionTitleList addObject:#"FRONT DESK"];
[sectionTitleList addObject:#"CASHIER"];
[sectionTitleList addObject:#"HOUSE KEEPING"];
modelList = [[NSMutableArray alloc] initWithCapacity: 4];
[modelList insertObject:[NSMutableArray arrayWithObjects:[[CellModel alloc] initWith:#"Service Speed" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Good Speed" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Confirmation Quality" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Quick Service in Reservetion" withRangeMark:UNKNOWN],nil] atIndex:0];
[modelList insertObject:[NSMutableArray arrayWithObjects:[[CellModel alloc] initWith:#"Check In" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Happy on Their Service" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Coutesey" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Quick Service at Check In" withRangeMark:UNKNOWN],nil] atIndex:1];
[modelList insertObject:[NSMutableArray arrayWithObjects:[[CellModel alloc] initWith:#"Front Office & Reception" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Overall Quality of Room" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Check" withRangeMark:UNKNOWN],[[CellModel alloc] initWith:#"Response Time" withRangeMark:UNKNOWN],nil] atIndex:2];
[modelList insertObject:[NSMutableArray arrayWithObjects:[[CellModel alloc] initWith:#"Room Decor" withRangeMark:UNKNOWN],nil] atIndex:3];
// [modelList addObject: [[CellModel alloc] initWith:#"Service Speed" withRangeMark:UNKNOWN]];
// [modelList addObject: [[CellModel alloc] initWith:#"Good Speed" withRangeMark:UNKNOWN]];
// [modelList addObject: [[CellModel alloc] initWith:#"Confirmation Quality" withRangeMark:UNKNOWN]];
// [modelList addObject: [[CellModel alloc] initWith:#"Quick Service in Reservetion" withRangeMark:UNKNOWN]];
// for (int i=0; i<5; i++) {
// CellModel *cellModel = [[CellModel alloc] init];
// cellModel.range = UNKNOWN;
// cellModel.itemText = #"";
// [modelList addObject:cellModel];
// }
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
TableViewCell *cell = (TableViewCell*)[tableView dequeueReusableCellWithIdentifier:#"TableViewCell"];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSLog(#"section: %ld - row : %ld - item text : %#", (long)indexPath.section, (long)indexPath.row, ((CellModel*)[[modelList objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]).itemText);
[cell setupCellWithModel:[[modelList objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]];
((CustomButton*)cell.veryGoodButton).rowTag = indexPath.row;
((CustomButton*)cell.veryGoodButton).sectionTag = indexPath.section;
((CustomButton*)cell.goodButton).rowTag = indexPath.row;
((CustomButton*)cell.goodButton).sectionTag = indexPath.section;
((CustomButton*)cell.averageButton).rowTag = indexPath.row;
((CustomButton*)cell.averageButton).sectionTag = indexPath.section;
((CustomButton*)cell.belowAverageButton).rowTag = indexPath.row;
((CustomButton*)cell.belowAverageButton).sectionTag = indexPath.section;
[cell.veryGoodButton addTarget:self action:#selector(veryGood:) forControlEvents:UIControlEventTouchUpInside];
[cell.goodButton addTarget:self action:#selector(good:) forControlEvents:UIControlEventTouchUpInside];
[cell.averageButton addTarget:self action:#selector(average:) forControlEvents:UIControlEventTouchUpInside];
[cell.belowAverageButton addTarget:self action:#selector(belowAverage:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[modelList objectAtIndex:section] count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return sectionTitleList.count;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 18)];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, tableView.frame.size.width, 18)];
[label setFont:[UIFont boldSystemFontOfSize:12]];
[label setTextColor:[UIColor whiteColor]];
NSString *string =[sectionTitleList objectAtIndex:section];
[label setText:string];
[view addSubview:label];
[view setBackgroundColor:[UIColor darkGrayColor]];
return view;
}
- (void) veryGood:(CustomButton*)sender {
((CellModel*)[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]).range = VERY_GOOD;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.rowTag inSection:sender.sectionTag] withCellModel:[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]];
}
- (void) good:(CustomButton*)sender {
((CellModel*)[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]).range = GOOD;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.rowTag inSection:sender.sectionTag] withCellModel:[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]];
}
- (void) average:(CustomButton*)sender {
((CellModel*)[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]).range = AVERAGE;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.rowTag inSection:sender.sectionTag] withCellModel:[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]];
}
- (void) belowAverage:(CustomButton*)sender {
((CellModel*)[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]).range = BELOW_AVERAGE;
[self setCellDynamicly:[NSIndexPath indexPathForRow:sender.rowTag inSection:sender.sectionTag] withCellModel:[[modelList objectAtIndex:sender.sectionTag] objectAtIndex:sender.rowTag]];
}
- (void)setCellDynamicly:(NSIndexPath*)indexPath withCellModel:(CellModel*)cellModel {
TableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
[cell prepareForReuse];
[cell setupCellWithModel:cellModel];
}
#end
I think that it will work fine for you. Just do some change part of array init on code to dynamic :)
last appearance :
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 600;
self.tableView.rowHeight = UITableViewAutomaticDimension;
sectionTitleList = [NSMutableArray<NSString*> new];
for (NSString* sectionTitle in yourSectionResponseArray) {
[sectionTitleList addObject: sectionTitle];
}
modelList = [[NSMutableArray alloc] initWithCapacity: [sectionTitleList count]];
//your row title array has to be 2D array.
for(int i = 0; i < [sectionTitleList count]; i++) {
NSMutableArray* rowStringArray = [NSMutableArray new];
for(NSString* rowTitle in [your2DRowResponseArray objectAtIndex:i]) {
[rowStringArray addObject: rowTitle];
}
[modelList insertObject: rowStringArray];
}
}
May be this can help you.
Since you haven't provided us the API response details as requested earlier we are forced to use static value. Please replace sectionTitleList & modelList from the array API response. Please find the below code to be used to assign you API response to model created by #Gökhan Aydın .
sectionTitleList = #[#"RESERVATION",#"FRONT DESK",#"CASHIER",#"HOUSE KEEPING",#"COMMON"];
modelList = #[
#[
#"Service Speed",
#"Good Service",
#"Confirmation quality",
#"Quick Service in Reservation"
],
#[
#"Check In",
#"Happy on their Service",
#"Courtesey",
#"Quick Service at Checkin"
],
#[
#"Front office & reception",
#"Overall Quality of Room",
#"Check",
#"Response time"
],
#[
#"Room Decor",
#"Time taken to serveTime taken to serveTime taken t",
#"Bathroom",
#"Facilities in the Room",
#"Choice of menu",
#"Housekeeping",
#"Room Service"
],
#[
#"Overall Comments",
#"Will you come back again"
]
];
self.navigationItem.title = [modelList lastObject];
GNM = [sectionTitleList mutableCopy];
NM = [[NSMutableArray alloc]init];
for (NSArray *feedbacktitles in modelList) {
if ([feedbacktitles isKindOfClass:[NSArray class]]) {
__block NSMutableArray *tempArray = [NSMutableArray new];
[feedbacktitles enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL * _Nonnull stop) {
FeedbackModel *model = [[FeedbackModel alloc]initWith:title withRangeMark:UNKNOWN];
[tempArray addObject:model];
if (idx == [feedbacktitles count] - 1 ) {
*stop = TRUE;
[self->NM addObject:tempArray];
tempArray = [NSMutableArray new];
}
}];
}
}
or by simple for loop
for (NSArray *feedbacktitles in modelList) {
NSLog(#"%#",feedbacktitles);
NSMutableArray* rowStringArray = [NSMutableArray new];
if ([feedbacktitles isKindOfClass:[NSArray class]]) {
for(int i = 0; i < [feedbacktitles count]; i++) {
NSString* rowTitle = [feedbacktitles objectAtIndex:i];
FeedbackModel *model = [[FeedbackModel alloc]initWith:rowTitle withRangeMark:UNKNOWN];
[rowStringArray addObject: model];
if (i == [feedbacktitles count] - 1) {
[NM addObject: rowStringArray];
rowStringArray = [NSMutableArray new];
}
}
}
}
I have a simple collection view with 5 elements.
The default order of the cells looks like this:
I wanna know if it's possible to change the padding\order of the cells to get result like this:
Option 1: (Clean option)
You should have 2 sections.
Section 1 with 3 cells
Section 2 with 2 cells
You can then adjust the inset with collectionView(_:layout:insetForSectionAt:) for the section you want to adjust. (in this case, section 2)
If you do not implement this method, the flow layout uses the value in
its sectionInset property to set the margins instead. Your
implementation of this method can return a fixed set of margin sizes
or return different margin sizes for each section.
Section insets are
margins applied only to the items in the section. They represent the
distance between the header view and the first line of items and
between the last line of items and the footer view. They also indicate
they spacing on either side of a single line of items. They do not
affect the size of the headers or footers themselves.
Option 2: (Spaghetti option, but good to know)
Create a custom subclass for section 2 items, where you can customize the inset of the actual content for the UICollectionViewCell contentView subviews.
Then in section 2, return your customized cell.
To do this, you may need to write a custom layout. Check out the Collection View Programming Guide for more information.
The default (flow) layout will always lay the cells out in this pattern:
You can achieve this type of format in UICollectionView by changing the number of sections from 1 to 2.
And then you can define your custom UICollectionViewFlowLayout accordingly for different sections.
SOLUTION: I've created a subclass of UICollectionView named "CenteringCollectionView" and with a few calculations of the sections I made it!
The .h file:
#import <UIKit/UIKit.h>
#class CenteringCollectionView;
#protocol CenteringCollectionViewDelegate <NSObject>
-(void)collectionView:(CenteringCollectionView *)collectionView didDequeueReusableCell:(UICollectionViewCell *)cell indexPath:(NSIndexPath *)indexPath;
#end
#interface CenteringCollectionView : UICollectionView
#property (nonatomic, strong) NSMutableArray *dataSourceArr;
#property (nonatomic, weak) id<CenteringCollectionViewDelegate> delegateCenteringCollection;
#end
The .m file:
#import "CenteringCollectionView.h"
#interface CenteringCollectionView () <UICollectionViewDelegate, UICollectionViewDataSource>
#property (nonatomic, assign) IBInspectable long elementsInRow;
#property (nonatomic, assign) long elementsInRowInitialValue;
#property (nonatomic) IBInspectable NSString *cellIdentifier;
#property (nonatomic) IBInspectable CGFloat cellRelativeSize; // 0..1
#property (nonatomic, assign) long numOfSections;
#property (nonatomic, assign) IBInspectable BOOL autoResize; // *** If we want auto resize - we need to set the height constraint of the collection view in size of 1 line only even if we have more than 1 line (section).
#property (nonatomic, assign)IBInspectable CGFloat heightMiddleSpacing;
#property (nonatomic, assign) long cellSize;
//#property (nonatomic, assign) CGFloat verticalTopInset;
#property (nonatomic, assign) CGFloat initialHeightConstraint;
#property (nonatomic, weak) NSLayoutConstraint *selfHeightConstraint;
#property (nonatomic, assign) CGFloat cellSpacing;
#property (nonatomic, assign) BOOL shouldReloadUIElements;
// UI IBInspectable
#property (nonatomic, weak) IBInspectable UIColor *runtimeColor;
#end
static long const maxElementsInRowDefault = 3;
#implementation CenteringCollectionView
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
self.elementsInRow = maxElementsInRowDefault; // will get the default value if not stored value in storyboard
self.elementsInRowInitialValue = self.elementsInRow;
self.cellRelativeSize = 0.5;
self.initialHeightConstraint = -1;
}
return self;
}
-(void)setDataSourceCount:(long)dataSourceCount
{
if (dataSourceCount == _dataSourceCount)
{
return;
}
_dataSourceCount = dataSourceCount;
self.shouldReloadUIElements = YES;
self.elementsInRow = MIN(self.elementsInRowInitialValue, self.dataSourceCount);
self.numOfSections = ceil((CGFloat)self.dataSourceCount / (CGFloat)self.elementsInRow);
CGFloat selfHeight = [self handleAutoResizeAndReturnTheNewHeightIfNeeded];
CGFloat selfWidth = CGRectGetWidth(self.frame);
CGFloat cellWidth = (selfWidth / self.elementsInRow) * self.cellRelativeSize;
CGFloat cellHeight = (selfHeight / self.numOfSections) * self.cellRelativeSize;
self.cellSize = MIN(cellWidth, cellHeight);
dispatch_async(dispatch_get_main_queue(), ^{
[self setCollectionView];
[self reloadData];
});
}
-(void)awakeFromNib
{
[super awakeFromNib];
self.elementsInRowInitialValue = self.elementsInRow;
[self handleUIelementsIBInspectable];
}
-(void)handleUIelementsIBInspectable
{
if (self.runtimeColor)
{
[self setBackgroundColor:self.runtimeColor];
}
}
-(CGFloat)handleAutoResizeAndReturnTheNewHeightIfNeeded
{
if (self.autoResize)
{
for (NSLayoutConstraint *constraint in [self constraints])
{
if (constraint.firstAttribute == NSLayoutAttributeHeight)
{
if (self.initialHeightConstraint == -1) // not set yet
{
self.initialHeightConstraint = constraint.constant;
}
if (!self.selfHeightConstraint)
{
self.selfHeightConstraint = constraint;
}
CGFloat newHeight = self.initialHeightConstraint * self.numOfSections;
constraint.constant = newHeight;
if (self.bounds.size.height != newHeight)
{
CGRect frame = self.bounds;
frame.size.height = newHeight;
[self setBounds:frame];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.superview layoutIfNeeded];
[self layoutIfNeeded];
});
return newHeight;
}
}
}
return CGRectGetHeight(self.frame);
}
-(long)numOfSpacesInRow
{
return self.elementsInRow + 1;
}
-(long)numOfSpacesBetweenLines
{
return self.numOfSections + 1;
}
-(void)setCellRelativeSize:(CGFloat)cellRelativeSize
{
_cellRelativeSize = MAX(0, MIN(cellRelativeSize, 1));
}
-(void)setCollectionView
{
[self reloadData];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
CGFloat horizontalCellSpacing = ((CGRectGetWidth(self.frame) - (self.cellSize * self.elementsInRow)) / self.numOfSpacesInRow);
CGFloat verticalCellSpacing = (CGRectGetHeight(self.frame) - (self.numOfSections * self.cellSize)) / self.numOfSpacesBetweenLines;
self.cellSpacing = MAX(MIN(horizontalCellSpacing, verticalCellSpacing), 0);
[layout setMinimumInteritemSpacing:self.cellSpacing];
[layout setMinimumLineSpacing:self.cellSpacing];
[layout setScrollDirection:UICollectionViewScrollDirectionVertical];
[self setCollectionViewLayout:layout];
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
self.scrollEnabled = NO;
if (!self.delegate)
{
self.delegate = self;
self.dataSource = self;
}
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(self.cellSize, self.cellSize);
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
BOOL isLastSection = (section == self.numOfSections - 1);
if (isLastSection == NO)
{
return self.elementsInRow;
}
else
{
long numOfLeftItemsInLastRow = self.dataSourceCount % self.elementsInRow;
if (numOfLeftItemsInLastRow == 0)
{
return self.elementsInRow;
}
else
{
return numOfLeftItemsInLastRow;
}
}
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:self.cellIdentifier forIndexPath:indexPath];
if ([self.delegateCenteringCollection respondsToSelector:#selector(collectionView:didDequeueReusableCell:indexPath:)])
{
[self.delegateCenteringCollection collectionView:self didDequeueReusableCell:cell indexPath:[self indexPathWithoutSectionsFrom:indexPath]];
}
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.delegateCenteringCollection respondsToSelector:#selector(collectionView:didSelectItemAtIndexPath:cell:)])
{
UICollectionViewCell *selectedCell = [collectionView cellForItemAtIndexPath:indexPath];
[self.delegateCenteringCollection collectionView:self didSelectItemAtIndexPath:[self indexPathWithoutSectionsFrom:indexPath] cell:selectedCell];
}
}
-(NSIndexPath *)indexPathWithoutSectionsFrom:(NSIndexPath *)indexPath
{
long sectionNum = indexPath.section;
long rowNum = sectionNum * self.elementsInRow + indexPath.row;
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:rowNum inSection:0];
return newIndexPath;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return self.numOfSections;
}
-(void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
dispatch_async(dispatch_get_main_queue(), ^{
if (self.shouldReloadUIElements == NO)
{
return;
}
if (self.autoResize && self.selfHeightConstraint)
{
BOOL isTheFirstCellInTheLastSection = (indexPath.section == self.numOfSections - 1) && indexPath.row == 0;
if (isTheFirstCellInTheLastSection)
{
CGFloat newHeight = CGRectGetMaxY(cell.frame) + self.cellSpacing;
self.selfHeightConstraint.constant = newHeight;
if (self.bounds.size.height != newHeight)
{
CGRect frame = self.bounds;
frame.size.height = newHeight;
[self setBounds:frame];
}
[self.superview layoutIfNeeded];
[self layoutIfNeeded];
}
}
});
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
if (self.shouldReloadUIElements == NO)
{
return collectionView.contentInset;
}
NSInteger cellsCount = [collectionView numberOfItemsInSection:section];
CGFloat horizontalInset = (collectionView.bounds.size.width - (cellsCount * self.cellSize) - ((cellsCount - 1) * self.cellSpacing)) * 0.5;
horizontalInset = MAX(horizontalInset, 0.0);
BOOL isLastSection = (section == self.numOfSections - 1);
CGFloat verticalTopInset = self.cellSpacing;
CGFloat verticalBottomInset = verticalTopInset;
if (section == 0 && isLastSection == NO)
{
if (self.heightMiddleSpacing)
{
verticalBottomInset += self.heightMiddleSpacing;
}
verticalBottomInset /= 2;
}
if (section > 0)
{
if (self.heightMiddleSpacing)
{
verticalTopInset += self.heightMiddleSpacing;
}
verticalTopInset /= 2;
if (isLastSection == NO)
{
if (self.heightMiddleSpacing)
{
verticalBottomInset += self.heightMiddleSpacing;
}
verticalBottomInset /= 2;
}
}
return UIEdgeInsetsMake(verticalTopInset, horizontalInset, verticalBottomInset, horizontalInset);
}
#end
And to make it work, all we need to do in the parent view is:
self.collectionView.delegateCenteringCollection = self;
self.collectionView.dataSourceCount = 5; // Or whatever number we want!
In the storyboard: we need to create collectionView of this class and set the "elements in row" value, also set the "Cell Identifier" and the "Cell relative size" between 0 to 1 (the "Cell relative size" value: will calculate the cell size & paddings according to the collectionView width & height).
And at last - set "autoResize" to "true" if you want that the collection view will resize its own height constraint(if exist) automatically according to the number of rows. If we set "autoResize" to true, the height constraint that we set to the collectionView will determine the height of a single row. If our collectionView should grow for example to 3 rows, it will multiple our collectionview height constraint by 3.
And it works like a charm!
I'm currently building an app that has to present a twitter feed in the form of an horizontal collection view.
3 tweets (cells) should always be visible on screen and centered horizontaly aswell as half a tweet (last element of the previous 3 and first element of the next 3) on both side.
Here is a picture so it's easier to understand
When the user scrolls it should scroll 3 by 3 (or less if there are actualy less cell left to scroll). Sort of a custom paging.
I tried using a Custom layout and it works and make the cells be centered, showing half tweets on both side just like I want. But I can't make it work with the scrolling I want (3by3). And it won't let me show the first or last cell entirely... Anyway, when I had the following code, it just cancel the custom layout behaviour, but scrolls 3 by 3...
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
float pageWidth = ((self.view.frame.size.width / 4)*3);
float currentOffset = scrollView.contentOffset.x;
float targetOffset = targetContentOffset->x;
float newTargetOffset = 0;
if (targetOffset > currentOffset)
newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth;
else
newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth;
if (newTargetOffset < 0)
newTargetOffset = 0;
else if (newTargetOffset > scrollView.contentSize.width)
newTargetOffset = scrollView.contentSize.width;
targetContentOffset->x = currentOffset;
[scrollView setContentOffset:CGPointMake(newTargetOffset, 0) animated:YES];
}
So guys, has anyone played with this before and could help me get things done ? Thanks a bunch.
ViewController.h
#import <UIKit/UIKit.h>
#import "CustomCell.h"
#import "DetailimageViewController.h"
#interface RootViewController : UIViewController<UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>
{
IBOutlet UICollectionView *collectionViewHorizontalVertical;
}
ViewController.m
#import "RootViewController.h"
#interface RootViewController ()
{
NSMutableArray *arrayImages;
DetailimageViewController *detailImageVC ;
}
#end
#implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
arrayImages = [[NSMutableArray alloc]initWithObjects:#"iMove.jpg",#"iPad.jpg",#"iPhone.jpg",#"iPod.jpg",#"iRing.jpg",#"iTV.jpg",#"iwatch.jpeg",nil];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
UINib *cellNib = [UINib nibWithNibName:#"CustomCell" bundle:nil];
[collectionViewHorizontalVertical registerNib:cellNib forCellWithReuseIdentifier:#"cvCell"];
}
//UICollectionView DataSource and Delegate Methods
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return arrayImages.count;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cvCell";
CustomCell *cell = (CustomCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.imgViewCollection.image = [UIImage imageNamed:[arrayImages objectAtIndex:indexPath.row]];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"The indexPath is - %ld",(long)indexPath.item);
int ind = (int)indexPath.item;
detailImageVC = [[DetailimageViewController alloc]initWithNibName:#"DetailimageViewController" bundle:nil];
detailImageVC.arrayImagesCount = arrayImages;
detailImageVC.intSelectedIndex = ind;
[[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:#"%d",detailImageVC.intSelectedIndex] forKey:#"SelectedCollectionViewID"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self.navigationController pushViewController:detailImageVC animated:YES];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(200, 200);
}
#end
In above coding I have 7 images.So you need to have your images above 7 or less.It is your wish.
Then DetailimageViewController.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface DetailimageViewController : UIViewController<UIScrollViewDelegate>
{
}
#property (strong, nonatomic) NSMutableArray *arrayImagesCount;
#property (strong, nonatomic) IBOutlet UIScrollView *scroll;
#property (strong, nonatomic) IBOutlet UIPageControl *pageControl;
#property (strong, nonatomic) IBOutlet UIImageView *imageviewScrollView
#property (assign, nonatomic) NSInteger seletedIndex;
#property (strong, nonatomic) UIImage *imageSelection;
#property (nonatomic, assign) int intSelectedIndex;
#property (nonatomic, strong) NSArray *pageImages;
#property (nonatomic, assign) CGFloat lastContentOffset;
- (IBAction)actionBack:(id)sender;
#end
DetailimageViewController.m
#import "DetailimageViewController.h"
#interface DetailimageViewController ()
{
UIImageView *subimg;
}
#end
#implementation DetailimageViewController
typedef enum ScrollDirection
{
ScrollDirectionNone,
ScrollDirectionRight,
ScrollDirectionLeft,
ScrollDirectionUp,
ScrollDirectionDown,
ScrollDirectionCrazy,
} ScrollDirection;
#synthesize arrayImagesCount;
#synthesize scroll;
#synthesize seletedIndex;
#synthesize imageSelection;
#synthesize intSelectedIndex;
#synthesize pageImages = _pageImages;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
scroll.layer.cornerRadius=8.0f;
scroll.layer.masksToBounds=YES;
scroll.layer.borderColor=[[UIColor redColor]CGColor];
scroll.layer.borderWidth= 1.0f;
NSInteger pageCount = arrayImagesCount.count;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int intCollectionViewIndex = [[defaults valueForKey:#"SelectedCollectionViewID"]intValue];
if(intSelectedIndex == intCollectionViewIndex)
{
for (int i=intSelectedIndex; i<[arrayImagesCount count]; i++)
{
CGRect frame;
if(i == intCollectionViewIndex)
{
frame.origin.x = self.scroll.frame.size.width *intCollectionViewIndex;
frame.origin.y=0;
frame.size=self.scroll.frame.size;
subimg=[[UIImageView alloc]initWithFrame:CGRectMake(self.scroll.frame.size.width *intCollectionViewIndex,0,self.scroll.frame.size.width,self.scroll.frame.size.height)];
subimg.image=[UIImage imageNamed:[NSString stringWithFormat:#"%#",[arrayImagesCount objectAtIndex:i]]];
[self.scroll addSubview:subimg];
[self.scroll setContentOffset:CGPointMake(self.scroll.frame.size.width*i,-20) animated:YES];
self.scroll.contentSize = CGSizeMake(self.scroll.frame.size.width*arrayImagesCount.count, self.scroll.frame.size.height);
}
else{
}
}
}
}
ScrollView Delegate Method
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(#" Offset = %# ",NSStringFromCGPoint(scrollView.contentOffset));
ScrollDirection scrollDirection;
if (self.lastContentOffset > scrollView.contentOffset.x)
{
scrollDirection = ScrollDirectionRight;
NSLog(#"The scrollview is scrolling right side");
for(int j=intSelectedIndex;j<[arrayImagesCount count];j--)
{
CGRect frameRight;
frameRight.origin.x = self.scroll.frame.size.width *j;
frameRight.origin.y=0;
frameRight.size=self.scroll.frame.size;
subimg=[[UIImageView alloc]initWithFrame:CGRectMake(self.scroll.frame.size.width *j,0,self.scroll.frame.size.width,self.scroll.frame.size.height)];
subimg.image=[UIImage imageNamed:[NSString stringWithFormat:#"%#",[arrayImagesCount objectAtIndex:j]]];
[self.scroll addSubview:subimg];
self.scroll.contentSize = CGSizeMake(self.scroll.frame.size.width*arrayImagesCount.count, self.scroll.frame.size.height);
}
}
else if (self.lastContentOffset < scrollView.contentOffset.x)
{
scrollDirection = ScrollDirectionLeft;
NSLog(#"The scrollview is scrolling left side");
for(int k=intSelectedIndex;k<[arrayImagesCount count];k++)
{
CGRect frameLeft;
frameLeft.origin.x = self.scroll.frame.size.width *k;
frameLeft.origin.y=0;
frameLeft.size=self.scroll.frame.size;
subimg=[[UIImageView alloc]initWithFrame:CGRectMake(self.scroll.frame.size.width *k,0,self.scroll.frame.size.width,self.scroll.frame.size.height)];
subimg.image=[UIImage imageNamed:[NSString stringWithFormat:#"%#",[arrayImagesCount objectAtIndex:k]]];
[self.scroll addSubview:subimg];
self.scroll.contentSize = CGSizeMake(self.scroll.frame.size.width*arrayImagesCount.count, self.scroll.frame.size.height);
}
}
self.lastContentOffset = scrollView.contentOffset.x;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
CGPoint translation = [scrollView.panGestureRecognizer translationInView:scrollView.superview];
NSLog(#"The translation.x is - %f",translation.x);
NSLog(#"The scrollview content off set is - %f",scrollView.contentOffset.x);
if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0) {
// handle dragging to the right
NSLog(#"It is dragging to right side");
} else {
// handle dragging to the left
NSLog(#"It is dragging to left side");
}
}
- (IBAction)actionBack:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
#end
The problem in pictures:
Basically, my table view adds an empty cell between each other, and I don't know why. I already tried putting an NSLog statement in cellForRowAtIndexPath:, willDisplayCell:forRowAtIndexPath:, and didSelectRowAtIndexPath:, and the data source in each cell's indexPath is correct. It's just that the displayed cells are skipping in between, and I don't understand why.
My view controller and table view cell subclasses are also very simple. Here's the code:
PrivateMessagesViewController.m
static NSString * const kCellIdentifier = #"kCellIdentifier";
#interface PrivateMessagesViewController () <UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) NSMutableArray *messages;
#property (strong, nonatomic) SCPFInboxQuery *query;
#property (nonatomic) BOOL hasAlreadyFetchedBefore;
#property (strong, nonatomic) UITableView *tableView;
// This is a custom view that either shows a loading animation,
// a "No Results Found" label, or an error message with a Retry button
// at the center of the view of a view controller.
#property (strong, nonatomic) SCPCenterView *centerView;
#end
#implementation PrivateMessagesViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Private Messages";
self.messages = [NSMutableArray array];
self.query = [[SCPFInboxQuery alloc] init];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, [UIScreen mainScreen].bounds.size.height - 113) style:UITableViewStylePlain];
self.tableView.dataSource = self;
self.tableView.delegate = self;
[self.tableView registerClass:[SCPPrivateMessageListCell class] forCellReuseIdentifier:kCellIdentifier];
self.tableView.alpha = 0; // The table view starts out invisible.
[self.view addSubview:self.tableView];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!self.hasAlreadyFetchedBefore) {
[self.view addSubview:self.centerView];
[self.centerView showLoadingView];
__weak PrivateMessagesViewController *weakSelf = self;
[self.query runInBackgroundWithCompletion:^(NSArray *messages, NSError *error) {
PrivateMessagesViewController *innerSelf = weakSelf;
// If there is an error, handle it.
if (error) {
// ...
return;
}
// If there weren't any messages before and none were found,
// the user has no messages in the inbox.
if (!innerSelf.hasAlreadyFetchedBefore && messages.count == 0) {
[innerSelf.centerView showNoResultsLabel];
}
else {
if (!innerSelf.hasAlreadyFetchedBefore) {
[innerSelf.centerView fadeOutAndRemoveFromSuperview];
innerSelf.tableView.alpha = 1;
} else {
}
[innerSelf.messages addObjectsFromArray:messages];
[innerSelf.tableView reloadData];
}
innerSelf.hasAlreadyFetchedBefore = YES;
}];
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.messages.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SCPPrivateMessageListCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
SCPFMessage *message = self.messages[indexPath.row];
cell.message = message;
return cell;
}
#pragma mark - Table view delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [SCPPrivateMessageListCell heightForMessage:self.messages[indexPath.row]];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
SCPPrivateMessageListCell *theCell = (SCPPrivateMessageListCell *)cell;
NSLog(#"Message at %d: %#", indexPath.row, theCell.message.rawData);
}
#pragma mark - Getters
- (SCPCenterView *)centerView
{
if (!_centerView) {
_centerView = [[SCPCenterView alloc] initWithParent:self.view];
_centerView.noResultsText = #"You don't have any private messages yet.";
}
return _centerView;
}
#end
SCPPrivateMessageListCell.m
static const CGFloat kInnerMargin = 10;
static const CGFloat kSpaceBetweenImageAndRightLabel = 10;
static const CGFloat kImageViewSize = 60;
static const CGFloat kRightLabelX = kInnerMargin + kImageViewSize + kSpaceBetweenImageAndRightLabel;
static const CGFloat kMaxRightLabelWidth = 320 - (kRightLabelX + kInnerMargin);
#interface SCPPrivateMessageListCell ()
#property (strong, nonatomic) UIImageView *thumbnailImageView;
#property (strong, nonatomic) UILabel *dateLabel;
#property (strong, nonatomic) UILabel *senderLabel;
#property (strong, nonatomic) UILabel *subjectLabel;
#property (strong, nonatomic) UILabel *summaryLabel;
#end
#implementation SCPPrivateMessageListCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
if (self) {
_thumbnailImageView = [[UIImageView alloc] init];
_thumbnailImageView.contentMode = UIViewContentModeScaleAspectFill;
_thumbnailImageView.layer.cornerRadius = kImageViewSize / 2;
_thumbnailImageView.clipsToBounds = YES;
_dateLabel = [[UILabel alloc] init];
_dateLabel.font = [UIFont systemFontOfSize:10];
_dateLabel.textAlignment = NSTextAlignmentCenter;
_dateLabel.numberOfLines = 1;
_dateLabel.lineBreakMode = NSLineBreakByTruncatingTail;
_senderLabel = [SCPPrivateMessageListCell senderLabel];
_subjectLabel = [SCPPrivateMessageListCell subjectLabel];
_summaryLabel = [SCPPrivateMessageListCell summaryLabel];
[self.contentView addSubview:_thumbnailImageView];
[self.contentView addSubview:_dateLabel];
[self.contentView addSubview:_senderLabel];
[self.contentView addSubview:_subjectLabel];
[self.contentView addSubview:_summaryLabel];
}
return self;
}
- (void)setMessage:(SCPFMessage *)message
{
_message = message;
[self.thumbnailImageView setImageWithURL:message.thumbnailURL];
self.dateLabel.text = message.dateSent;
self.senderLabel.text = message.nameOfSender;
self.subjectLabel.text = message.subject;
self.summaryLabel.text = message.summary;
[self setNeedsLayout];
}
- (void)layoutSubviews
{
self.thumbnailImageView.frame = CGRectMake(kInnerMargin, kInnerMargin, kImageViewSize, kImageViewSize);
[self.dateLabel sizeToFitWidth:kImageViewSize];
self.dateLabel.frame = CGRectMake(kInnerMargin, kInnerMargin + kImageViewSize, kImageViewSize, self.dateLabel.frame.size.height);
[self.senderLabel sizeToFitWidth:kMaxRightLabelWidth];
self.senderLabel.frame = CGRectMake(kRightLabelX, kInnerMargin, kMaxRightLabelWidth, self.senderLabel.frame.size.height);
CGFloat subjectLabelY = self.senderLabel.frame.origin.y + self.senderLabel.frame.size.height;
[self.subjectLabel sizeToFitWidth:kMaxRightLabelWidth];
self.subjectLabel.frame = CGRectMake(kRightLabelX, subjectLabelY, kMaxRightLabelWidth, self.subjectLabel.frame.size.height);
CGFloat summaryLabelY = self.subjectLabel.frame.origin.y + self.subjectLabel.frame.size.height;
[self.summaryLabel sizeToFitWidth:kMaxRightLabelWidth];
self.summaryLabel.frame = CGRectMake(kRightLabelX, summaryLabelY, kMaxRightLabelWidth, self.summaryLabel.frame.size.height);
CGFloat cellHeight = [SCPPrivateMessageListCell heightForMessage:self.message];
self.contentView.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cellHeight);
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cellHeight);
}
#pragma mark - Class methods
+ (UILabel *)senderLabel
{
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont boldSystemFontOfSize:17];
label.textColor = [UIColor colorFromHex:0x0076be];
label.numberOfLines = 1;
label.lineBreakMode = NSLineBreakByTruncatingTail;
return label;
}
+ (UILabel *)subjectLabel
{
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:14];
label.numberOfLines = 1;
label.lineBreakMode = NSLineBreakByTruncatingTail;
return label;
}
+ (UILabel *)summaryLabel
{
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:12];
label.textColor = [UIColor grayColor];
label.numberOfLines = 3;
label.lineBreakMode = NSLineBreakByTruncatingTail;
return label;
}
+ (CGFloat)heightForMessage:(SCPFMessage *)message
{
CGFloat height = kInnerMargin;
UILabel *senderLabel = [SCPPrivateMessageListCell senderLabel];
senderLabel.text = message.nameOfSender;
[senderLabel sizeToFitWidth:kMaxRightLabelWidth];
height += senderLabel.frame.size.height;
UILabel *subjectLabel = [SCPPrivateMessageListCell subjectLabel];
subjectLabel.text = message.subject;
[subjectLabel sizeToFitWidth:kMaxRightLabelWidth];
height += subjectLabel.frame.size.height;
UILabel *summaryLabel = [SCPPrivateMessageListCell summaryLabel];
summaryLabel.text = message.summary;
[summaryLabel sizeToFitWidth:kMaxRightLabelWidth];
height += summaryLabel.frame.size.height;
height += kInnerMargin;
return height;
}
#end
There. I'm not doing anything non-standard. The subviews of the cells also disappear when I scroll, but when I scroll them back in, the content becomes displayed, still with a skipping empty cell. Anyone have any idea why this is happening?
The problem was in my table view cell's layoutSubviews.
self.contentView.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cellHeight);
That should have been:
self.contentView.frame = CGRectMake(self.contentView.frame.origin.x, self.contentView.frame.origin.y, self.contentView.frame.size.width, cellHeight);
I found out by setting a different color for self.backgroundColor and self.contentView.backgroundColor from inside the init method.