Automatically determining the size of a UITableViewCell - iphone

I am trying to determine the size of a UITableCellView. The reason being that I am using one class for different orientations and devices.
The cell contains one subview that is supposed to fill the entire cell. Right know I'm doing this in the UITableViewCell's init method:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
//iPad
subv = [[OrbitView alloc] initWithFrame:CGRectMake(52, 5, 660, 420) ];
}else{
//iPhone
subv = [[OrbitView alloc] initWithFrame:CGRectMake(15, 5, 290, 200) ];
}
Clearly, there must be a better way of doing this, without the magic numbers. How/Where should I set the frame of the subview in the UITableViewCell so that it fills the entire UITableViewCell?

Use the dimensions of the table view that the cell will go in. Set the autoresizingMask to flexible width to handle rotation and accessory views. This code assumes you have set the rowHeight of the table, but you could use a fraction of the screen height instead of testing the device type.
-(CGRect) cellFrameForTableView:(UITableView *)inTable {
CGRect result = [inTable frame];
result.origin = CGPointZero;
result.size.height = [inTable rowHeight];
return result;
}
Add your custom view to the cell content, not the cell, if you want auto sizing to adjust your view to leave room for cell extras like accessory views. In that case things like edit controls will adjust your custom view along with the content view.
In the past I have had trouble with flexible height views in cells, so I would go with flexible bottom margin instead.

Related

UICollectionViewCells with UICollectionViewFlowLayout - strange layout happening

I am currently testing in xcode a UICollectionView with just one horizontal row like a kinda cover flow. Basically I have my own Custom Cell class and xib file for the cell and then on each cell I am adding another UIView with a xib. In case you are wondering why, it is so I can add different UIViews to the cell. Right now I am only adding one.
Edit I have followed the WWDC 2012 video on creating a linelayout of a UICollectionViewCell with one difference. Instead of the cell in the middle getting bigger all the other cells get smaller.
Everything below is new to my question.
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *array = [super layoutAttributesForElementsInRect:rect];
CGRect visibleRect;
visibleRect.origin = self.collectionView.contentOffset;
visibleRect.size = self.collectionView.bounds.size;
for (UICollectionViewLayoutAttributes *attributes in array){
if (CGRectIntersectsRect(attributes.frame, rect)) {
CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;
CGFloat normalizedDistance = distance / ACTIVE_DISTANCE;
if (ABS(distance) < ACTIVE_DISTANCE) {
//THIS WOULD MAKE THE MIDDLE BIGGER
//CGFloat zoom = 1 + ZOOM_FACTOR *(1- ABS(normalizedDistance));
//attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0);
//attributes.zIndex = round(zoom);
} else {
//THIS MAKES ALL THE OTHERS NOT IN THE RECT SMALLER
CGFloat zoom = 1 + ZOOM_FACTOR *(1- ABS(normalizedDistance));
attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0);
attributes.zIndex = round(zoom);
}
}
}
return array;
}
The problem can be seen in the attached image.
Pink = Collection View Size
Brown = Cell size
Green = Cells Content size and an attached xib to the content size.
The problem I THINK I have is with the layout. When the sell is dequeued it is made smaller by the above code. Then when it is reused the CELL gets bigger again but the content view does not.
I have tired to manually set the frame of the content view but that does nothing.
UPDATE 1: This also only happens when I add a xib to the Cells content view. If there is no subview to the content view then there is no problem
UPDate 2: It appears that the subview of the cell, my xib is not resizing. I have tried to manually change its frame size but the only place this helps is in the cells drawrect method which feels like a hack to me.
reused cell not able to redraw itself so give call to
-(void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self setNeedsDisplay]; // force drawRect:
}
from cellForItemAtIndexPath of the UICollectionView.
also have a look at this link
and this question
My answer is very specific and I am not sure it will help anyone.
The problem was that I had a constraint on the bottom of the grey view. After I changed this constraint to a less than or equal too then for some reason it worked.
Now I know this does not explain why it was not happening to every cell but it fixed my problem.
As such Harsh's answer might also be worth looking at if you have landed here after doing a search.
Edit: there also appears to be some bugs in the 6.0 UiCollectionView controller which seem to be fixed in 6.1

objective c- adding few subviews to a UITableViewCell

I have a UITableView that displays images, but I want some text to be displayed above and under every image.
when I add text it's being displayed in the center behind the image.
how can I programmatically control the position of subviews in my cell ?
(the number of cell changes during the program at runtime)
thanks
inside cellForRowAtIndexPath add your text as subviews (e.g. x= 10, y = 20, width = 200, height = 100) :
myText = [[UITextView alloc] initWithFrame:CGRectMake(10, 20, 200, 100)];
myText.text = #" some text here";
[self addSubview:myText];
to bring the text to the front:
[self bringSubviewToFront:myText];
I would create a custom UITableViewCell to be honest. Subclass it and add the views you want to its contentView in its initialiser, then set it up as you wish for each cell in your table view data source.
First of all you should have mentioned if you are using a custom cell or not. in case it's the built-in cell that you are using, if you don't like the way it looks you should create a custom cell. see http://www.icodeblog.com/2009/05/24/custom-uitableviewcell-using-interface-builder/
If you allready use a custom cell, my guess is that you didn't implement correctly the method
heightForRowAtIndexPath:
please check if a fix is needed...

How to add a subview to a tableview only covering the table cell but not the table header view

I'm using a UISegmentedControl as the headerview of a tableview. Now I want to add loading view (a view defined by myself) only covering the table cells but not my headerview. How do I achieve this?
You can add this view to the cell you want:
UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:indexPathOfCell];
[cell addSubview:view];
The simplest way to add the loading view would be like this
// get the frame of your table header view
CGRect headerFrame = headerView.frame;
// construct a frame that is the screen minus the space for your header
CGRect loadingFrame = [[UIScreen mainScreen] applicationFrame];
loadingFrame.origin.y += headerFrame.size.height;
loadingFrame.size.height -= headerFrame.size.height;
// use that frame to create your loading view
MyLoadingView *loadingView = [[MyLoadingView alloc] initWithFrame:loadingFrame];
// add your view to the window *
[[headerView window] addSubview:loadingView];
* Adding the view to the window may not be the best thing for your design, but since I don't know any of the details of your view hierarchy, this is the way that will always work.
Caution: If you do not cover up the segmented control, and it is enabled, the user may click on it and change the state of the app when you aren't expecting it - like when you're trying to load something for them. Be sure that you can cancel this loading view if the user changes the state of the app.

How can I modify the appearance of 'empty' cells in plain UITableView?

If you have a plain (not grouped) UITableView with a single row, the rest of the screen is filled with blank or empty cells. How do you change the appearance of these blank cells? Af first, I thought they would have the appearance of the cell used in the table view but it seems they don't.
The people from Cultured Code (Things) have done a nice job modifying these cells but I can't immediately think of a way to change their appearance.
Any tips?
Although it's not quite what you're looking for, you can also change it to just display a blank region (instead of blank cells) by setting a footer view on the table. A UIView of height 0 will do the trick.
Based on samvermette's answer, but modified to use a background image directly rather than compositing an image from a UITableViewCell subclass. Sam's answer is good, but it will be less performant than just creating a background image directly.
Create a UIView subclass -- in this example I called it CustomTiledView -- and add the following code to the class:
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed:#"tableview_empty_cell_image"];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextScaleCTM (context, 1, -1);
CGContextDrawTiledImage(context,
CGRectMake(0, 0, rect.size.width, image.size.height),
[image CGImage]);
}
Add the following code to your tableviewcontroller:
- (CGFloat)tableView:(UITableView *)tableView
heightForFooterInSection:(NSInteger)section {
// this can be any size, but it should be 1) multiple of the
// background image height so the last empty cell drawn
// is not cut off, 2) tall enough that footer cells
// cover the entire tableview height when the tableview
// is empty, 3) tall enough that pulling up on an empty
// tableview does not reveal the background.
return BACKGROUND_IMAGE_HEIGHT * 9; // create 9 empty cells
}
- (UIView *)tableView:(UITableView *)tableView
viewForFooterInSection:(NSInteger)section {
CustomTiledView *footerView = [[CustomTiledView alloc] init];
return [footerView autorelease];
}
Finally, you'll need to set the bottom content inset of your tableview to the negative of the value returned from -tableView:heightForFooterInsection: In this example it would be -1*BACKGROUND_IMAGE_HEIGHT*9. You can set the bottom content inset either from the Size Inspector of Interface Builder or by setting the self.tableView.contentInset property from the tableviewcontroller.
Cheers!
I set a ~300px-high UIView subclass to my tableView header and footer views, adjusting the tableView insets so they compensate for these views (set the top and bottom insets to -300px).
My UIView subclass implements the drawRect method, in which I use CGContextDrawTiledImage() to draw an empty UITableViewCell repetitively:
- (void)drawRect:(CGRect)rect {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(300, 46),NO,0.0);
emptyCell = [[SWTableViewCell alloc] initWithFrame:CGRectZero];
[emptyCell drawRect:CGRectMake(0, 0, 300, 46)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
[emptyCell release];
UIGraphicsEndImageContext();
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextScaleCTM (context, 1, -1); // this prevents the image from getting drawn upside-down
CGContextDrawTiledImage(context, CGRectMake(0, 0, 300, 46), [newImage CGImage]);
}
In my case my tableviewcells are 46px high, so if I want make UIView subclass to contain 8 of these empty cells, I need to make it 368px high.
From http://jomnius.blogspot.com/2011/03/hide-uitableview-empty-cell-separator.html
Easy way is to define that table has no cell separator lines:
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
Hard way, if you need separator lines, is to define that table has no separator lines and create cell separator lines as part of custom UITableViewCell. Bottom part of cell, obviously, and most likely using really thin graphics image. Remember to define image autosizing and mode properly.
Another way is to define an empty UITableView's tableFooterView:
UIView *footer =
[[UIView alloc] initWithFrame:CGRectZero];
self.myTable.tableFooterView = footer;
[footer release];
If you simply want to change the height of the "empty cells" when there are no cells at all in your TableView: you need to set the rowHeight property of your UITableView (the implementation of tableView:heightForRowAtIndexPath: has no effect on empty TableViews). If there are cells in your TableView and you have implemented tableView:heightForRowAtIndexPath: then the last row height will be used for empty cells.
You will probably have to make a custom subclass of UITableView that fills the background with the appearance of blank cells.
- (void)drawRect:(CGRect)rect {
[super drawRect: rect];
// draw your background here if the rect intersects with the background area
}
I believe the approach of using the UITableView tableView:viewForFooterInSection: method will not work for the case where the table is empty, ie., with no cells. In that case, you can use the technique Answerbot proposed can be repurposed to stuff the created UIView into the table's footer view explicitly, like the following:
CGRect cellRect = CGRectMake(0, 0, table.bounds.size.width, table.bounds.size.height);
CustomTiledView *footerView = [[[CustomTiledView alloc] initWithFrame:cellRect] autorelease];
table.tableFooterView = footerView;
For swift 4.0 :
self.tableView.tableFooterView = UIView(frame: CGRect.zero)

How do I push grouped tables down in the view on the Iphone?

Below shows the default position when you add a grouped table to a view? How do I push the entire grouped table down in the view?
(source: pessoal.org)
You can assign a transparent view with a fixed height to the tableHeaderView property of the tableView. This will push the table contents down by the height of the transparent view.
You can do this from your UITableViewController's viewDidLoad:
// force the table down 70 pixels
CGRect headerFrame = self.tableView.bounds;
headerFrame.size.height = 70;
UIView *header = [[UIView alloc] initWithFrame: headerFrame];
header.backgroundColor = [UIColor clearColor];
self.tableView.tableViewHeader = header;
[header release];
Look at the delagate to the UITableView.
You will find a property 'heightForHeaderInSection'.
For section 0 just make the header larger (default is 0) it will push the table down the view.
If you are moving the table down, you undoubtedly wish to use the space you gain to add UI elements.
At that point, consider building the page in IB. You can resize the table view to be where you like and put the UI elements above the table. You can use a UIViewController to manage the page and add the UITableViewDelegate/Datasource protocol methods so that you can wire the UITableView back to your view controller as a delegate... then you can also wire the other UI elements to the same view controller.
The simplest way to do it is probably just to modify the frame for the tableview. You'll need to get a reference to the tableview in your controller either through an IBOutlet or by finding the view in the view hierarchy OR you can change the frame in Interface Builder.
In code something like:
tableView.frame = CGRectMake(0.0, 200.0, 320.0, 280.0);
Would position the tableview down the screen and limit its height - the dimensions you use will be dependent on whether you had a tab bar on the view and things like that.
In interface build just select the tableview, then choose the Size inspector (the inspector tab with the ruler icon) and set the height and y offset to shift it down the view.