Adding UILabels Dynamically in a Loop - iphone

I am looking for a function or a loop prototype to add UILabels to a view on iPhone. The reason for this is I won't know in advance how many labels I need to add, so they will need to be added dynamically.
My pseudo code is as follows. The idea is that each label is given a string and then placed in the next screen, hence the +self.view.frame.size.width statement. Paging etc work perfectly, the problem is all the labels appear to be ending up on the second screen i.e. Label 3 appears on top of label 2. The issue would appear to be I am always referencing altLabel, and as such once I move to the second position, I am constantly referencing that position and never moving once there.
I can use the 'count' variable to multiple the screen width, but if I do that, every time I update the label text, it will overwrite the previous.
int count = 0;
int maxNumber = 10;
while(count < maxNumber) {
//Add a label
UILabel *altlabel; //Declare the label
if (count > 0) {
//Move the label
altlabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(altlabel.frame)+self.view.frame.size.width,10,300,25)];
altlabel.text = [NSString stringWithFormat:#"%# %# (%d)", _name,_age, class+count];
}
else {
altlabel = [[UILabel alloc] initWithFrame:CGRectMake(10,10,300,25)];
altlabel.text = [NSString stringWithFormat:#"%# %# (%d)", _name,_age, class];
}
altlabel.textColor = [UIColor greenColor];
[altlabel sizeToFit];
[_scrollView addSubview:altlabel];
count++;
}

The problem is this line:
UILabel *altlabel; // Declare the label
if (count > 0) {
//Move the label
altlabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(altlabel.frame)+self.view.frame.size.width,10,300,25)];
altlabel.text = [NSString stringWithFormat:#"%# %# (%d)", _name,_age, class+count];
}
You are setting up the frame using altlabel.frame, but there altlabel is not setted up: you redeclared it on the first line with UILabel *altlabel.
With this code every label but the first will have the same frame. Try with this:
int count = 0;
int maxNumber = 10;
CGRect rect;
while(count < maxNumber) {
// Add a label
UILabel *altlabel; // Declare the label
if (count > 0) {
//Move the label
altlabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(rect.frame)+self.view.frame.size.width*count, 10, 300, 25)];
altlabel.text = [NSString stringWithFormat:#"%# %# (%d)", _name,_age, class+count];
} else {
altlabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 300, 25)];
altlabel.text = [NSString stringWithFormat:#"%# %# (%d)", _name,_age, class];
}
rect = altlabel.frame;
altlabel.textColor = [UIColor greenColor];
[altlabel sizeToFit];
[_scrollView addSubview:altlabel];
count++;
}
Now the frame of new label is saved in a temporary var (CGRect frame) and you can use it.

This code should work:
int count = 0;
int maxNumber = 10;
while(count < maxNumber) {
//Add a label
UILabel *altlabel; //Declare the label
if (count > 0) {
//Move the label
altlabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(altlabel.frame)+(self.view.frame.size.width*count),10,300,25)];
altlabel.text = [NSString stringWithFormat:#"%# %# (%d)", _name,_age, class+count];
}
else {
altlabel = [[UILabel alloc] initWithFrame:CGRectMake(10,10,300,25)];
altlabel.text = [NSString stringWithFormat:#"%# %# (%d)", _name,_age, class];
}
altlabel.textColor = [UIColor greenColor];
[altlabel sizeToFit];
[_scrollView addSubview:altlabel];
count++;
}

A much cleaner approach would be to predetermine the frame of your label before creation and then add it as a subview (or perhaps save each label to an array for reference later on).
NSInteger numberOfLabels = 10;
CGFloat labelHeight = 25.0;
CGFloat padding = 10.0;
for(NSInteger index = 0; index < numberOfLabels; ++index)
{
CGRect frame = CGRectMake(10.0, (index * (labelHeight + padding)), 300.0, labelHeight);
UILabel *label = [[UILabel alloc] initWithFrame:frame];
[[self view] addSubview:label];
}
You may want to assign the label a tag with setTag: to reference each label, or gather then from an array rather than looping through subviews to gather or append text after they have been created.

I think the problem will be that your label 'altLabel' is being reinitialised each time the loop runs through and therefore the frame of the label is also being reset.
This means that every time a new label is created, the frame will be in exactly the same place.
A simple way to fix this would simply be to move the initial declaration of the label to outside the while loop.
A potentially better and more efficient fix would require a rework of the loop used. When I do things like this, I tend to use a for loop as you have use of an index to help position things:
for(int i = 0; i < 10; i++)
{
//Getting the x-position correct here may take a little trial and error
UILabel *altLabel = [[UILabel alloc] initWithFrame:CGRectMake(INSET + i*LABEL_WIDTH, 10, 300, 25)];
[altLabel setText:[NSString stringWithFormat:#"%# %# (%d)", _name,_age, class+count]];
[altLabel setTextColor:[UIColor greenColor]];
[altLabel sizeToFit];
[_scrollView addSubview:altLabel];
}
This should then mean you don't need a counter.
Hopefully this helps!
Matt

Related

How to get UILabel Tags in iPhone

I am creating labels dynamically from NSMutableArray.While creating labels I have set tags for each label. I have one NSMutableArray named wordArray. Now, I want to check my string is available in wordArray or not,
I can check this using :
[wordArray containsObject:wordStr];
For creating labels dynamically :
UILabel *wordLabl;
int tagValue3 = 1;
for (int iloop = 0; iloop < [wordArray count]; iloop++)
{
wordLabl = [self addwordLabelRect:CGRectMake(80 * iloop + 20, 420 , 100, 20)andTag:tagValue3];//30 + 35 30 * iloop+
[self.view addSubview:wordLabl];
tagValue3 += 1;
}
-(UILabel *)addwordLabelRect:(CGRect)rect andTag:(int)integerValue
{
wordLabel = [[UILabel alloc] init];
wordLabel.frame = rect;
wordLabel.userInteractionEnabled = YES;
wordLabel.tag = integerValue;
wordLabel.backgroundColor = [UIColor clearColor];
wordLabel.font = [UIFont systemFontOfSize:15];
wordLabel.text = [NSString stringWithFormat:#"%#",[wordArray objectAtIndex:integerValue - 1]];
wordLabel.textAlignment = NSTextAlignmentCenter;
wordLabel.textColor = [UIColor whiteColor];
return wordLabel;
}
Using above code I am creating labels and Tags.
But,If wordArray contains the string I want to change the textColor of that label.I think this can be done using Tag , but how can I get the tag value of the label.
Sorry, I overlooked you code... You just need to add following lines where you want to access your appropriate label:
if([wordArray containsObject:wordStr])
{
UILabel *label = (UILabel *) [self.view viewWithTag:([wordArray indexOfObject:wordStr] - 1)];//since u started tag assignment from 1
label.textcolor = [UIColor yellowColor];
}
I guess you're doing something like that to set the tags ?
for (NSUInteger i = 0; i < [wordArray count]; ++i) {
UILabel * label;
// setup your label...
[label setTag:i];
[yourView addSubview:label];
}
If so, just do :
NSUInteger index = [wordArray indexOfObject:wordStr];
if (index != NSNotFound) {
UILabel * label = [yourView viewWithTag:index];
// do whatever you want with your label
}
Good luck.
if you want to get UILabel from its Tag.
you can use following loop
int i=0;
for (NSObject *view in self.View.subviews)
{
if ([view isKindOfClass:[UILabel class]])
{
label = (UILabel *)[[self view] viewWithTag:wordArray[i]];
NSLog(#"%#",label.text);
//here you get your label
}
i++;
}

UILabel multi-set values

I know this is going to sound like a trivial question but I have defined 50 labels in my *.h file
UILabel *tempLabel1;
UILabel *tempLabel2;
UILabel *tempLabel3;
...
UILabel *tempLabel50;
In my *.c file I want to set the value for each of those labels but I don't want to do it manually or write them out over and over again.
//Instead of doing this
tempLabel1.text = #"1";
tempLabel2.text = #"2";
...
tempLabel50.text = #"50";
//I would like to do something like this
//I know this isn't correct syntax but want to know if something like
//this can be done?
for (int i = 0; i < 50; i++)
{
tempLabel[i].text = #"%d", i+1;
}
Well one way that comes to mind (not the cleanest but A way) is to do the following:
UILabel *tempLabels[50];
The problem you run into then is you can't use IB to connect them. Instead what you do is use the tag property in each of them (this means you need to set the tag for all 50 UILabels). To properly connect them you run this in viewDidLoad:
for (index = 1; index < 50; ++index)
{
tempLabels[index] = (UILabel *) [self.view viewWithTag: index];
}
Bingo! Now anywhere in your code if you need to change the labels you can do the following:
for (index = 1; index < 50; ++index)
{
tempLabels[index].text = [NSString stringWithFormat: #"Number %d", index];
}
It's kind of tedious setting the tags, but once you are done, you are done.
BTW, unlike the other solutions, you can use IB to create your labels.
this would be a good start for you, I guess.
NSMutableArray *_labels = [NSMutableArray array];
for (int i = 1; i < 50; i++) {
UILabel *_newLabel = [[UILabel alloc] init]; // please, make the init method as you wish
// ... any customization of the UILabel
[_newLabel setText:[NSString stringWithFormat:#"%d", i]];
[_newLabel setTag:i];
[_labels addObject:_labels];
[self.view addSubview:_newLabel];
}
// ... and then you can do the following
for (int i = 0; i < _labels.count; i++) {
[((UILabel *)[_labels objectAtIndex:i]) setText:[NSString stringWithFormat:#"%d", i]];
}
You can add the UILabels programmatically and hence have access to them - so you can set their text value as well.
You can add a UILabel like this:
UILabel *theLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 100)]; //need to calculate the x,y coordinates in dependency of i
theLabel.text = [NSString stringWithFormat:#"%i",i];
[self.view addSubview:theLabel]; // add it to your view
myLabel.backgroundColor = [UIColor clearColor]; // change the color
If you need access to the labels later as well, just add them to an NSArray that you keep.

dynamically created labels are overridden

i am working on one application in which i have added 5 labels dynamically in a function.when i recall the same function the labels are overridden on the previously created labels in spite of releasing the labels on each creation.
for(int i = 1; i < [array count]; i++)
{
CGRect lblframe = CGRectMake(count, ycord, width, height);
UILabel *label = [[UILabel alloc] initWithFrame:lblframe];
label.backgroundColor = [UIColor blackColor];
label.font = [UIFont systemFontOfSize:17];
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor colorWithRed:(188/255.f) green:(149/255.f) blue:(88/255.f) alpha:1.0];;
label.text = [arr objectAtIndex:i];
count = count + xcord;
[subcatScroll addSubview:label];
[label release];
}
Write below code before for loop to get your requirement:
for (id object in [subcatScroll subviews]) {
[object removeFromSuperview];
}
I'm not sure I completely follow, so correct me if I'm misunderstanding.
Every time you call this function, you are adding a number of new labels. So if you call this function the second time, assuming 'count', 'ycord', 'width', and 'height' correspond with the values that the first call had, you are obviously adding a second group of labels in the same place as the first ones which are now directly on top of one another. You are not "overriding" the old labels, you are placing a second group directly ontop of the old ones.
Calling "release" on each label, only means you are decreasing the retainCount by 1. This number is used for memory management only. This means if you now remove the labels from the view the memory is released.
CGRect lblframe = CGRectMake(10.0, ycord, 200.0, 20.0);
UILabel *label = [[UILabel alloc] initWithFrame:lblframe];
NSLog(#"retainCount of label: %d", [label reatinCount]); // will print "1" since you called alloc
[self.view addSubview:label];
NSLog(#"retainCount of label: %d", [label reatinCount]); // will print "2" since adding to subview increases retaincount by one
[label release];
NSLog(#"retainCount of label: %d", [label reatinCount]); // will print "1" since you released
[label removeFromSuperview]; // will decrease retainCount of label to "0" and therefore free the memory
so say you wanted to remove the previously created labels from the view, you would have to do so. Either keep a reference to each of them and call "removeFromSuperview" on each of them.
If the only thing in the view where you're adding the labels, you can also just remove every subview that was added to it like so:
// remove old labels
for (UILabel *aLabel in [self.view subviews]) [aLabel removeFromSuperview];
NSArray *myArray = [NSArray arrayWithObjects:#"I", #"II", #"III", #"IV", nil];
for (int i=0; i<[myArray count]; i++) {
float ycord = i*40.0;
CGRect lblframe = CGRectMake(10.0, ycord, 200.0, 20.0);
UILabel *label = [[UILabel alloc] initWithFrame:lblframe];
label.backgroundColor = [UIColor blackColor];
label.font = [UIFont systemFontOfSize:17];
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor colorWithRed:(188/255.f) green:(149/255.f) blue:(88/255.f) alpha:1.0];;
label.text = [myArray objectAtIndex:i];
[self.view addSubview:label];
[label release];
}
I hope this helped, but providing further info on what you're trying to do may make it easier to help you.

uislider adding uitextfield but not updating

So, I have the slider adding UITextFields but it's not updating/subtracting UITextField's when selecting less than the previous Slider Value. Does [self.view addSubview:textField]; need to be outside of the for loop? Thanks in advance.
- (IBAction) sliderValueChanged:(UISlider *)sender {
float senderValue = [sender value];
int roundedValue = senderValue * 1;
ingredientLabel.text = [NSString stringWithFormat:#"%d", roundedValue];
int moveYBy = 35;
int baseY = 140;
for(int y = 0; y < roundedValue; y++){
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(20, baseY, 227, 31)];
textField.text = [NSString stringWithFormat:#"%d", roundedValue];
textField.borderStyle = UITextBorderStyleRoundedRect;
baseY = baseY + moveYBy;
[self.view addSubview:textField];
[textField release];
NSLog(#"Adding %d fields!", roundedValue);
}
NSLog(#"%d", roundedValue);
}
You are creating N text fields everytime the slider value changes (where n is the rounded value).
Instead, you should make an NSMutableArray an iVar and store all the text fields there, when roundedValue is bigger than the number of text fields in that array, we add more. When it's smaller, we remove some.
(I'm using an iVar called textFieldsArray, and I also changed a little the way the y is calculated for the arrays)
- (IBAction) sliderValueChanged:(UISlider *)sender {
float senderValue = [sender value];
int roundedValue = senderValue * 1;
ingredientLabel.text = [NSString stringWithFormat:#"%d", roundedValue];
for(int y = 0; y < roundedValue; y++){
if(y > [textFieldsArray count]){
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(20, 140 + 35 * y, 227, 31)];
textField.text = [NSString stringWithFormat:#"%d", roundedValue];
textField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:textField];
[textFieldsArray addObject:textField];
[textField release];
NSLog(#"Adding %d fields!", roundedValue);
}
}
while([textFieldsArray count] > roundedValue){
UITextField *textField = [textFieldsArray lastObject];
[textField removeFromSuperview];
[textFieldsArray removeLastObject];
}
NSLog(#"%d", roundedValue);
}

How to remove subviews from superviews and redraw on a click a button click?

How to remove subviews from superviews and redraw on a click a button click?
float padding = 5.0;
float view_width = 95.0;
float view_height = 120.0;
int rows = 0.0f;
int columns = 0.0f;
UIView *myAddedView ;
for (int i=0; i<[product.CorrentAnswer intValue]; i++)
{
if(i%3 == 0 && i > 0)
{
columns = 0.0f;
rows += view_height;
}
myAddedView =[[[UIView alloc] initWithFrame:CGRectMake(padding+columns, rows, view_width, view_height)] autorelease];
myAddedView.backgroundColor = [UIColor clearColor];
CGRect myImageRect = CGRectMake( 40, 100.0f, 40.0f, 40.0f);
UIImageView *myImage = [[UIImageView alloc]initWithFrame:myImageRect];
NSString *imageName = [NSString stringWithFormat:#"%#",product.imagename];
[myImage setImage:[UIImage imageNamed:imageName]];
[myAddedView addSubview:myImage];
[viewarray addObject:myAddedView];
[self.view addSubview:myAddedView];
columns+= view_width;
}
i want to remove myAddedView from self.view?
hope to get answer very soon....
you can do this by assigning a tag to myAddedView ....
code change :
myAddedView =[[[UIView alloc] initWithFrame:CGRectMake(padding+columns, rows, view_width, view_height)] autorelease];
myAddedView.backgroundColor = [UIColor clearColor];
//add this line
myAddedView.tag = 10;
and on the button click(when you want to remove the subview) write :
if([self.view viewWithTag:10]!=nil)
{
[[self.view viewWithTag:10] removeFromSuperView];
}
thanks
the answer from user698952 is okay, adding a tag is the way to go.
myAddedView.tag = 10;
If you have more than one view with the same tag you have to change the code for removal a little bit.
UIView *someView = nil;
while (someView = [self.view viewWithTag:10]) {
[someView removeFromSuperview];
}