UICollectionView cells not spacing at all - ios

I have a collection view which is delegate and datasource of itself, and with a layout defined like this:
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self){
self.dataSource = self;
self.delegate = self;
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumLineSpacing = 0;
layout.sectionInset = UIEdgeInsetsMake(0, 8, 0, 8);
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.footerReferenceSize = CGSizeMake(1, 70);
layout.itemSize = CGSizeMake(60, 70);
layout.minimumInteritemSpacing = 4.0f;
[self setCollectionViewLayout:layout];
}
return self;
}
The code is run correctly except for the minimuminteritemspacing.
The result is a collectionview where the items in every section don't have any spacing at all.
The minimum spacing value I set should be adjusted upward, not downward, correct?
So why the result I see is like the one in this screen? (I colored every collectionitem so that is clear there is no spacing)
For further detail, here are the frames I'm logging, as you can see the third item starts exactly after the second one (145 pixels = 85(previousitem.x) + 60(previousitem.width)) with no spacing.
2014-04-22 10:25:49.954 App[15172:60b] self <PhotoIndexCollectionViewCell: 0x16576630; baseClass = UICollectionViewCell; frame = (8 0; 60 70); layer = <CALayer: 0x165777a0>>
2014-04-22 10:25:49.955 App[15172:60b] self <PhotoIndexCollectionViewCell: 0x16578380; baseClass = UICollectionViewCell; frame = (85 0; 60 70); layer = <CALayer: 0x16578520>>
2014-04-22 10:25:49.955 App[15172:60b] self <PhotoIndexCollectionViewCell: 0x16586620; baseClass = UICollectionViewCell; frame = (145 0; 60 70); layer = <CALayer: 0x165866c0>>
What am I misunderstanding here?
I even tried adding this method which is actually called for every section, but the result is the same.
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{
return 4.0f;
}

You can use following Delegate methods to set spacing:
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
// NSLog(#"SETTING SIZE FOR ITEM AT INDEX %ld", (long)indexPath.row);
CGSize mElementSize = CGSizeMake(150, 36);
return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 3.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 7.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}

As specified in the apple documentation, the space may be adjusted upward - But it looks that it may also be adjusted downward.
I honestly don't really understand why and don't have time to investigate this right now ( I'm facing the problem, and have to finish my work ;) ) - It may simply be a bug in the Apple layout, because it is presented to be so simple
https://developer.apple.com/documentation/uikit/uicollectionviewflowlayout/1617706-minimuminteritemspacing?changes=latest_minor
Anyway I see two ways to solve this :
1 - Compute the collection container bounds ( in the viewDidLayout function? ) by adding all items widths ( if width is not fixed ) or set it to ( itemWidth + minimumSpace ) * numberOfItems + minimumSpace ( for first padding )
2 - The radical way ( the one I have chosen ) : I embed my cell content in a view that is insetted by the amount I want. It just can't fail.
Cheers all

Related

Strange UICollectionViewCell behaviour if float size

Updated:
Sample project is github link
USE iPHONE 6 simulator
2 possible ways to achieve this bug.
Just build and run and see.
Or uncomment 256 row
//return CGSizeMake(widthAndHeight * self.venueLayoutZoom, widthAndHeight * self.venueLayoutZoom);
and press "Remove column" button
I have UICollectionView with a lot of UICollectionViewCells. My UI makes me to use zero space between cells. I have a pinch gesture in my UICollectionView. So sometimes sizeForItem:atIndexPath: returns me a big float numbers (like 11.821123411231). The problem is:
If I don't round these floats I have a strange behaviour sometimes -
It should be
If I round up or down sizeForItem:atIndexPath: it looks great but there are spaces between cells
I don't know what to do. It is really necessary to do without these spaces or strange cells.
My flow layout is this
Controller Code:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
CGFloat widthAndHeight = [self widthAndHeightForCollectionView:collectionView];
CGFloat result = widthAndHeight * self.venueLayoutZoom;
return CGSizeMake(result, result);
}
- (void)didReceivePinchGesture:(UIPinchGestureRecognizer *)gesture
{
static CGFloat scaleStart;
if (gesture.state == UIGestureRecognizerStateBegan) {
scaleStart = self.venueLayoutZoom;
}
else if (gesture.state == UIGestureRecognizerStateChanged) {
self.venueLayoutZoom = scaleStart * gesture.scale;
}
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
VenueLayoutCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kVenueLayoutCellReuseIdentifier forIndexPath:indexPath];
self.activeCollectionViewCellsDictionary[indexPath] = cell;
if (self.activeCollectionViewObjects.count > indexPath.section) {
NSArray *rows = self.activeCollectionViewObjects[indexPath.section];
if (rows.count > indexPath.row) {
if ([rows[indexPath.row] isKindOfClass:[VenueLayoutCellObject class]]) {
VenueLayoutCellObject *object = rows[indexPath.row];
cell.cellObject = object;
}
}
}
return cell;
}
Cell Code:
#property (nonatomic, strong) CALayer *circularLayer;
- (void)awakeFromNib
{
[super awakeFromNib];
[self allocAndAddLayers];
}
- (void)allocAndAddLayers
{
self.circularLayer = [CALayer layer];
[self.layer addSublayer:self.circularLayer];
}
#pragma mark - Property Set
- (void)setCellObject:(VenueLayoutCellObject *)cellObject
{
self->_cellObject = cellObject;
self.objectBackgroundColor = cellObject.objectColor;
self.type = cellObject.type;
}
- (void)prepareForReuse
{
[self.circularLayer removeFromSuperlayer];
[self allocAndAddLayers];
}
- (void)setType:(VenueLayoutObjectType)type
{
self->_type = type;
[self updateInderfaceDependOnType];
}
- (void)layoutSubviews
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
[self updateRoundedCorners];
[CATransaction commit];
[super layoutSubviews];
}
- (void)updateRoundedCorners
{
CGRect bounds = self.bounds;
CGRect frame = self.frame;
self.circularLayer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
}
- (void)setLayerBackgroundColor:(UIColor *)color
{
self.circularLayer.backgroundColor = color.CGColor;
self.objectMaskLayer.strokeColor = color.CGColor;
self.deselectedColor = color;
}
- (void)updateInderfaceDependOnType
{
UIColor *tempObjectColor = [UIColor grayColor];
UIColor *objectColor = self.objectBackgroundColor ? : tempObjectColor;
[self setLayerBackgroundColor:objectColor];
}
Updated Code:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
CGFloat widthAndHeight = self.widthAndHeightForActiveCollectionView;
CGFloat result = lroundf(widthAndHeight * self.venueLayoutZoom);
CGFloat width = result;
if (indexPath.row > self.increasedWidthInitialIndex) {
width++;
}
return CGSizeMake(width, result);
}
CGFloat widthAndHeight = CGRectGetWidth(self.activeCollectionView.bounds) / maxCount;
NSNumber *widthNumber = #(CGRectGetWidth(self.activeCollectionView.bounds));
NSInteger count = widthNumber.integerValue % maxCount;
maxCount--;
self.increasedWidthInitialIndex = maxCount - count;
Updated:
If I use low item size (e.g CGSizeMake(7.f, 7.f)) cells doesn't fit whole
collection view but space still exists
Eventually setting width / height to half pixels changes the scale according to the device pixel depth (retina vs non-retina) - more info here
When you try and divide your screen to non-whole numbers, i.e. for screen width of 320 create 6 cells of 53.3 with might cause the UI to break.
You should try and find the remainder of your devision, i.e:
320 % 6 -> 2
And then make 2 cells 1 pixel wider.
So instead of 6 cells consisting of 53.3 pixels wide, you will have 2 consisting of 54 and 4 more of 53, then everything will fit correctly.
EDIT:
After going over your project, I have added printouts of your collection see what issues could be caused by widths, Iv'e added this method in the ViewController.m:
- (void)printoutGrid
{
NSLog(#"collectionview bounds: %f, %#", self.activeCollectionView.bounds.size.width, NSStringFromCGSize(self.activeCollectionView.contentSize));
CGFloat calculatedWidth = [self widthAndHeightForActiveCollectionViewItem];
CGFloat result = floor(calculatedWidth * self.venueLayoutZoom);
for (int rowAt = 0; rowAt < self.activeCollectionViewObjects.count; rowAt++)
{
NSArray* arrayAt = self.activeCollectionViewObjects[rowAt];
NSString* rowString = #"|";
for (int colAt = 0; colAt < arrayAt.count; colAt++)
{
if (colAt > self.increasedWidthInitialIndex)
{
rowString = [rowString stringByAppendingString:[NSString stringWithFormat:#"%d|", (int)result + 1]];
}
else
{
rowString = [rowString stringByAppendingString:[NSString stringWithFormat:#"%d|", (int)result]];
}
}
NSLog(#"%#", rowString);
}
}
And called it after every time you reload the collection or invalidate the layout, Iv'e found only that you should use floor instead of lroundf.
This method will help you debug your widths for the future.
But, after going over your project settings, something seemed off in your simulator, I noticed it was too large / out of scale and not retina, I went to your project settings and saw that your project is not retina compatible - which means the UI will not use Auto-Scaling -> which means it will use the same resolution (320 x 518) for all devices and what it does, it stretches the UI - meaning in iPhone 6 it multiplies it, and the stretching is being anti-analysed, which causes these so-called empty spaces between cells even though there is not space there.
What you need to do, is go to your project settings -> and in general scroll down to "Launch Screen File" and select "LaunchScreen" from the list:
This seems to solve the issue for this project. Let me know if you have anymore question and if it works.
Please note - it will require you to change size calculation a-bit because the resolution changes again after "viewDidLayoutSubviews" and not only when the view loads.
Good luck!

UICollectionView Center Cells with paging enabled

Been trying to center align my cells using UICollectionView with paging enabled. Unfortunately I can never make the cells align in the center when trying to do this. As I scroll through the collection the cells always move slightly off. Im trying to achieve this for both Portrait and landscape views. Ive been using insets to try and center the cells and their position:
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
CGFloat cellSpacing = ((UICollectionViewFlowLayout *) collectionViewLayout).minimumLineSpacing;
CGFloat cellWidth = ((UICollectionViewFlowLayout *) collectionViewLayout).itemSize.width;
NSInteger cellCount = [collectionView numberOfItemsInSection:section];
CGFloat inset = (collectionView.bounds.size.width - ((cellCount) * (cellWidth + cellSpacing))) * 0.5;
inset = MAX(inset, 0.0);
if(UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)){
return UIEdgeInsetsMake(50.0,inset,0.0,inset); // top, left, bottom, right
}
else{
return UIEdgeInsetsMake(50.0,inset,0.0,inset); // top, left, bottom, right
}
}
I then changed the line spacing:
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)
collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{
CGFloat cellSpacing = ((UICollectionViewFlowLayout *) collectionViewLayout).minimumLineSpacing;
CGFloat cellWidth = ((UICollectionViewFlowLayout *) collectionViewLayout).itemSize.width;
NSInteger cellCount = [collectionView numberOfItemsInSection:section];
CGFloat inset = (collectionView.bounds.size.width - ((cellCount-1) * (cellWidth + cellSpacing))) * 0.5;
inset = MAX(inset, 0.0);
if(UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)){
NSLog(#"Changed to landscape Spacing");
return inset;
}
else{
return inset;
}
The size of my cells are set here:
-(CGSize)
collectionView:(UICollectionView *) collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
//Set Landscape size of cells
if(UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)){
CGFloat cellWidth = [[UIScreen mainScreen] bounds].size.width-360;
CGFloat cellHeigt = [[UIScreen mainScreen] bounds].size.height-60;
NSLog(#"Is Landscape");
return CGSizeMake(cellWidth, cellHeigt);
}
//Set Potrait size of cells
else{
CGFloat cellWidth = [[UIScreen mainScreen] bounds].size.width-60;
CGFloat cellHeigt = [[UIScreen mainScreen] bounds].size.height-160;
NSLog(#"Is Portrait");
return CGSizeMake(cellWidth, cellHeigt);
}
}
Instead of trying to set the frame programmatically, you can simply set the the cell to occupy the whole width of the UICollectionView and center the content inside using autoLayout, this way you won't have to account for interface changes and different screen sizes as autoLayout will handle that for you. In your data source,
-(CGSize)
collectionView:(UICollectionView *) collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(collectionView.bounds.size.width, collectionView.bounds.size.height)
}
Set all your inter item spacing to 0 and enable paging for the UICollectionView
Next just use autoLayout to set the contents to center inside the cell!
Try This. you have to Take UICollectionViewFlowLayout and set it's scrolldirection,minimum space and attach to collection view Layout.
UICollectionViewFlowLayout *flowLayout;
- (void)viewDidLoad {
[super viewDidLoad];
flowLayout = [[UICollectionViewFlowLayout alloc]init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.minimumInteritemSpacing = 0.0;
flowLayout.minimumLineSpacing = 0.0;
_obj_CollectionView.pagingEnabled = YES;
_obj_CollectionView.collectionViewLayout = flowLayout;
}
if you want to scroll vertically modify it.
Hope it will work.

Uicollectionview weird gap

I have collection view with custom flow layout and i wonder why i have extra space like that (right side):
It may hard to notice here, though, but you may see gray gap between right side and cell.
Here is how i override standard collection view flow layout to remove horizontals gaps:
#implementation CalendarFlowLayout
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *answer = [super layoutAttributesForElementsInRect:rect];
NSLog(#"layout blck passed");
for(int i = 1; i < [answer count]; ++i) {
UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
NSInteger maximumSpacing = 0;
NSInteger origin = CGRectGetMaxX(prevLayoutAttributes.frame);
if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
CGRect frame = currentLayoutAttributes.frame;
frame.origin.x = origin + maximumSpacing;
currentLayoutAttributes.frame = frame;
}
}
return answer;
}
#end
Cell size calculated as follow:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(SCREEN_WIDTH/7, (SCREEN_HEIGHT-NAVBAR_HEIGHT-STATUS_BAR_HEIGHT)/6);
}
Those macros above look like that:
#define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width
It has been tested and it return correct output.
Also, if i set width to SCREEN_WIDTH/3, there is will be no gap.
How to remove it? Why is that happen?
375 / 3
= 125
375 / 7
= 53.57142857142857
You can't really light a half a pixel, so it is probably rounding down, leaving you with a gap. Make sure your size is a multiple of your subview size (or add a pixel to the rightmost object if it's not).
The problem is that the width of the cell (eg. SCREEN_WIDTH/3) is not a divisor of SCREEN_WIDTH. Correct divisors of SCREEN_WIDTH (375, as you said in comments) are 3, 5, 25 and 125 (125*3=375).
But As there are different screen size among all iOS devices, I think you should manage the problem differently. For example, you should choose a specific cell width and try to center the collection view in its container, so the extra-space will always be divided on both left and right side of the collection view.

UITableView cell width on iOS 8 stuck at 320pt

I am currently trying to create a simple UITableView with custom cells without using storyboard.
I'm getting an issue on the iPhone 6 simulator where the table view has a width of 375 (as it should), but the cells inside are getting a width of 320.
The number 320 is nowhere to be found in the project as I am not hard coding it. When I am setting the background colour of the cell, it extends the full width of 375, but I need to align an image to the right, which only aligns 320 across as shown in the photo below.
I'm not sure if it's because I'm missing constraints or if there's a bug. Any help is appreciated, thanks!
Code to set up table:
- (TBMessageViewCell *)getMessageCellforTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"MessageCell";
TBMessageViewCell *cell = (TBMessageViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[TBMessageViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
[cell createSubviews];
}
// Set the new message and refresh
[cell setMessage:self.viewModel.messages[indexPath.row]];
[cell populateSubviews];
cell.backgroundColor = [UIColor blueColor];
NSLog(#"cell Width: %f", cell.contentView.frame.size.width);
return cell;
}
Complete TBMessageViewCell:
#implementation TBMessageViewCell
const CGFloat MARGIN = 10.0f;
const CGFloat AVATAR_SIZE = 40.0f;
-(id)initWithStyle:(UITableViewCellStyle *)style reuseIdentifier:(NSString *)reuseIdentifier
{
if(self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]){
}
// Sets background and selected background color
self.backgroundColor = [UIColor clearColor];
UIView *selectionColor = [[UIView alloc] init];
selectionColor.backgroundColor = [UIColor clearColor];
self.selectedBackgroundView = selectionColor;
return self;
}
- (void)populateSubviews
{
// Set the message body
[self.messageBodyLabel setText:self.message.body];
[self.messageBodyLabel setTextAlignment:NSTextAlignmentRight];
CGRect bodyFrame = CGRectMake(MARGIN, MARGIN, self.frame.size.width - (AVATAR_SIZE + (MARGIN * 3)), self.frame.size.height);
// Calculates the expected frame size based on the font and dimensions of the label
// FLT_MAX simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(bodyFrame.size.width, FLT_MAX);
CGRect textRect = [self.message.body boundingRectWithSize:maximumLabelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:self.messageBodyLabel.font}
context:nil];
bodyFrame.size.height = textRect.size.height;
// Setup the new avatar frame (Right aligned)
CGRect avatarFrame = CGRectMake(bodyFrame.size.width + (MARGIN * 2), MARGIN, AVATAR_SIZE, AVATAR_SIZE);
// Align to the LEFT side for current user's messages
if ([[TBConfig userID] isEqualToString:self.message.user.userID]) {
// Set avatar to left if it's me
avatarFrame.origin.x = MARGIN;
bodyFrame.origin.x = AVATAR_SIZE + (MARGIN * 2);
[self.messageBodyLabel setTextAlignment:NSTextAlignmentLeft];
}
self.avatar.frame = avatarFrame;
self.avatar.layer.cornerRadius = self.avatar.frame.size.width/2;
self.messageBodyLabel.frame = bodyFrame;
// Set the new cell height on the main Cell
CGFloat cellHeight = MAX(bodyFrame.size.height, self.frame.size.height) + MARGIN;
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, cellHeight);
// Set the new Profile avatar
if (![self.avatar.profileID isEqualToString:self.message.user.facebookID]) {
[self.avatar setProfileID:nil];
[self.avatar setProfileID:self.message.user.facebookID];
}
}
- (void)createSubviews
{
self.messageBodyLabel = [[UILabel alloc] init];
self.messageBodyLabel.textColor = [UIColor whiteColor];
self.messageBodyLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.messageBodyLabel.numberOfLines = 0;
[self addSubview:self.messageBodyLabel];
// Creates the avatar
self.avatar = [[FBProfilePictureView alloc] init];
[self.avatar setPictureCropping:FBProfilePictureCroppingSquare];
[self addSubview:self.avatar];
}
You're printing the size of the cell before it has been added to the display — before it has been sized. It doesn't yet know the size of tableview it will be added to.
The cells will be given an appropriate frame when added to the display.
EDIT: oh, and you probably don't want that cellIdentifier to be static. You probably wanted *const.
Don't know if you have found the answer. I faced the same problem when I was trying to subclass UITableViewCell and add custom subviews programmatically without using xib.
Finally the solution worked for me is to use [[UIScreen mainScreen] applicationFrame] instead of self.frame when calculating subviews' frames.
The proper way to solve this is to perform your layout in the layoutSubviews method.
In your case, simply call "populateSubviews" within "layoutSubviews" method, like this:
- (void)layoutSubviews {
[super layoutSubviews];
[self populateSubviews];
}
... but before doing this I would recommend that you do content population in a separate method (ie, calls to label.text = ...), and place all layout-affecting calls (ie, label.frame = ...) below [super layoutSubviews] in the method above.
That would result in something like:
- (void)layoutSubviews {
[super layoutSubviews];
CGRect bodyFrame = CGRectMake(MARGIN, MARGIN, self.frame.size.width - (AVATAR_SIZE + (MARGIN * 3)), self.frame.size.height);
// Calculates the expected frame size based on the font and dimensions of the label
// FLT_MAX simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(bodyFrame.size.width, FLT_MAX);
CGRect textRect = [self.message.body boundingRectWithSize:maximumLabelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:self.messageBodyLabel.font}
context:nil];
bodyFrame.size.height = textRect.size.height;
// .. the rest of your layout code here ..
}
- (void)populateSubviews {
[self.messageBodyLabel setText:self.message.body];
// .. the rest of your code here ..
}
After you set your avatar frame in:
self.avatar.frame = avatarFrame;
self.avatar.layer.cornerRadius = self.avatar.frame.size.width/2;
self.messageBodyLabel.frame = bodyFrame;
write
self.avatar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin;
It should hook your avatar image to the right margin and leave the left margin as flexible.
Select your table view cell's connection inspector and check if you haven't connected editingAccessoryView by mistake
While this answer may not be as straightforward as you'd expect UIKit to deliver, due to a bug in UITableView - when doing things programmatically - you gotta get your hands dirty. Xib lovers - be warned - this answer isn't for you. It's probably just working.
In later IOS versions, let's hope this problem get resolved. The problem is uitableview is hardcoding the dimensions of the cell to 320. In one project I had - I was forcing the frame size to to fix this. N.B. this has problems with splitview controller on iPad.
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"cell frame width:%f",cell.frame.size.width); // you should see <- 320! WTH
// you can crudely correct this here
cell.frame = CGRectMake(0,0,[[UIScreen mainScreen] applicationFrame].size.width,CELL_HEIGHT);
}
Another option - that's working better for me is a local width variable to reference. I know this code is not ideal - but it works consistently.
#interface AbtractCustomCell : UITableViewCell {
float width;
}
#end
#implementation AbtractCustomCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//optimise speed
// [self setOpaque:YES];
if ([SDiPhoneVersion deviceSize] == iPhone47inch) {
width = 375;
}
else if ([SDiPhoneVersion deviceSize] == iPhone47inch) {
width = 414;
}
else {
width = 320; // hardcode iphone 4/5 /ipad2
}
}
return self;
}
#end
then you have the option to make TBMessageViewCell a subclass of this AbstractCustomCell which will have this variable there for you. Instead of using self.contentView.bounds.size.width / self.bounds.size.width just use width.
I'm programmatically layout without Storyboard and facing same issue, and I need to return the cell upon cellForRowAt indexPath which in turn it still didnt manage to get the container size yet.
And I manage to solve it by move the layout codes into willDisplay cell delegate.

UICollectionView Cell Frame Has Decimal Origin Value

I have a UICollectionView that I created programatically. Each cell in the collection view displays a label, and all the labels have identical properties. Despite this, I noticed that the text contained in each label in the center column of the collection view looked blurry.
A recursive description of the collection view shows that the center cell in the table always has an x origin that is a decimal value:
<UICollectionViewCell: 0xd98c1e0; frame = (242.5 0; 220 45); layer = <CALayer: 0xd98c270>> ...
My questions are: 1) could this be causing the bluriness? and 2) What is the best way to ensure that none of the x and y origins end up having a decimal value? (Aside from manually calculating the layout)
For reference, here is my UICollectionView code:
//subclass UICollectionViewFlowLayout
#implementation LabelLayout
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
}
- (id)init
{
self = [super init];
if (self) {
[self setup];
}
return self;
}
-(void)prepareLayout
{
[super prepareLayout];
_cellCount = [[self collectionView] numberOfItemsInSection:0];
}
- (void)setup
{
self.itemSize = CGSizeMake(220.0f, 45.0f);
self.sectionInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
self.minimumLineSpacing = 10.0f;
self.minimumInteritemSpacing = 20.0f;
}
#end
This would definitely cause blurring as everything is being anti-aliased across two pixels (Note: On a retina screen, you won't see any blurring because each point is actually two pixels so half points technically exist as a single pixel). To fix it you might have to use CGRectIntegral to force the frame to integer bounds. The best way to do that would be:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
for (NSLayoutAttributes *attribute in attributes){
attribute.frame = CGRectIntegral(attribute.frame);
}
}
You should do the same thing for layoutAttributesForItemAtIndexPath:.

Resources