How to place "x" number of objects on the view - objective-c

If the user provides a number, such as 8, how exactly would I place eight labels onto the view?
For example:
int userGivenNumber = textfield.text;
for (int labelNumber=1; i<=userGivenNumber; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, *previousLabel*.frame.origin.y + 20)];
}
How would you get the location of previousLabel? Additionally, if the user wanted to edit a label, such as label 3, how would I edit this label?
The problem is that I don't know how many labels they want to place while coding, and I have no way of keeping track of the labels, since they are called label. Do you have any ideas? Do you understand what I am asking? Thanks for your help.

- (void)addLabels {
CGFloat offset = 0;
// labels is NSMutableArray property
labels = [[NSMutableArray alloc] initWithCapacity:8];
for (int i = 0; i < 8; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, offset, 320, 20)];
[self.view addSubview:label];
[labels addObject:label];
offset += label.frame.size.height;
}
}
Edit: Like jerrylroberts said, to access the label array from elsewhere in your code, you should declare it as a property.

So you could add the views like so:
int userGivenNumber = [textfield.text intValue];
for (int labelNumber=1; i<=userGivenNumber; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, *previousLabel*.frame.origin.y + 20)];
[self.view addSubview:label];
[label release];
}
If you wanted to keep track of them you could just create a mutable array as a property and then add each label to the array before you add to the subview;
Interface
#property (nonatomic, retain) NSMutableArray *addedLabels;
Implementation
#synthesize addedLabels=_addedLabels;
- (void)viewDidLoad
[super viewDidLoad];
// Create your array to hold labels
NSMutableArray *addedLabels = [[NSMutableArray alloc] initWithCapacity:0];
self.addedLabels = addedLabels;
[addedLabels release];
// NOW put your code
int userGivenNumber = [textfield.text intValue];
for (int labelNumber=1; i<=userGivenNumber; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, *previousLabel*.frame.origin.y + 20)];
[self.view addSubview:label];
[addedLabels addObject:label];
[label release];
}
}
Now you can easily access any label you have added if you have the index. Hope this helps

Just keep a reference to the location (CGPoint) outside the loop, but update it inside the loop to the current label's location. When you assign the next frame do your operation depending on width and size of the label, and don't forget to update the reference of CGPoint.

Related

Constraint spacing UILabel in For Loop

I have a small problem and hope someone can help me solve it ... I searched the net and made some attempts, but I could not solve my problem.
I created a FOR loop that plays a specified number of labels obtained through an array, as you can see from the code that I posted below ...
Now my problem is how to insert constraint programmatically. I need that between a label and the other (horizontal) there is a specific space.
Example:
if I label 4 I would like these would take around the horizontal space is in the iPhone display SE both iPhone 7 Plus ..
So my question is how do I set a specific space between each label and pass in the FOR loop?
CGFloat padding = 0;
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"INFO UNIVERSITARIE",#"INFO GENERALI", #"TROVA SEDI", nil];
for (NSInteger i = 0; i < array.count; i ++) {
NSString *valueText = [array objectAtIndex:i];
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(padding *i, 0, 50, 30);
label.text = [NSString stringWithFormat:#"%#", valueText];
label.textColor = [UIColor whiteColor];
label.font = [UIFont fontWithName:#"HelveticaNeue" size:12];
[label sizeToFit];
[_baseView addSubview:label];
padding = label.frame.size.width;
label.translatesAutoresizingMaskIntoConstraints = NO;
}
Researching this, I remembered that the UIStackView is our new friend, designed specifically for this problem.
NSArray *array = #[ #"INFO UNIVERSITARIE",#"INFO GENERALI", #"TROVA SEDI" ];
NSMutableArray *labels = [NSMutableArray array];
for (NSString *string in array) {
UILabel *label = [[UILabel alloc] init];
label.text = string;
[labels addObject:label];
}
UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:labels];
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.spacing = 12.0;
stackView.frame = self.view.bounds;
[self.view addSubview:stackView];
Just learned about this myself, but I tried this code and it works nicely.

Objective C - How to create a set of sub views to update

Perhaps I am thinking about this incorrectly, so please point me in the right direction..
I want to make many UIViews as a property so I can update them with different methods. Something like this:
#property UIView *view1
#property UIView *view2
...
#property UIView *view200
-(void)updateViews{
for (i=0; i <200; i++){
//Update view here
}
So my questions are:
How can I easily make multiple views?
How can I easily pass a message to each individual view?
So many great responses, I think I need to add a little more info.
Have tried putting my UIViews into an array to index them but I struggle to access them to update their positions within the UIViewController. I thought making them a property is the correct way to since I need to update them with the device heading. Looks like using a tag might be best. Can someone further comment on this approach:
for (i = 0 ; i < 144; i++) {
UIView *sunView =[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"sun.png"]];
sunView.tag = i;
}
//then later, in a separate method do the following:
for (i = 0 ; i < 144; i++) {
CGFloat CGx = self.acceleration.X;
CGFloat CGy = self.acceleration.Y
[sunView.tag.i setFrame:CGRectMake(CGx, CGy, 20, 20)]
}
Im not sure how to access the UView with the corresponding indexed tag. Can someone help me there too?
When they are really subviews then you could iterate through the superview's subviews array.
You could do that recursievely in order to apply it on all subivews of your subviews, if you have multiple hierarchy levels.
If you don't want to apply this to each of your superview's subviews, then tag your subviews with something like view.tag = 6502 and use that to identify those views to which you want to apply it.
Or maintain your own array or set (iterable collection) of views and iterate through them.
Create your views in a loop and store them in an NSMutableArray. That way you will have access to all of them in your view controller.
Create a property.
#property (monatomic) NSMutableArray *arrayOfViews;
self.arrayOfViews = [[NSMutableArray alloc] init];
UIView *view;
for (int i = 0; i < 10; i++)
{
view = [[UIView alloc] init];
[self.arrayOfViews addObject:view];
}
Run a loop over this array and access the views one by one and call the method you need to call.
On a side note: Why are you creating 200 UIViews? That's a lot :)
I think you need something like that:
-(void)updateViews
{
UIView *views;
UILabel *label;
for(int i = 0 ; i < numberOfViews ; i++)
{
views = [[UIView alloc] initWithFrame:CGRectMake(...)];
label = [[UILabel alloc] initWithFrame:CGRectMake(0,0,views.frame.size.width,views.frame.size.height)];
[label setText:[NSString stringWithFormat:#"%d",i]];
[views addSubview:label];
[self.view addSubview:views];
}
}
How can I easily make multiple views?
Do you want to create it in IB?
1) You can use tags in Xcode
UILabel * label = (UILabel*)[self.view viewWithTag:19];
UIView * view = (UIView*)[self.view viewWithTag:20];
2) You can use property that you also do
How can I easily pass a message to each individual view?
if your views inside another view(currentView) you can use that
for (UIView *yourView in self.currentView.subviews) {
//Update view here
}
Or if you want to create it in the code
for (int i = 0; i < 10; i++)
{
UIView * myView = [[UIView alloc]initWithFrame:CGRectMake(10*i, 10*i, 25, 25)];
int r = arc4random() % 255;
int g = arc4random() % 255;
int b = arc4random() % 255;
myView.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1];
[self.view addSubview: myView];
}
That's what you can see
And to call all these views you can use
for (UIView *yourView in self.view.subviews) {
[yourView removeFromSuperview];
}
And that's what you'll see
If you want to call own view you can use tags like this
for (int i = 0; i < 10; i++)
{
UIView * myView = [[UIView alloc]initWithFrame:CGRectMake(10*i, 10*i, 25, 25)];
myView.tag = i + 21;
int r = arc4random() % 255;
int g = arc4random() % 255;
int b = arc4random() % 255;
myView.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1];
[self.view addSubview: myView];
}
for (UIView *yourView in self.view.subviews) {
if (yourView.tag == 21) {
[yourView removeFromSuperview];
}
}

How do I save a UILabel's properties in a NSMutableArray?

For example,
-(void)drawHypnoticMessage:(NSString *)message{
....
UILabel messageLabel = [[UILabel alloc]init];
messageLabel.backgroundColor = [UIColor clearColor];
messageLabel.textColor = [UIColor whiteColor];
messageLabel.text = message;
[messageLabel sizeToFit];
int width = (int)(self.view.bounds.size.width - messageLabel.bounds.size.width);
int x = arc4random() % width;
int height = (int)(self.view.bounds.size.height - messageLabel.bounds.size.height);
int y = arc4random() % height;
CGRect frame = messageLabel.frame;
frame.origin = CGPointMake(x,y);
messageLabel.frame = frame;
[self.view addSubview:messageLabel];
...}
I want to be able to add this label "messageLabel" to a NSMutable array like this:
NSMutableArray *thisArray;
[thisArray addObject:messageLabel];
and then access it later after STATE RESTORATION like this:
UILabel *thisLabel = [thisArray objectAtIndex:0];
[self.view addSubview: thisLabel];
For some reason, when I try to access the UILabel stored inside the NSMutableArray, the text in ---> thisLabel.text <--- shows up empty. In Addition, all the properties in the --->thisLabel<--- also shows up empty when I try to access it again after STATE RESTORATION.
such as:
--->thisLabel.textColor<---- shows up empty.
--->thisLabel.frame <---- shows up empty.
Can anybody help me solve this quirk? It's really frustrating.
I want to be able to add this label "messageLabel" to a NSMutable
array like this:
NSMutableArray *thisArray;
[thisArray addObject:messageLabel];
Did you remember to first say
thisArray = [[NSMutableArray alloc]init];

adding buttons below the other

I want to add buttons one below the other. I have this simple code:
- (void)viewDidLoad
{
[super viewDidLoad];
for(int i=0 ; i<9 ; i++)
{
UIButton *myButton = [[UIButton alloc] init];
myButton.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height/10); //this "10" i want also dynamically
myButton.backgroundColor = [UIColor blackColor];
[self.view addSubview:myButton];
}
}
Of course i know that it will be draw one on another. But can i do it in the loop without knowing the height (becouse high will depends on how many buttons will be in the loop).
What i want to achieve:
Try This:
- (void)viewDidLoad
{
[super viewDidLoad];
int number = 10;
for(int i=0 ; i<9 ; i++)
{
UIButton *myButton = [[UIButton alloc] init];
myButton.frame = CGRectMake(self.view.frame.origin.x, (self.view.frame.size.height/number)*i + number, self.view.frame.size.width, self.view.frame.size.height/number);
myButton.backgroundColor = [UIColor blackColor];
[self.view addSubview:myButton];
}
}
you need to define the size of the buttons for the correct show, unfortunately without the size of the buttons you cannot achieve you wished because how else does the system know what sized button you'd like to show...?
- (void)viewDidLoad
{
[super viewDidLoad];
Float32 _spaceBetweenButtons = 8.f;
Float32 _offsetY = 32.f;
Float32 _buttonWidth = 300.f; // width fo button
Float32 _buttonHeight = 32.f; // height of the button
for (int i = 0 ; i < 9 ; i++) {
UIButton *_myButton = [[UIButton alloc] initWithFrame:CGRectMake(0.f, 0.f, _buttonWidth, _buttonHeight)];
[_myButton setBackgroundColor:[UIColor blackColor]];
[_myButton setTitle:[NSString stringWithFormat:#"button #%d", i] forState:UIControlStateNormal]; // just add some text as title
[self.view addSubview:_myButton];
[_mybutton setCenter:CGPointMake(self.view.frame.size.width / 2.f, _offsetY + i * (myButton.frame.size.height + _spaceBetweenButtons))];
}
}
if you want to calculate the size of the buttons dynamically and you want to align the button's height to the view's height, here would be one way:
NSInteger _numberOfButtons = 20;
Float32 _spaceBetweenButtons = 8.f;
Float32 _calculatedHeight = (self.view.frame.size.height - (_numberOfButtons + 1 * _spaceBetweenButtons)) / _numberOfButtons;
and the method is same as above, but I'm not sure you will get good UI in case of hundreds buttons. :)
Perhaps this might work? Sorry I haven't used self.view.frame in ages, but you get the general idea.
- (void)viewDidLoad
{
[super viewDidLoad];
int number;
for(int i=0 ; i<9 ; i++)
{
UIButton *myButton = [[UIButton alloc] init];
myButton.frame = CGRectMake(i * self.view.frame.origin.x / number,
self.view.frame.origin.y,
self.view.frame.size.width,
self.view.frame.size.height / number); //this "10" i want also dynamically
myButton.backgroundColor = [UIColor blackColor];
[self.view addSubview:myButton];
}
}

UIScrollView only works if the child views aren't hit

I have a scroll view that doesn't scroll right, I've simplified the code for below.
It draws the view and some horizontal buttons that i add more stuff to in the real code.
If you drag the whitespace between the buttons the view scrolls. If you happen to put your finger on a button, it won't scroll.
After a related suggestion, I tried to add the delaysContentTouches = YES line, but it doesn't seem to make a difference.
UIScrollview with UIButtons - how to recreate springboard?
What am I doing wrong?
TIA,
Rob
Updated the code
- (void)viewDidLoad {
l = [self landscapeView];
[self.view addSubview:l];
[l release];
}
- (UIScrollView *) landscapeView {
// LANDSCAPE VIEW
UIScrollView *landscapeView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 325)];
landscapeView.backgroundColor = [UIColor whiteColor];
landscapeView.delaysContentTouches = YES;
NSInteger iMargin, runningY, n;
iMargin = 3;
runningY = iMargin;
for (n = 1; n <= 38; n++) {
//add day labels
UIButton *templabel = [[UIButton alloc] initWithFrame:CGRectMake(iMargin,runningY,320 - ( 2 * iMargin),20)];
templabel.backgroundColor = [UIColor grayColor];
[landscapeView addSubview:templabel];
[templabel release];
runningY = runningY + 30;
}
landscapeView.contentSize = CGSizeMake( 320, runningY);
return landscapeView;
}
I can't duplicate your results; when I create a scrollView and add buttons, scrolling is still active even when doing a touch-down on the button. Are you setting any other UIScrollView properties, or subclassing any methods, that aren't showing up in your simplified code?
It looks like one thing that's going on is that the getter for landScapeView is a complicated constructor...so every time you do [self landscapeView] or self.landscapeView, you're creating a whole new UIScrollView and operating on that.
I'd try something like this in your .h file:
#interface MyClass: MyParent {
UIScrollView *landscapeView;
}
#property (retain) UIScrollView *landscapeView;
...and this in your .m file:
#implementation MyClass
#synthesize landscapeView;
(void)viewDidLoad
{ l = [[[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 325)] autorelease];
[self.view addSubview:self.landscapeView]; [l release];
landscapeView.backgroundColor = [UIColor whiteColor];
landscapeView.delaysContentTouches = YES;
NSInteger iMargin, runningY, n;
iMargin = 3;
runningY = iMargin;
for (n = 1; n <= 38; n++) { //add day labels
UIButton *templabel = [[UIButton alloc] initWithFrame:CGRectMake(iMargin,runningY,320 - ( 2 * iMargin),20)];
templabel.backgroundColor = [UIColor grayColor];
[landscapeView addSubview:templabel];
[templabel release]; runningY = runningY + 30;
}
landscapeView.contentSize = CGSizeMake( 320, runningY);
}