If I have a large number of buttons set up in Interface Builder, how can I place them into an array via code?
For example, if I have three buttons and in the interface file I define them:
#property (nonatomic, retain) IBOutlet UIButton *button1;
#property (nonatomic, retain) IBOutlet UIButton *button2;
#property (nonatomic, retain) IBOutlet UIButton *button3;
If I want to rename each of these buttons to say "Hello", I want to be able to lump them into an array and then use a function such as:
for (int i = 0; i < someArray.count; i++)
{
someArray[i].text = #"Hello";
}
Could someone please provide information on how this is achieved (if it's possible)?
Thanks
Another approach is to wire the buttons up to an NSArray in Interface Builder.
#property (nonatomic, retain) IBOutletCollection(UIButton) NSArray *buttons;
The following code will add 5 buttons, each with a new tag and also connect it to an event. The buttons will be placed side by side with a 5px padding:
If you plan on accessing the button outside of the for{} scope below, you can define your button in your header, otherwise, you can define it inside the scope. UIButton * settButton;
.m
CGFloat staticX = 5; // Static X for all buttons.
CGFloat staticWidth = 60; // Static Width for all Buttons.
CGFloat staticHeight = 56; // Static Height for all buttons.
CGFloat staticPadding = 5; // Padding to add between each button.
for (int i = 0; i < 5; i++)
{
settButton = [UIButton buttonWithType:UIButtonTypeCustom];
[settButton setTag:i];
[settButton setFrame:CGRectMake((staticX + (i * (staticHeight + staticPadding))),5,staticWidth,staticHeight)];
[settButton setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%i.png",i]] forState:UIControlStateNormal];
[settButton addTarget:self action:#selector(buttonEvent:) forControlEvents:UIControlEventTouchDown];
[settButtonView addSubview: settButton];
}
[self.view addSubview: settButtonView];
Assuming the buttons in IB are correctly wired to the IBOutlet properties then its as straightforward as:
NSArray *buttonArray = [[NSArray alloc] initWithObjects:button1,button2,button3,nil];
Since you created the buttons directly in Interface Builder, can't you just set them directly in code?
A more general solution would be something like this...if I assume two things: that they are all subviews of the UIViewController's view and that these UIButtons are the only UIButtons in that view, you can do something like this:
for (UIView *aView in [self.view subviews]) {
if ([aView isKindOfClass:[UIButton class]) {
UIButton *aButton = (UIButton *) aButton;
[aButton setTitle:#"Hello" forState:UIControlStateNormal];
}
}
I think that the easiest is to create a single button that you will init and add to a mutable array:
in *.m:
UIButton *buttonChar;
in your function:
buttonArray = [[NSMutableArray alloc] init];
for (int i=0; i<lenghtWord; i++) {
buttonChar = [[UIButton alloc] initWithFrame:CGRectMake(.2*size.height+(float)i*charFontSize, .5*size.width, charFontSize, charFontSize)];
buttonChar.tag = i;
[buttonChar setTitleColor:[UIColor blackColor] forState:(UIControlStateNormal)];
[buttonChar setTitle:[[NSString alloc] formatWithString:#"Button %d",i] forState:UIControlStateNormal];
buttonChar.titleLabel.font = [UIFont boldSystemFontOfSize:15];
buttonChar.titleLabel.textAlignment = UITextAlignmentCenter;
buttonChar.layer.cornerRadius = 5;
buttonChar.layer.masksToBounds = YES;
buttonChar.layer.borderWidth = 1;
buttonChar.layer.borderColor = [[UIColor blackColor] CGColor];
[buttonChar setBackgroundColor:[UIColor whiteColor]];
[buttonChar addTarget:self action:#selector(buttonAction:withEvent:) forControlEvents:UIControlEventTouchDragInside];
[buttonArray addObject:buttonChar];
}
buttons are available through:
[[buttonArray objectAtIndex:j] setTitle:#" " forState:UIControlStateNormal];
Since the tag option is also filled, I can always tell what button from the array was touched if it was displayed (buttonAction:withEvent:)
Cheers
Related
I'm trying to implement page control and scroll view using an image array, and for some reason, my images are shifting around when swiping to the next page. It almost seems like the images are too big for the scroll view, but making them smaller doesn't seem to work. Is there a way to make it so that the ScrollView doesn't "scroll" vertically? See code below.
SSViewController.h
#import <UIKit/UIKit.h>
#interface SSViewController : UIViewController <UIScrollViewDelegate>
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (strong, nonatomic) IBOutlet UIPageControl *pageControl;
#property (nonatomic, strong) NSArray *imageArray;
SSViewController.m
-(void)viewDidAppear:(BOOL)animated
{
imageArray = [[NSArray alloc] initWithObjects:#"first.png", #"second.png", nil];
for (int i = 0; i < [imageArray count]; i++) {
//We'll create an imageView object in every 'page' of our scrollView.
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.image = [UIImage imageNamed:[imageArray objectAtIndex:i]];
size:imageView.clipsToBounds = YES;
imageView.contentMode = UIViewContentModeScaleAspectFill;
[self.scrollView addSubview:imageView];
}
//Set the content size of our scrollview according to the total width of our imageView objects.
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [imageArray count], scrollView.frame.size.height);
}
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
// Update the page when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
self.scrollView.contentOffset = CGPointMake(self.scrollView.contentOffset.x, 0);
}
I think good idea will be to shift all your allocaton code (espacially all code define frames) to viewWillAppear method, because in viewDidLoad some frame wouldn't be already set.
I've got a UIButton declared in interface builder with an outlet set as follows:
#property (weak, nonatomic) IBOutlet UIButton *loginButton;
It works fine until I insert a subview. Then it stops responding. Here's the offending line:
[self.loginButton insertSubview:_gradientButtonView atIndex:0];
Commenting that out makes the button work again. Here's all the code involved (using the awesome SSToolkit and a custom category on UIColor):
SSGradientView *_gradientButtonView = [[SSGradientView alloc] initWithFrame:self.loginButton.layer.bounds];
_gradientButtonView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_gradientButtonView.topBorderColor = [UIColor colorWithRed:0.558f green:0.599f blue:0.643f alpha:1.0f];
_gradientButtonView.topInsetColor = [UIColor colorWithWhite:1.0f alpha:0.3f];
_gradientButtonView.colors = [NSArray arrayWithObjects:[UIColor from_hex:#"E6E7E8"], [UIColor from_hex:#"A7A9AC"], nil];
_gradientButtonView.layer.cornerRadius = 5;
self.loginButton.layer.cornerRadius = 5;
self.loginButton.titleLabel.shadowOffset = CGSizeMake(0, 1);
[self.loginButton setTitleShadowColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.loginButton.layer.masksToBounds = YES;
_gradientView.bottomBorderColor = [UIColor colorWithRed:0.428f green:0.479f blue:0.520f alpha:1.0f];
_gradientButtonView.clipsToBounds = YES;
_gradientButtonView.userInteractionEnabled = YES;
[self.loginButton insertSubview:_gradientButtonView atIndex:0];
self.loginButton.userInteractionEnabled = YES;
This was answered in the comments above:
Is there a specific reason you're writing
_gradientButtonView.userInteractionEnabled = YES;? To my knowledge, this prevents the view from sending touch events up the responder
chain
Ok simple question but can't find an answer.
I'v got a button to save information in my app.
I have
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
This is the information i want to save, i'v got 5 textfields in textFields mutablearray.
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
and
-(void)saveInfo {
[[[NSUserDefaults standardUserDefaults] setValue: ????? forKey:#"Phone"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
The question is how to access and get information from like textFields[1].text in my saveInfo void ?
Ok To get things a little bit clearer i'v added the whole class. its not very big, and maybe someone could see thats the problem with my implementation .
#implementation Settings
- (id)init: (TableViewController*) TableControll {
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textFields addObject:textField];
[textField release]; textField = nil;
}
UITextField *textName = textFields[0];
textName.placeholder = #"Vardas";
UITextField *textNo = textFields[1];
textNo.placeholder = #"Telefonas";
textNo.keyboardType = UIKeyboardTypeNumberPad;
UITextField *textPin = textFields[2];
textPin.keyboardType = UIKeyboardTypeNumberPad;
textPin.placeholder = #"Pin";
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(150, 20, 160, 30);
[button setTitle:#"Advanced settings" forState:UIControlStateNormal];
[TableControll.view addSubview:button];
UIButton *save = [UIButton buttonWithType:UIButtonTypeRoundedRect];
save.frame = CGRectMake(150, 60, 160, 30);
[save setTitle:#"Save settings" forState:UIControlStateNormal];
[TableControll.view addSubview:save];
[button addTarget:self action:#selector(goAdvanced)
forControlEvents:UIControlEventTouchUpInside];
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
return self;
}
-(void)goAdvanced {
AppDelegate *newControll = (AppDelegate*)[UIApplication sharedApplication].delegate;
[newControll ChangeController];
}
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
What you'd want to do if you are using interface builder is create a bunch of IBOutlet for your textfields instead of keeping them in an array. Check out this: tutorial
Now it looks like you're creating things by hand, so in this case, you probably just want to declare your array as #property so it can be accessed by your save method.
To access the text property of a UITextField from your array you would write:
((UITextField *)[textFields objectAtIndex:1]).text
If you want to access the all textfield,
for(int i=0;i<[textFields count];i++) {
UITextField *tempTxtField=[textFields objectAtIndex:i];
NSlog(#"%#",tempTxtField);
}
-(void)saveInfo {
NSMutableArray *tempArr = [NSMutableArray array];
for(int i = 0; i < [textFieldsArray count]; i++){
[tempArr addObject:[(UITextField*)[textFieldsArray objectAtIndex:i]text]];
}
[[[NSUserDefaults standardUserDefaults] setValue:tempArr forKey:#"Phone"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I'm not entirely sure I understand your question, but this is what I would do in your place. Instead of creating an array to hold each of the textfields, I'd just assign them a custom tag. Any number will work (although avoid zero since that's the default tag on all views). So your init method would look like this:
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
textField.tag = (i+1);
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textField release]; textField = nil;
}
Then in the code that you want to reference the text field, you'd retrieve the view by its tag, making sure to cast it as UITextField.
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *textField = nil;
UIView *view = [self.view viewsWithTag:i];
if ([view isKindOfClass:[UITextField class]]) {
textField = (UITextField *) view;
NSLog(#"do it %#",textField.text)
}
}
}
NOTE: I'm referencing self.view but you'll need to reference TableControll.view. You'll need to retain a reference to it somewhere in your code. Also, I'd recommend your start using ARC.
Hope that helps! Good luck!
Ok simple question but can't find an answer..
I need to pass my viewcontroller to an method "saveinfo" within a class which is called when the button is pressed, how to make viewcontroller visible to "saveinfo" method so i can use it there?
Ok i'll add the whole class. Basicaly I need to get the textfield information when the button is pressed. But i can't get access to textFields nor TableControll variables in my saveinfo method.
#implementation Settings
- (id)init: (TableViewController*) TableControll {
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textFields addObject:textField];
[textField release]; textField = nil;
}
UITextField *textName = textFields[0];
textName.placeholder = #"Vardas";
UITextField *textNo = textFields[1];
textNo.placeholder = #"Telefonas";
textNo.keyboardType = UIKeyboardTypeNumberPad;
UITextField *textPin = textFields[2];
textPin.keyboardType = UIKeyboardTypeNumberPad;
textPin.placeholder = #"Pin";
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(150, 20, 160, 30);
[button setTitle:#"Advanced settings" forState:UIControlStateNormal];
[TableControll.view addSubview:button];
UIButton *save = [UIButton buttonWithType:UIButtonTypeRoundedRect];
save.frame = CGRectMake(150, 60, 160, 30);
[save setTitle:#"Save settings" forState:UIControlStateNormal];
[TableControll.view addSubview:save];
[button addTarget:self action:#selector(goAdvanced)
forControlEvents:UIControlEventTouchUpInside];
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
return self;
}
-(void)goAdvanced {
AppDelegate *newControll = (AppDelegate*)[UIApplication sharedApplication].delegate;
[newControll ChangeController];
}
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
just add the NSMutableArray as ivar to your class:
#implementation TableControll {
NSMutableArray *_textFields;
}
- (id)init: (TableViewController*) tableControll {
_textFields = [[NSMutableArray alloc] initWithCapacity:5];
//init the textfields
//and add it as subview
}
// skipping the rest of the implementation
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
you should check if you could reuse the UITextFields or have to init the NSMutableArray every time again. It seems you don't use ARC, but you shouldn't write something like [textField release]; textField = nil;. You want to release the object to decrement the counter, but do not set it to nil (except in dealloc).
I am trying to build an NSMutableArray each time a button is pressed. I am using NSLog to check the array count after each button pressed and the value is zero. THe code is below.
ProjectViewController.h
NSMutableArray *numberQuery
...
#property (nonatomic, retain) NSMutableArray *numberQuery;
ProjectViewController.m
- (void)makeButtons{
UIButton * pickButton;
int y_plot = 150;
int x_plot = 70;
int z = 0;
for(int y = 1; y < 10; y++)
{
for(int x = 1; x < 5; x++){
z++;
pickButton = [UIButton buttonWithType:UIButtonTypeCustom];
pickButton.frame = CGRectMake(x*x_plot, y_plot, 60, 40);
[pickButton setBackgroundImage:[UIImage imageNamed:#"btnUnselected.png"] forState:UIControlStateNormal];
[pickButton addTarget:self action:#selector(digitClick:) forControlEvents:UIControlEventTouchUpInside];
[pickButton setTitle:[NSString stringWithFormat:#"%d",z] forState:UIControlStateNormal];
pickButton.titleLabel.textColor = [UIColor blackColor];
pickButton.tag = z;
[self.view addSubview:aButton];
}
y_plot=y_plot+45;
}
}
//************************
- (void)digitClick:(id)sender{
UIButton * chosenButton =(UIButton *)sender;
if ([sender isSelected] ==FALSE) {
[sender setSelected:TRUE];
[chosenButton setBackgroundImage:[UIImage imageNamed:#"btnSelected.png"] forState:UIControlStateNormal];
chosenButton.titleLabel.textColor = [UIColor whiteColor];
if([queryNumbersX count]<6){
[self numberSearchArray:chosenButton.tag];
}
}
else
{[sender setSelected:FALSE];
[chosenButton setBackgroundImage:[UIImage imageNamed:#"btnUnselected.png"]forState:UIControlStateNormal];
chosenButton.titleLabel.textColor = [UIColor blackColor];
}
forState:UIControlStateNormal];
NSLog(#"clicked button with title %d",chosenButton.tag);
}
//************************
-(void) numberSearchArray:(NSInteger)newNumber;
{
[self.numberQuery addObject:[NSNumber numberWithInt: newNumber]];
NSLog(#"numberSearchArray %d - count %d",newNumber, [self.numberQuery count]);
}
Am I using the NSMutableArray in the right manner...declaration?
This is the code in the viewDidLoad method
NSMutableArray *numberQuery = [[NSMutableArray alloc] initWithObjects:nil];
Although I have the array declared int he header file, It seems as though I cannot access it outside of the method in which it was allocated.
#property (nonatomic, retain) NSMutableArray *numberQuery;
You must balance that with
#synthesize numberQuery;
in the .m
and the correct creation would be
self.numberQuery = [NSMuatableArray arrayWithCapacity:someNumber];
By doing this
NSMutableArray *numberQuery = [[NSMutableArray alloc] initWithObjects:nil];
You are not using your #property you are creating a new variable, this is why you get the warning that your variable is not use, because it's scope is actually just the viewDidLoad method instead of the object.
It looks like that you have never alloced numberQuery. So it is always nil and thus addObject method is ignored. You need to alloc this in init (or any suitable place you like) and release in dealloc (or in other suitable place).