UITableView: How to offset text in cell? - iphone

Greetings,
I'm trying to implement a tableview with asynchronously loading images (80px x 60px). I have the async bit working, however my text (cell.textlabel.text) isn't showing up correctly - it overlaps the image!
Here is a photo of my iPhone:
Any ideas about how I might fix this?
I've tried setting a frame with CGRectMake, but it's not working... All out of ideas here and thought I'd ask the stackoverflow community.
Many thanks in advance,
Here is the code I am using:
-(UITableViewCell ) tableView:(UITableView)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
static NSString *CellIdentifier = #"ImageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithFrame:CGRectZero reuseIdentifier:CellIdentifier]
autorelease];
} else {
AsyncImageView* oldImage = (AsyncImageView*)
[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
CGRect frame;
frame.size.width=80; frame.size.height=60;
frame.origin.x=0; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc]
initWithFrame:frame] autorelease];
asyncImage.tag = 999;
NSString *urlStr = [[NSString alloc] initWithFormat:#"http://www.example.com/driverPhotos/%#/%#_80.png",[options objectAtIndex:[indexPath row]],[images objectAtIndex:[indexPath row]]];
NSURL* url=[NSURL URLWithString:urlStr];
[asyncImage loadImageFromURL:url];
[cell.contentView addSubview:asyncImage];
cell.textLabel.frame=CGRectMake(100, 0, 220, 60);
cell.textLabel.text=#"Hi";
return cell;
}

You can't change the frame's of any of the default subviews (detailTextLabel, textLabel, imageView, etc) If you really want to then you'll have to subclass UITableView and override Layout Subviews..
I'd suggest ignoring cell.textLabel and creating your own UILabel and adding it to cell.contentView in the same way you are adding your AsyncImageView (with tags, etc).
If you don't set anything on cell.textLabel then it won't appear and cover up your AsyncImageView. (however if it does then just bring you AsyncImageView to the front)
Btw, if you press the Home button and the lock button at the same time, the iPhone will take a screenshot for you and save it into the photoalbum. Where you can email it to yourself and get it on your PC.

Or you can have a custom cell and implement x, y in layoutSubviews:
-(void) layoutSubviews
{
[super layoutSubviews];
[[self textLabel] setFrame:CGRectMake(75,10,250,20)];
[[self detailTextLabel] setFrame:CGRectMake(75,30,250,20)];
}

Related

iOS - UITableView scrollbar goes out of screen

I am new to iOS and i have some serious problem i don't know why this happened, i also tried to find out the reason behind this but i failed.
I am creating a app in iPhone which take tweet of particular user using twitter api, i have no problem in getting the json data, also able to display it in UITableView in iOS 6 using storyboard, i had changed the row height to 200 px, so that i can display user name text tweet and image.
But when I scroll up or down the UITableViewCell the scrollbar goes out of the screen.
What may be the reason?how can I fix it?
ScreenShots
First it shows like this when the app loads the scrollbar takes the full screen
then when i scroll it get out of the screen
at last it completely gets out of screen
UITableView delegate methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *name,*time,*tweet,*image;
name=[[NSMutableArray alloc]init];
time=[[NSMutableArray alloc]init];
tweet=[[NSMutableArray alloc]init];
image=[[NSMutableArray alloc]init];
static NSString *CellIdentifier = #"SimpleTableItem";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
for (User *userModel in self.user) {
[name addObject:userModel.nameStr];
[image addObject:userModel.imageStr];
}
for (Json *jsonModel in self.json) {
[tweet addObject:jsonModel.tweetStr];
[time addObject:jsonModel.timeStr];
}
// Fetch using GCD
dispatch_queue_t downloadThumbnailQueue = dispatch_queue_create("Get Photo Thumbnail", NULL);
dispatch_async(downloadThumbnailQueue, ^{
NSString *imageURL=[image objectAtIndex:indexPath.row];
NSURL *url = [NSURL URLWithString:imageURL];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
UIImageView *image = (UIImageView *)[cell.contentView viewWithTag:5];
image.image=img;
[cell setNeedsLayout];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[spinner stopAnimating];
});
});
self.labelName = (UILabel *)[cell.contentView viewWithTag:10];
[self.labelName setText:[NSString stringWithFormat:#"%#", [name objectAtIndex:indexPath.row]]];
self.labelTime = (UILabel *)[cell.contentView viewWithTag:11];
[self.labelTime setText:[NSString stringWithFormat:#"%#", [time objectAtIndex:indexPath.row]]];
self.labelTweet = (UILabel *)[cell.contentView viewWithTag:12];
[self.labelTweet setText:[NSString stringWithFormat:#"%#", [tweet objectAtIndex:indexPath.row]]];
cell.imageView.frame=CGRectMake(0, 0, 40, 40);
cell.textLabel.lineBreakMode=NSLineBreakByWordWrapping;
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight=self.labelName.frame.size.height+self.labelTime.frame.size.height+self.labelTweet.frame.size.height+50;
return rowHeight;
}
Well scroll goes out of the screen means the tableView frame is larger than the screen size
Set the frame of tableview properly using setFrame: method
I think you have to check the height of the UITableView. Show the screenshot.
Here the ScrollBar goes down as the Height of TableView is larger then the UIView in which you are adding TableView. Adjust the frame according to your view then the ScrollBar will not disappear.

Cell image only appearing after scrolling

I have a UITableView with method cellForRowAtIndexPath shown below, the problem is that cellImage only appears after having scrolled completely up (so no rows are visible) and then releasing. The strange thing is that I have identical code in another class for a separate table view and the image appears fine. Any ideas?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryNone;
}
[cell.textLabel setText:[items objectAtIndex:indexPath.row]];
[cell.textLabel setFont:[UIFont fontWithName:#"Helvetica" size:15.0f]];
[cell.textLabel setTextColor:[UIColor whiteColor]];
[cell setBackgroundColor:[[UIColor alloc] initWithRed:117.0/255.0 green:118.0/255.0 blue:121.0/255.0 alpha:1.0]];
[self.tableView setBackgroundView:nil];
[self.tableView setBackgroundView:[[UIView alloc] init]];
[self.view setBackgroundColor:[[UIColor alloc] initWithRed:167.0/255.0 green:169.0/255.0 blue:172.0/255.0 alpha:1.0]];
UIImageView *cellImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"next#2x.png"]];
[cell addSubview:cellImage];
[cellImage setFrame:CGRectMake(0, 0, 26, 24)];
[cellImage setCenter:CGPointMake(cell.frame.size.width - 30, cell.frame.size.height/2)];
return cell;
}
[self.tableView setBackgroundView:nil];
[self.tableView setBackgroundView:[[UIView alloc] init]];
The lines dont belong to the method. You call the methods every time you scroll for every cell. Put them in your viewDidLoad method, after you have created your table view.
UIImageView *cellImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"next#2x.png"]];
[cell addSubview:cellImage];
These lines are really very BAD and may cause a memory leak.
Everytime you scroll the table view you add a imageview to the cell. Table view reuses the cells. It means when cell is reused, you add a new imageview to the cell. After you scroll more times you have x times imageview on every cell, unless you remove them somewhere in you code.
Other point is, if you want to add some subview to a cell (eg. in init method of the cell) then add it to contenview of the cell like this
[cell.contentView addSubview:someView];
Otherwise your subview may overlap accessory views. And you can have problems when your cell is resized.
I advise you read the guide from the following link:
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/tableview_iphone/TableViewCells/TableViewCells.html#//apple_ref/doc/uid/TP40007451-CH7-SW1
As captured in many of the comments, there are a number of issues:
Set your view and tableView background in your viewDidLoad method (or via your XIB), not in cellForRowAtIndexPath
Use the cell.imageView property to set a left icon, OR, alternatively, to build a custom cell you would use [cell.contentView addSubview:cellImage]. If you do the latter, you should also add your textLabel in the same manner as a UILabel.
To set the background of a tableview cell, use this delegate method:
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
[cell setBackgroundColor:[[UIColor alloc] initWithRed:117.0/255.0 green:118.0/255.0 blue:121.0/255.0 alpha:1.0]];
}
though for efficiency you should instantiate this UIColor once in your viewcontroller and set it as [cell setBackgroundColor:self.cellBackground];
The problem you are facing is due to reuseIdentifier for cell.
Also you are creating Imageview everytime cellForRowAtIndexPath is executed.
i will suggest two solution here for you.
1st Option :- just replace this code :
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.accessoryType = UITableViewCellAccessoryNone;
}
this is not proper way when you are dealing with dynamic images, means you are downloading thumbnail from server and data content is more, if it's small and static data then it's fine for you.
2nd Option :- just use this formatted code this will not create imageview everytime just use object from current cell with tag.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryNone;
UIImageView *cellImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 26, 24)];
cellImage.tag = 88;
[cell addSubview:cellImage];
[cellImage setCenter:CGPointMake(cell.frame.size.width - 30, cell.frame.size.height/2)];
}
[cell.textLabel setText:[items objectAtIndex:indexPath.row]];
[cell.textLabel setFont:[UIFont fontWithName:#"Helvetica" size:15.0f]];
[cell.textLabel setTextColor:[UIColor whiteColor]];
[cell setBackgroundColor:[[UIColor alloc] initWithRed:117.0/255.0 green:118.0/255.0 blue:121.0/255.0 alpha:1.0]];
[self.tableView setBackgroundView:nil];
[self.tableView setBackgroundView:[[UIView alloc] init]];
[self.view setBackgroundColor:[[UIColor alloc] initWithRed:167.0/255.0 green:169.0/255.0 blue:172.0/255.0 alpha:1.0]];
UIImageView *cellImage = (UIImageView *)[cell viewWithtag:88];
cellImage.image = [UIImage imageNamed:#"next#2x.png"];
}
Fixed using the following code:
UIImageView *cellImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"next#2x.png"]];
[cell setAccessoryView:cellImage];

Problem in customize cell selection Style in UITableView in iPhone

In my application ,I am using Grouped style for TableView. In that I want to customize the cell selection Style.I want that selection Style to be red.
I am using the below code for that:
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor redColor];
[cell setSelectedBackgroundView:bgColorView];
[bgColorView release];
By using the above code. I have a problem.Since I have taken grouped Style table , in the
selection of first and last rows, the selection is appear with sharp edged rectangle instead of
appeaing round Corners.
Can Anyone Help me in this.
Thanks in Advance.
Try this ,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.selectedBackgroundView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"SelectedCellBackground.png"]] autorelease];
}
// Cell configuration takes place here
}
add QuartzCore framework. and import QuartzCore/QuartzCore.h framework in .m file. and after that add following code in cellForRowAtIndexPath Method.
UIImageView *imv = [[UIImageView alloc]init];
imv.backgroundColor=[UIColor redColor];
[cell setSelectedBackgroundView:imv];
CALayer *layer = imv.layer;
[layer setMasksToBounds:YES];
[layer setCornerRadius:10.0];
[imv release];
Override -(void)setSelected:animated: in your subclass.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
if (selected)
[self setBackgroundColor:[UIColor redColor]];
else
[self setBackgroundColor:[UIColor whiteColor]];
}
You can add fancy animation here to blend in and fade out the background upon selection and deselection if animated is YES.
In general UITableViewCell can be a bit awkward to subclass, be patient here.
UIImageView *imageVieww=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, cell2.bounds.size.width, cell2.bounds.size.height)];
imageVieww.image=[UIImage imageNamed:#"mavilik.png"];
[cell2 setSelectedBackgroundView:imageVieww];
[imageVieww release];

Images change while scrolling the table in iphone?

I'm using the xml for fetching the data and display it in the uitable. In the XML i have a separate tag for the image as "link". I'm displaying this image as the cell image. Everything workings fine when the applications loads, but when i scroll the table the images in the cell are getting changed.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType=UITableViewCellAccessoryNone;
cell.selectionStyle=UITableViewCellSelectionStyleNone;
//cell. separatorStyle=UITableViewCellSeparatorStyleNone;
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(110, 10, 190, 130)];
[titleLabel setTag:2];
titleLabel.numberOfLines=7;
[titleLabel setFont:[UIFont systemFontOfSize:14]];
[titleLabel setTextColor:[UIColor blackColor]];
[titleLabel setBackgroundColor:[UIColor clearColor]];
[cell.contentView addSubview:titleLabel];
[titleLabel release];
imageView= [[UIImageView alloc] initWithFrame:CGRectMake(5, 20, 90, 110)];
[cell.contentView addSubview:imageView];
}
NSDictionary *appRecord = [responseArr objectAtIndex:indexPath.row];
NSString *urlLink;
urlLink=[NSString stringWithFormat:#"%#",[appRecord objectForKey:#"link"]];
NSLog(#"LINK : %#",urlLink);
if([urlLink length] ==0)
{
imageView.image=[UIImage imageNamed:#"ioffer.png"];
}
else {
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlLink]];
UIImage *image = [[UIImage alloc] initWithData:imageData];
imageView.image = image;
}
UILabel *desclbl = (UILabel*)[cell.contentView viewWithTag:2];
desclbl.text = [NSString stringWithFormat:#"%#",[appRecord objectForKey:#"description"]];
return cell;
}
I have used these code in the table's cellForRowAtIndexPath. responseArr is the array where i stored the links.
Can any one help me in this issue.
Thanks in advance
Malathi
If you reuse an existing table view cell, i.e. the code skips the first if-block, then imageView isn't initialized (where is it declared anyway?). That means even though you set a new text, some random image is reused.
The fix is to make sure that imageView is intialized in all cases.
And please do declare it locally in this method. Everything else seems very dangerous to me.
The "implied else" of the if (cell == nil) is that it's reusing a cell from the table's cache. It doesn't reset anything about those, it just picks them up and uses them. Which means that any element you've got on there needs to be cleared manually, especially if it's going to be some time before they're filled in.
You're already doing some defaulting, here:
if([urlLink length] ==0)
{
imageView.image=[UIImage imageNamed:#"ioffer.png"];
}
If you just make that NOT conditional -- ie just say
imageView.image=[UIImage imageNamed:#"ioffer.png"];
what you'll get is, your cell will load with its default image, then when the image loads remotely it'll replace it.
NOW: You're doing that image load synchronously. Which means your whole UI is going to freeze while the web request is being made. Not great.
I had the same issue. The cells are reused at an other index, when scrolling.
Try putting the code, that fills the cells with data, outside the "if (cell == nil)". Worked for me.
Best regards,
Alexander
You also use the custom cell instead of this and check each time
as like given below example-
Condition-
if(shout.creator.avatarImage){
avatarView.image = shout.creator.avatarImage;
}
else{
FetchImageOperation *operation = [[FetchImageOperation alloc] init];
operation.delegate = self;
operation.urlString = shout.creator.avatarURL;
[operationQueue addOperation:operation];
[operation release];
}
-(void)fetchthumbImageOperation:(FetchThumbImageOperation *)operation didFetchImage:(UIImage *)image
{
avatarView.image= image;
}
Here, i check the condition for image in tableview data source.
-(UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
}

Buggish behavior of a UILabel Text when selecting a Custom built UITableViewCell: the text get mixup or overlaid with a previously loaded label

I have been looking for a solution to this issue for a few days now... and cannot find someone with a similar problem or a solution that would work for me. At this point I am not even sure that I am doing something wrong, as I have read and analyzed many sample code and I am almost 100% sure that I am doing this the way it should...
Anyway here it comes:
I have a UITableView to which I display custom built UITableViewCell, here is where I create them:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
NSDictionary *myDictionary = [myArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier: CellIdentifier] autorelease];
CGRect textViewRect = CGRectMake(10.0, 0.0, 250, 25);
UILabel *textView = [[UILabel alloc] initWithFrame:textViewRect];
textView.text = [myDictionary objectForKey:#"name"];
textView.font = [UIFont systemFontOfSize:12.0];
textView.textColor = [UIColor blackColor];
textView.highlightedTextColor = [UIColor whiteColor];
textView.textAlignment = UITextAlignmentRight;
[cell.contentView addSubview:textView];
[textView release];
CGRect imageRect = CGRectMake(270.0, 15, 16, 16);
UIImageView *icon = [[UIImageView alloc] initWithFrame:imageRect];
icon.image = [myDictionary objectForKey:#"color-icon"];
icon.highlightedImage = [myDictionary objectForKey:#"gray-icon"];
[cell.contentView addSubview:icon];
[icon release];
}
So as you can see, pretty standard stuff... Then when I click on one of the cell, another view gets loaded instead of the table.
Until now, everything is fine, but then when I come back to that table view and that it has to reload the problem starts...
By the way I have added this to the delegate methods so the cells never stay selected:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// [...] a lot more code here
}
When I clicked on my cell in the simulator with the mouse and keep it down the cell stays selected as expected (same way on the device itself) and this is why I get:
[Image 1]
The UILabel Text is totally mixed up ! The screenshot is actually of the last cell of the table and the overlapping text is the one of the first cell. And the behavior on the first is similar, if I maintain the click on it, it will show the same behavior mixing up with the UILabel text of the last cell. I am guessing that is is due to the way the dequeueReusableCellWithIdentifier works (probably a FILA queue).
Of course I tried to work around that and found some really weird stuff.
If I don't click the cells are perfect, no bugs, the correct text is displayed etc:
[Image 2]
Then I tried to mess up a little bit with the parameters of my UILabel. I added this:
textView.backgroundColor = [UIColor clearColor];
And when I do this, as soon as the table reload, then I don't even need to highlight the cell to see the screw up behavior:
[Image 3]
The only way I was about to get rid of the problem to always instantiate a new cell rather than dequeueing one...
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier: CellIdentifier] autorelease];
was replaced by:
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier: CellIdentifier] autorelease];
But of course this won't work on the long term because of the memory leak...
Also, it is to be noted that I have the exact same behavior for another UITableView in another view somewhere in this App... The other custom cell is more complex, more labels, more images, etc, but all the label exhibit the same behavior. And this more complex Table View is managed by a Navigation Controller, so no custom loading / unloading like the first one...
That's all I have, and I can't find a solution... please help !
Arghh this is really annoying... I am new so I cannot post images... :(
Here is a link where you can see the referenced images: https://skitch.com/aponsin/rne9k/fullscreen.png-100-layer-3-rgb-8
Alex
The problem is that you create new label and add it to cell each time cell is being reused. To fix that you must create your label only when your cell is created:
if (cell == nil){
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier: CellIdentifier] autorelease];
CGRect textViewRect = CGRectMake(10.0, 0.0, 250, 25);
UILabel *textView = [[UILabel alloc] initWithFrame:textViewRect];
textView.tag = kLabelTag;
textView.font = [UIFont systemFontOfSize:12.0];
textView.textColor = [UIColor blackColor];
textView.highlightedTextColor = [UIColor whiteColor];
textView.textAlignment = UITextAlignmentRight;
[cell.contentView addSubview:textView];
[textView release];
CGRect imageRect = CGRectMake(270.0, 15, 16, 16);
UIImageView *icon = [[UIImageView alloc] initWithFrame:imageRect];
icon.image = [myDictionary objectForKey:#"color-icon"];
icon.highlightedImage = [myDictionary objectForKey:#"gray-icon"];
[cell.contentView addSubview:icon];
[icon release];
}
And after that you can get your label from cell using tag property you've assigned:
UILabel *textView = (UILabel*)[cell.contentView viewWithTag:kLabelTag];
textView.text = [myDictionary objectForKey:#"name"];
same logic also applies to setting up your icon imageview if it varies in different cells
Also have a look at components standard UITableViewCell already provides (depending on its cell style) - there's already UIImageView and UILabels there and you can set your custom properties to them and use them without creating extra components