Adjust height of Storyboard-created UITableview to height of its contents - objective-c

I've dragged a table view into my storyboard scene, but its height is static and won't adjust based on how many cells it contains unless I manually adjust it in storyboard. How can I get this table to adjust its own height based on the total height of its contents?

You're going to have to do some version of this:
Figure out how many cells will be displayed
Figure out the height for each cell
Do the math and set the height of the UITableView
Before you get mad (since I know that's pretty obvious), let me follow up with this:
If you know for sure how many cells will be displayed all the time (and it's a static value), you can just manually adjust the height in Interface Builder.
If you don't know for sure (which I'm guessing is the case, based on your question), you'll have to do #'s 1 thru 3 above at runtime. Then, because UITableView is a subclass of UIView, you can simply adjust its frame property.
For example:
I've got 7 cells.
Cells 1, 3 and 5 (indices 0, 2 and 4) are 20 pixels tall.
Cells 2, 4, 6 and 7 (indices 1, 3, 5 and 6) are 30 pixels tall.
I need a total display height of 180 pixels (you might actually need to play with this because of separators, etc..)
So, I can just call:
CGFloat newHeight = ... // Whatever you calculate
CGRect currentFrame = [[self MyTableView] frame];
[[self MyTableView] setFrame:CGRectMake(
currentFrame.origin.x,
currentFrame.origin.y,
currentFrame.size.width,
newHeight)
];
If you want to get really fancy, you can animate the change by wrapping it in a [UIView animationWithDuration:] block.
Hope this helps!
Update/Edit
Here's a kludgy way to do it... it works, but I'm sure there's a better way to do it. I do not claim this to be the best/fastest/most efficient way. This is more to show a principle. ;-)
- (CGFloat)totalHeightNeededForTableView:(UITableView *)tv {
CGFloat retVal = 0;
int sectionCount = [self numberOfSectionsInTableView:tv];
int rowCount = 0;
NSIndexPath *path = nil;
for (int i = 0; i < sectionCount; i = i + 1) {
rowCount = [self tableView:tv numberOfRowsInSection:i];
for (int j = 0; j < rowCount; j = j + 1) {
path = [NSIndexPath indexPathForRow:j inSection:i];
retVal = retVal + [self tableView:tv heightForRowAtIndexPath:path];
}
}
return retVal;
}

Related

UICollectionView column grid gaps

I am using UICollectionView flow layout in my iPad application. I have cells with different width and heights. When I used subclass of UICollectionViewFlowLayout as layout for collection view, it shows me gaps between cells.
If there is large cell in column, it makes grid and small cells of that column get render centered of that large cell in column. Is there any better way to tight cell wrapping?
I am using horizontal scrolling. I tried using layoutAttributesForElementsInRect: method, but didn't get succeed into that.
Please let me know if anyone has done same kind of thing by using layoutAttributesForElementsInRect: method or by other way...
Please find attached image. I need same kind of solution
Thanks in advance...
Use like this
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.minimumInteritemSpacing = 0;
layout.minimumLineSpacing = 2;
I subclassed UICollectionViewFlowLayout and in both my layoutAttributesForItemAtIndexPath: and layoutAttributesForElementsInRect: methods I have one method called
setLineAttributes:(UICollectionViewLayoutAttributes *)attributes visibleRect:(CGRect)visibleRect:
which contains:
if (attributes.indexPath.item == 0 || attributes.indexPath.item == 1 || attributes.indexPath.item == 2) {
CGRect f = attributes.frame;
f.origin.x = 0;
attributes.frame = f;
} else {
NSIndexPath *ipPrev = [NSIndexPath indexPathForItem:attributes.indexPath.item - 3 inSection:attributes.indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat rightPrev = fPrev.origin.x + fPrev.size.width + 10;
if (attributes.frame.origin.x <= rightPrev)
return;
CGRect f = attributes.frame;
f.origin.x = rightPrev;
attributes.frame = f;
}

Using drawRect with a pop over, need to display images

in my application I have a class name playGrid which contains three objects, an NSArray of images named plays, and two NSUIntegers rowCount and columCount for the amount of rows and columns in the popover that will be used.
For this example, I have 6 images and I am trying to show them over 2 columns and three rows. I am trying to display these views in a popover. Previously I was able to do this with blocks of colors, but now that I am trying to do with images I am unable to generate the popover correctly. Listed below is my drawRect code for the successful popover that shows the colors.
How would I convert this to work with UIImages instead of the colors?
In the example below, rowCount and columnCount are 2 and 3 just like the one we are trying to make, but the array is named colors, and contains six UIColor items.
- (void)drawRect:(CGRect)rect {
CGRect b = self.bounds;
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGFloat columnWidth = b.size.width / columnCount;
CGFloat rowHeight = b.size.height / rowCount;
for (NSUInteger rowIndex = 0; rowIndex < rowCount; rowIndex++) {
for (NSUInteger columnIndex = 0; columnIndex < columnCount; columnIndex++) {
NSUInteger colorIndex = rowIndex * columnCount + columnIndex;
UIColor *color = [self.colors count] > colorIndex ? [self.colors objectAtIndex:colorIndex] : [UIColor whiteColor];
CGRect r = CGRectMake(b.origin.x + columnIndex * columnWidth,
b.origin.y + rowIndex * rowHeight,
columnWidth, rowHeight);
CGContextSetFillColorWithColor(myContext, color.CGColor);
CGContextFillRect(myContext, r);
}
}
}
I know I will not need certain things like the color or the CGContextSetFillColorWithColor line, but how do i replace myContent with the image, it seems like this is what I would have to do, but I have not been able to successfully do this. Thanks again for your help as I am newer to Objective C.
Assuming that you want to continue to do drawing into the view using drawRect:, I think you just want to use the drawInRect: method on UIImage.
So:
UIImage *image = [plays objectAtIndex:rowIndex * columnCount + columnIndex];
[image drawInRect:r];
I've heard the performance of drawInRect is not great - but I haven't measured it myself. Note also that drawInRect: scales the image to fit the rect as needed; so visually, the results may not be what you intend.
An alternative is to compose your popover's view in a nib where you could layout your view statically. If you always want a 2x3 matrix, you could setup your view there with a 2x3 grid of UIImageView instances.
EDIT: (to clarify that you are drawing images in the rects now, no filling blocks of color)
- (void)drawRect:(CGRect)rect {
CGRect b = self.bounds;
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGFloat columnWidth = b.size.width / columnCount;
CGFloat rowHeight = b.size.height / rowCount;
for (NSUInteger rowIndex = 0; rowIndex < rowCount; rowIndex++) {
for (NSUInteger columnIndex = 0; columnIndex < columnCount; columnIndex++) {
CGRect r = CGRectMake(b.origin.x + columnIndex * columnWidth,
b.origin.y + rowIndex * rowHeight,
columnWidth, rowHeight);
UIImage *image = [plays objectAtIndex:rowIndex * columnCount + columnIndex];
[image drawInRect:r];
}
}
}

Resizing UITableView

I'm working on the project. Currently I'm facing a problem, I have 3 UITableView's in one ViewController. It looks something like this:
Now, The first TableView(top one), has just one row, that has a size of 55 pixels and it don;t have to be resizable. Next, second one is the TableView, again with one row, but this row must to resize depends on the content of it. Right now this TableView displaying this row:
This row must to resize depends on how long the text in it. What I did to calculate the size is:
if(tableView == self.usersPostOnTheWallTableView) {
NSDictionary *propertyItems = [self.repliesItems objectAtIndex:indexPath.row];
NSString *text = [self.postItems objectForKey:#"text"];
NSLog(#"%#", text);
CGSize constraintSize = CGSizeMake(280, MAXFLOAT);
CGSize sizeText = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
self.height = MAX(sizeText.height, 44.0f);
self.photosArray = [propertyItems objectForKey:#"attach_photos"];
self.videosArray = [propertyItems objectForKey:#"attach_videos"];
if((self.photosArray.count == 0) && (self.videosArray.count == 0)) {
height += (CELL_CONTENT_MARGIN * 2);
} else if ((self.videosArray.count > 0) && (self.photosArray.count == 0)) {
height += 90 + (CELL_CONTENT_MARGIN * 2);
} else if((self.photosArray.count > 0) && (self.videosArray.count == 0)) {
height += 85 + (CELL_CONTENT_MARGIN * 2);
}
}
Now, if the text is quite small, it fits the row well, and the row is resizes. Such as this:
But, after the text comes bigger, this what happening:
Obviously I don't need the scrolling right there, and I would disable it. But the thing here is that it takes the size of the text, and it resize the label, you can see how many space it make from the top and from the bottom of the label. But it don't put actual text there. Another thing is that it didn't resize the TableView it self, when I'm trying to resize it, I get the overlapping of the bottom table by the middle table.
Can anyone recommend any solution of this, or maybe another way of implementation?
Thanks in advance!
U can do this is use tableviewDelegate method for setting cell height according your text like this for example:
This method will be called for every cell to decide how much cell should have height
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *strDetails = [yourTextArray objectAtIndex:indexPath.row];
//if(indexPath.row == 1)
//{
CGSize stringSize = [strDetails sizeWithFont:[UIFont fontWithName:#"Marker Felt" size:13] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:UILineBreakModeWordWrap]; // Provide text as well as font name in which your text will be displayed and constrainedToSize which defines width and height it should be maximum
return stringSize.height+65; //Here 65 can be any value depending on Calculation ImageView height + uppermost space + bottom space added
//}
//else
//{
// return 80 // anything u wishes
//}
}

Display grid view of videos

I'm trying to display a grid view in a portrait and horizontal view of the iPad. Right now im just trying to pull this off on the portrait view, so you will see the according X, Y in the following code where i'm stuck.
- (void)renderPlaylist {
cellsArray = [[NSMutableArray alloc] init];
CGFloat xPos = 0.0f;
CGFloat yPos = 0.0f;
int i = 4;
int y = 1;
int p = 1;
for (BCVideo *video in [[self playlist] videos]) {
if (i > 0) {
ScrollCellViewController *cell = [[ScrollCellViewController alloc] initWithBCVideo:video];
[cell setDelegate:self];
[[cell view] setFrame:CGRectMake(xPos, yPos, 768.0f, 245.0f)];
[scrollView addSubview:[cell view]];
[cellsArray addObject:cell];
yPos = y * 235.0f;
y++;
i--;
}else{
i = 4;
xPos = p * 245.0f;
yPos = 0.0f;
y = 1;
p++;
}
//blabla lazy
CGSize size = CGSizeMake(2000.0f, 2000.0f);
[scrollView setContentSize:size];
}
}
The total of videos is 17. I want to display 4 videos in each row, and then move right, for the next row, the scroll view will be horizontal (like the TED app). It obviously needs to display four rows of 4, and then one row of 1. This currently outputs 3 rows of 4, and then 1 of 2. For a total of 14?
what?
exactly.
If i adjust the code to rows of 5, you get a total of 15 videos. If i just the code to rows of 6, you get a total of 16 videos.
Screenshot http://i53.tinypic.com/15oj687.png
Your code is wrong in several parts.
By following it and calling U the upper part of the "if" and L the lower part of the if, you repeat this pattern:
UUUULUUUULUUUULUU
Now every 4th U you calculate y=4*235=940 as upper-left corner and it is probably out of your view (e.g. if you have a navigation bar your view height will be exactly 940 pixels height!). So the 4th row is not visible because out of screen.
Besides each U cycle draws a view which is 768px wide and 245 high so it is an horizontal stripe. Now the first 3 Us from the first three videos draw the first three lines, the 4th U draws the line out of screen. Then the "L" does nothing, it skips the video (sic!) and set "p" such that the next sequence of 4 stripes will be shifted 245px right, which is probably buggy as the stripes are still 768px wide, so the next cycles these stripes will be partially out of screen (over the right border). Besides when you will start drawing the second sequence of UUUU you will overwrite them over the existing ones but shifted 245px right.
Well, I don't know what you want to do, but it seems quite complex for a grid and it is obviously buggy. You should take care of your "swiping" code before and then you can debug it by printing in the console the position of all your videos and try to debug it. Don't try to fix it by looking for magic numbers in the parameters.
Solution:
- (void)renderPlaylist {
cellsArray = [[NSMutableArray alloc] init];
CGFloat xPos = 0.0f;
CGFloat yPos = 0.0f;
// y => counter for position of vertical videos
int y = -1;
// p => number of rows
int p = 0;
// r => check
int r = 0;
for (BCVideo *video in [[self playlist] videos]) {
r++;
// vertical rows
if (y < 3) {
y++;
yPos = y * 200.0f;
}else{
// move sideways to the right one row, and reset the vertical row
p++;
xPos = p * 255.0f;
yPos = 0.0f;
y = 0;
}
//print video
ScrollCellViewController *cell = [[ScrollCellViewController alloc] initWithBCVideo:video];
[cell setDelegate:self];
[[cell view] setFrame:CGRectMake(xPos, yPos, 255.0f, 210.0f)];
[scrollView addSubview:[cell view]];
[cellsArray addObject:cell];
CGSize size = CGSizeMake(xPos + 250.0f, 1024.0f);
[scrollView setContentSize:size];
}
}

NSTableView - Trying to fit exactly 9 rows

I'm trying to size the rows of a NSTableView to exactly 9 rows fit. I've tried [menuTableView setRowHeight:floor(menuRect.size.height / 9)]; and I've tried [menuTableView setRowHeight:(menuRect.size.height / 9)]; and [menuTableView setRowHeight:ceil(menuRect.size.height / 9)]; but all of them have the same issue, if I've selected row 0 then row 9 is clipped at the bottom and if I select row 9 then row 0 is clipped at the top.
How can I set up a NSTableView to show 9 full rows so no matter what there is never a partial row visible?
Thanks,
edit: Yes menuRect is the frame for the menuTableView
edit:
Below is the full method I use to position the NSTableView and set the row height I've tried to remove any rounding issues with the use of the rowHeight variable. You can see with the attached screen shot that the last row isn't fully displayed
- (void) updateGUIPositions
{
NSRect screenRect = [self frame];
NSRect menuRect;
// Set the menu location on screen
NSInteger spacer = screenRect.size.width / 9;
menuRect.size.width = floor(screenRect.size.width - (spacer * 3)) / 2;
menuRect.size.height = ceil(screenRect.size.height - (spacer * 2));
NSInteger rowHeight = menuRect.size.height / 9;
menuRect.size.height = rowHeight * 9;
menuRect.origin.x = menuRect.size.width + (spacer * 2);
menuRect.origin.y = spacer;
[menuScrollView setFrame:menuRect];
// Setup the row height
[menuTableView setRowHeight:rowHeight];
}
I am not sure if this will work, but it sounds like a rounding error(I had the same problem with a UITableView). Try making the height of the NSTableView's frame 1px larger. So, menuTableView.frame.height = menuTableView.frame.height+1;
EDIT
Try using this...
`float rowHeight = menuRect.size.height / 9.0f;`
If you can fix the size of the rows and instead set the size of the frame programmatically, this related question suggests this formula works:
numRows * (rowHeight + intercellSpacing.height)
Using that formula, the scroller will draw, but you could just turn it off.