How do i change the location of the text in UITableView? - iphone

How do i change the location of the text AND show the FULL string in UITableView?
Here is a screen shot of what I have, once you look at it you will know what I mean. Thanks
My App http://img188.imageshack.us/img188/9926/chucknhelp.tif

You can do it without subclassing UITableViewCell.
In the method tableView:cellForRowAtIndexPath:, create a basic UITableViewCell and change the properties of the UILabel contained in this cell. Change the maximum number of lines to fit more text in your cell.
Unfortunately, the label of the cell is not accessible by properties, so you need to fetch it with the subviews property.
Of course this uses an implementation detail of UITableViewCell, so it might break with future releases of the SDK. Use with care.
Here is an example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"YourCellId"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"YourCellId"] autorelease];
cell.font = [UIFont systemFontOfSize:16];
UILabel* cellLabel = [cell.contentView.subviews objectAtIndex:0];
[cellLabel setNumberOfLines:3];
}
cell.text = #"Your text";
return cell;
}
Update:
To set the row height to fit the text, you can do the following:
1. Set the cell height to fit the text.
You need something like this:
CGSize textSize = [text sizeWithFont:font
constrainedToSize:CGSizeMake(313, 1000)
lineBreakMode:UILineBreakModeWordWrap];
cell.frame = CGRectMake(0.0f, 0.0f, 320.0, textSize.height);
2. Return the cell height in the tableView:heightForRowAtIndexPath: method.
For example like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [self tableView:(UITableView*)self.view cellForRowAtIndexPath:indexPath];
CGRect cellFrame = cell.frame;
return cellFrame.size.height;
}

Subclass UITableViewCell, and in the subclass's loadView method, create a UILabel inside its contentView. Set this label to have the appropriate wrapping and location.

Adam has it right. For a little more detail (as well as a method that scrolls lightning fast) you can check out this entry on atebits.com that bypasses the UILabel approach entirely.
Loren Brichter's UITableViewCell subclassing example
You can also look at the TableViewSuite example from developer.apple.com It contains 5 different examples, in increasing complexity, for building custom TableViews. The last example is structurally very similar to the tutorial on atebits.com.
Lecture 8 of the Stanford iPhone course is also all about Scroll and TableViews, and has some examples of subclassing UITableViewCell.
iPhone Course

Related

Proper way to add subview to UITableViewCell contentView

In my application i need to display multiple images in a UITableView,so i've already searched a lot in the web for the proper way to load large images to UITableViewCells,to be more clearly i'll divide the procedure that my app execute:
Download images asynchronous;
Save them to NSHomeDirectory();
=> Thins part is working perfectly.
The problem is,how to display the images in the UITableViewCell,i've already tried to add UIImageView's to the cell contentView but the scrolling performance were a bit affected,i've searched on Apple guides and i believe the correct way is adding UIImageView's to the cell and loading the images from NSHomeDirectory(),so:
What's the best way to customize a UITableViewCell and add the UIImageView's(302x302px) to it?
To get the best scroll performance, you must draw the content of the UITableViewCell yourself.
Loren Brichter, the author of the Tweetie app (now the official Twitter app), wrote a very famous blog post on this. Sadly, this blog post has been deleted.
This article may help you, though. It explains the fast scrolling, it has examples and it has a video to a presentation from Loren Brichter.
Basically, what you want to do is to subclass UITableViewCell and override the drawRect:method. To show an image, you would do something like the following:
- (void)drawRect:(CGRect)rect
{
[myImage drawAtPoint:CGPointMake(10, 10)];
}
This way you avoid to layout a lot of subviews.
I have the same question.
I'm doing the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString* CustomCellIdentifier = #"CustomCellIdentifier";
CustomCell* cell = [tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifier];
}
// add subview to cell
if (cell.customView == NULL) {
cell.customView = [[CustomView alloc] initWithFrame:cell.frame];
[cell.contentView addSubview:cell.customView];
}
// bind cell data
return cell;
}
Firstly, you need to create a custom cells for UITableView & keep going through following points.
set height of each row to 302 pixels as
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 302.0;
}
Use following code to create UIImageView at each cell of table
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:#"cell"];
const NSInteger IMAGE_VIEW_TAG=1001;
UIImageView *imageView;
if(cell==nil)
{
cell=[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"] autorelease];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
imageView =[[[UIImageView alloc] initWithFrame:CGRectMake(10, 0, 302, 302)] autorelease];
imageView.tag=IMAGE_VIEW_TAG;
imageView.contentMode=UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:imageView];
}
imageView=(UIImageView*)[cell.contentView viewWithTag:IMAGE_VIEW_TAG];
[imageView setImage:[UIImage imageNamed:#"image.png"];
return cell;
}
set number of rows you want to display
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
dont forget to add TableView delegate and data source , UITableViewDelegate and UITableViewDataSource

one image or thumbnail for cells in a table view

i have the following code which will displays result in a UItable view along with an image.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//create a cell
UITableViewCell *cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
// fill it with contnets
NSDictionary *exercise = [exercises objectAtIndex:indexPath.row];
cell.textLabel.text = [exercise valueForKey:#"player"];
UIImage *image = [UIImage imageNamed:#"iphone.gif"];
cell.imageView.image = image;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
// return it
return cell;
}
is there an option where i can display one image for all the cells for ex. 1 image on the left side and then 3 rows by the right side. I am a new bid and still getting my grip on iPhone coding.Please suggest me how we can do this.Thanks.
Yup, a UITableViewCell is pretty much another UIView, so you can add subviews to it and customize it anyway you need. For example, if you need to add an image to all the cells, just add it onto the contentView;
[cell.contentView addSubview:myImageView];
If you have several customizations needed for your cell, and are looking for a highly custom look as opposed to the generic look provided by the standard cells, I'd recommend looking into creating a custom UITableViewCell. The reason is that the standard cells have already laid out UI's with labels, images etc, and anything you add onto it may interfere with the existing UI in ways you do not intend.

Adding a subview larger than cellHeight to a UITableViewCell?

I'm trying to add a subview to a UITableViewCell and the design that I'm working from demands that this particular subview (an image) needs to be larger than the actual UITableViewCell and thus partly overlap its siblings.
So I've set up my table cell, generated my image and added it to the cell's contentView:
// rowHeight for the UITableView is 45.0f
UIImage *image = [self createCellThumbnail: someImage];
UIImageView *thumbView = [[UIImageView alloc] initWithFrame: CGRectMake(150, -5, 55,55)];
thumbView.transform = CGAffineTransformMakeRotation(0.1f);
thumbView.image = image;
cell.clipsToBounds = NO;
cell.contentView.clipsToBounds = NO;
[cell.contentView addSubview: thumbView];
While the image will 'overflow' into the cell below it, the top of the image is always clipped, as demonstrated here:
Does anyone know if what I'm trying to do is possible with the current approach?
Or should I just figure out a way to draw these images onto the UITableView after all the cells are drawn (it's a non-scrollable tableview, so that would work and be fairly easy).
Update:
Have also tried adding the following, to no avail:
cell.opaque = NO;
cell.contentView.opaque = NO;
cell.clearsContextBeforeDrawing = NO;
cell.contentView.clearsContextBeforeDrawing = NO;
cell.clipsToBounds = NO;
cell.contentView.clipsToBounds = NO;
I seems that the tableView renders its cell from bottom to top, so the cells above one cell overlap that one cell. To avoid this, you'd have to set the backgroundColor of all cells to +[UIColor clearColor] so that you won't see those overlap problems.
But setting the backgroundColor to clear in -tableView:cellForRowAtIndexPath: does not make any sense. UIKit does a lot of stuff with the cell before it's drawn, so does it reset the backgroundColor property of the cell.
What we need to do is setting the backgroundColor in a later state. Luckily there is this -[UITableViewDelegate tableView:willDisplayCell:forRowAtIndexPath:] which we can implement like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [UIColor clearColor];
}
Now we're setting the backgroundColor just before the cell is drawn an this turns out to be working.
UPDATE:
So I've done some more experimentation and the following solution still works without having to set the background of the cell to transparent, this involved moving the z order of the covered cell. This works with highlighting and selecting of the other cell (via the relevant callbacks), and if the two cell's backgrounds are different colors. Solution is as follows (you can ignore the didHighlight and didSelect methods if they don't matter to you):
(note that "covered row" is the one whose content we are trying to keep visible and In my case its content goes slightly into the row above, which was clipping it)
-(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == ROW_ABOVE_COVERED_ROW)
{
NSIndexPath * rowbelow = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:rowbelow];
[cell.superview bringSubviewToFront:cell];
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == ROW_ABOVE_COVERED_ROW)
{
NSIndexPath * rowbelow = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:rowbelow];
[cell.superview bringSubviewToFront:cell];
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 && indexPath.row == COVERED_ROW)
{
[cell.superview bringSubviewToFront:cell];
cell.contentView.superview.clipsToBounds = NO;
}
}
NOTE: you should also set the background color of your content to clear, or it will adopt the bgcolor of the rest of your cell, and so when you manage to bring your content to the front of the covering cell, it will take the background color with it and leave a nasty looking block in the other cell (in my case my only content was the detailTextLabel and the textLabel):
// in cellForRowAtIndexPath:
[cell setBackgroundColor:[UIColor redColor]]; //using red for debug
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.backgroundColor = [UIColor clearColor];
I hope that's helpful to anyone else trying this....
ORIGINAL:
For me the solution was to use:
self.contentView.superview.clipsToBounds = NO;
My cells were already transparent, but my content was still getting clipped. In my case I was using a custom cell which moves it's content up in layoutSubviews. So layoutSubviews for my custom cell wound up as follows:
-(void)layoutSubviews
{
[super layoutSubviews];
self.contentView.frame = CGRectOffset(self.contentView.frame, 0, -11);
self.contentView.superview.clipsToBounds = NO;
}
I don't know if this would work if the cell above was opaque, or if the cells were to highlight when pressed, whether this would cover up my content.
However, I didn't need to make the cell transparent again in the viewWillDisplayCell callback method - doing it in the normal cellForRowAtIndexPath was sufficient
I had this problem and I made sure my custom tableviewcell's main background had clip subviews checked and it solved the problem. This was with a custom tableview cell loaded from a xib though. Not exactly the same but similar situation.
I actually had the opposite just yesterday, I had created a custom table cell and for some reason I got an overflow which I didn't want to have. My solution was to add the following code to my view controller class:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 175;
}
When it matched the height of the table cell there was no overlap; when it was too small there was overlap. Mind you though that I got very quicky behavious so I'm not sure it's a very good idea to do this.

Cocoa-Touch: How to: custom UITableViewCell with UIColor clearColor background

I have a UITableView with custom cells.
I have MyTableViewCell : UITableViewCell and MyTableViewCellContentView : UIView classes.
What I'm doing is basically what is done in the AdvancedTableViewCells demo app from Apple with a slight change, on some rows I want to use a clearColor background to show the table's background behind the painted text.
So in MyTableView's cellForRowAtIndexPath I'm doing:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"MyCell";
MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.someValue = indexPath.section;
[cell finishedSetup];
return cell;
}
And in my MyTableViewCell's finishedSetup:
cellContentView = [[MyTableViewCellContentView alloc] initWithFrame:CGRectMake(0, 0, 320, 80) cell:self];
cellContentView.autoresizingMask = UIViewAutoresizingNone;
cellContentView.contentMode = UIViewContentModeRedraw;
[self.contentView addSubview:cellContentView];
And in MyTableViewCellContentView I implement the drawRect method. And plan to not use any subviews but draw my custom content just as the Apple example does in the CompositeSubviewBasedApplication.
The problem is that for a few sections I want to use a clearColor backgroundColor. This works, until a cell with a non-clearColor backgroundColor is reused to draw a clearColor cell, at which time the background is not cleared and will still have the old color.
How can I make the background redraw?
Edit:
I forgot to mention, I'm setting the background color in MyTableViewCellContentView's init after calling super's init. Setting it via:
self.backgroundColor = [UIColor clearColor];
I've verified that this in fact does get called and is called as expected with clearColor or redColor.
I've also tried setting the table cell's background color, it didn't help.
Edit #2: Here's my drawRect method:
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
static int i = 0;
[[NSString stringWithFormat:#"Cell %d", ++i] drawAtPoint:CGPointMake(3, 3) withFont:[UIFont boldSystemFontOfSize:16]];
}
To make the background color setting take effect you need to do the setting in tableView:willDisplayCell:forRowAtIndexPath - the OS will not alter anything you set here. The reason is that some additional setup of the cell gets done by the OS after you return it from tableView:cellForRowAtIndexPath. If you can, get a look at session 101 from WWDC 09 presented by Jason Beaver.
I haven't found out why it was happening. But I've tried a different strategy. I'm no longer reusing table cells, since I don't have that many of them.
Instead I'm creating all cells at startup and actually get a boost in performance when showing them since this way there is no additional setup needed when scrolling.

UITableViewCell / UISegmentedControl border issue

I'm trying to get a UISegmentedControl in a group UITableViewCell much like in the wifi settings in the Setting Application. The problem I'm having is I'm getting a double border. I get one border for the UISegmentedControl and one for the UITableViewCell.
I'm guessing I need to remove the border from the UITableViewCell. How can I go about doing that?
I just noticed this is still getting answers. As it happens I've had to do this for another project and since I asked this question I've learned a lot more about iPhone dev. Here is how I solved it recently. It's all about making the frame the correct size. This should do it for a standard table.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if(cell == nil)
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellIdentifier"] autorelease];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithFrame:CGRectMake(-1.0f, -1.0f, 302.0f, 46.0f)];
[cell.contentView addSubview:segmentedControl];
In the case of the Wi-Fi settings, I suspect what they've done is made the "Forget this Network" button, the "IP Address" label, and the "DHCP/BootP/Static" segmented control all part of the table's header view. If you need to do this in the middle of your table (as opposed to at the top or bottom, for which you'd use the tableHeaderView and tableFooterView properties respectively), I'd suggest using the delegate methods -tableView:viewForHeaderInSection: with -tableView:heightForHeaderInSection, or the corresponding Footer variants. With any of those, you'd set up a custom view for that "section" of your table view (using either a clear background color or [UIColor groupTableBackgroundColor]), containing a label and a segmented control arranged so that they match up with the rest of the table sections.
Using the technique in this post to remove the background opacity of the UITableViewCell worked more easily for me to get only the UISegmentedControl to show in the table row.
I've got slightly further with this. So far I've subclassed UITableViewCell. I created a nib with a UISegmentedControl in it and I set the UITableViewCell background alpha to 0. It still doesn't look quite right, but it's better than before.
My solution is to allow the segmented control to resize to fit, and to hide the table view's background in tableView:willDisplayCell:forRowAtIndexPath:.
This yields results identical to the "Settings.app > WiFi > Your Network > IP Address" Segmented Control without hard-coding any layout metrics:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
UISegmentedControl *control = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"One", #"Two", #"Three", nil]];
control.segmentedControlStyle = UISegmentedControlStylePlain;
control.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
control.frame = cell.contentView.bounds;
[cell.contentView addSubview:control];
[control release];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundView.alpha = 0.0;
}
The trick appears to be to size the UISegmentedControl to the size of the backgroundView of the control, not the contentView. I was able to do it programmatically by doing the following:
// Size to cover the entire background
self.contentView.frame = self.backgroundView.frame;
self.myControl.frame = self.contentView.bounds;
Note that if you are using an accessory, you need to account for the accessoryView as well.
The reason is that the view hierarchy is as follows:
self (the UITableViewCell or subclass)
backgroundView
contentView
(your controls go here)
accessoryView
In portrait layout, the backgroundView's frame is {{9, 0}, {302, 44}}, whereas the contentView's frame is slightly smaller, at {{10, 1}, {300, 42}}. This gives the cell its 1px "border" when the table style is grouped. You have to resize both the contentView and your control to get the appropriate size.
(NOTE: While Apple actually has several examples of a UISegmentedControl in the UICatalog sample code project in the SDK, they effectively "cheat" by using a UIViewController and setting the main view's background color to the table background color.)