changing a button's text from another method when the buttons are in a subclass? - iphone

How do you access a button that's in a subview of a view?
I have a viewController 'GamePlay', which has a scrollview in it called 'gameScroll'. Within this scrollview I have about 100 buttons, each with a tag, and I want to be able to change the text of the button from another method.
- (void) viewDidLoad {
//Created buttons in a for-loop, assigning each a tag
//numOfButtons is total number of buttons created
}
I imagine it would be something like this? but I cant seem to find an answer on exactly how i do it when the button is in a subview
- (void) otherMethod {
for (int i=0; i<numOfButtons; i++) {
// tagsForAction = get list of buttons that need to be changed from another array
for (j=0; j<tagsForAction.length; j++) {
intTagForAction = [tagsForAction objectAtIndex:j];
if (i = tagForAction) {
UIButton* button = [Gameplay.gameScroll.view viewWithTag:tagForAction];
button.title = #"A";
}
}
}
}
I know this code isnt totally right. Im just giving you an idea of the process. I can do everything except this part in the if statement:
UIButton* button = [Gameplay.gameScroll.view viewWithTag:tagForAction];
button.title = #"A";
so how do I change the text of these buttons?

NSArray *subViewList = [gameScroll subviews];
for (id button in subViewList)
{
if ([button isKindOfClass:[UIButton class]])
{
[button setTitle:#"OK" forState:UIControlStateNormal];
}
}
Try this code

You don't have to use the for loop like that, you can get an array of subviews from any view by doing something like [someView subviews]. So, inside of your otherMethod function you can do something like:
for (UIView *v in [gameScroll subviews]) {
if (v.tag == <some_int_here>) {
[v setTitle:#"Some other title" forState:UIControlStateNormal];
}
}
I'm not exactly sure what your criteria is for determining which buttons inside the gameScroll view have to get updated, but you can work from here.

Related

How to create Multiple buttons programmatically, get button name whenever press on particular button?

I want to create multiple buttons using MutableArray count. After creating the button, whenever pressing on particular button, I want to display that button name in a label. But Once press on button, it is always showing the MutableArray last index value name. Please help in this problem. I am fresher ti iOS. It's my code.
-(void)ViewDidLoad {
NSMutableArray *Mute_array=[[NSMutableArray alloc]initWithObjects:#"One", #"Two", #"Three", #"Four", #"Five", nil];
for (int k=0; k<[Mute_array count]; k++){
UIButton *btn_sub_category = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn_sub_category addTarget:self action:#selector(clicks:) forControlEvents:UIControlEventTouchDown];
[btn_sub_category setTitle:[Mute_Sub_Category objectAtIndex:k] forState:UIControlStateNormal];
btn_sub_category.frame = CGRectMake(278, k*130, 483, 44);
[self.view addSubview:btn_sub_category];
}
}
-(void)clicks:(id)sender{
label.text=[btn_sub_category currentTitle];
//Here a want to send the name of that clicked button current title
}
But, here button current title is always showing MutableArray last object "Five" only. I want pressed button current title.
-(void)clicks:(id)sender{
UIButton *theButton = (UIButton*)sender;
NSString *theButtonTitle = [theButton titleForState:UIControlStateNormal]
NSLog(#"theButtonTitle :- %#", theButtonTitle);
label.text=theButtonTitle;
//Here a want to send the name of that clicked button current title
}
Try this code.
I using following method to get title of button
titleForState:
Returns the title associated with the specified state.
- (NSString *)titleForState:(UIControlState)state Parameters
state
The state that uses the title. The possible values are described in UIControlState.
Return Value
The title for the specified state. If no title has been set for the
specific state, this method returns the title associated with the
UIControlStateNormal state.
Read Documentation https://developer.apple.com/library/ios/documentation/uikit/reference/UIButton_Class/UIButton/UIButton.html#//apple_ref/occ/instm/UIButton/titleForState:
Try like this:
-(void) clicks:(id)sender
{
if ([sender isKindOfClass:[UIButton class]])
{
UIButton *button = (UIButton*)sender;
NSString *title = button.currentTitle;
// do whatever you want with title
}
}
Try Like,
-(void)clicks:(id)sender{
UIButton *resultebutton= (UIButton*)sender;
label.text=resultebutton.titleLabel.text;
}

On iOS, is there a way to search ONLY subviews with a certain tag?

Because right now, viewWithTag actually search for itself first, and then all subviews recursively down the whole subtree, for a view with that tag.
But what if I set the tags of the subviews to 100, 101, etc, and later on, look for tag 100, but the parent of this current view sets the current view's tag to 100? Then viewWithTag will return the current view instead of any subview.
It is also strange that if the code is
[fooView viewWithTag: 123]
why would the code want to search the subtree including fooView itself? It is like, the code doesn't know fooView good enough to want to search for it too. Or put it another way, fooView is told to search itself... which is strange. A view doesn't know itself? (need to do a search to look for itself?)
So is there a way to search for subviews and grand-subviews only (without searching for self)?
Take advantage of the recursive nature of -viewWithTag:
- (UIView *)viewWithTagNotCountingSelf:(NSInteger)tag
{
UIView *toReturn = nil;
for (UIView *subView in self.subviews) {
toReturn = [subView viewWithTag:tag];
if (toReturn) {
break;
}
}
return toReturn;
}
Edit: this will drill down farther than "grand-subviews": it will get any view within the hierarchy that is not self. Also this is to be implemented in a category on UIView.
let result = view.subviews.filter{$0.tag == tag}.first
After reviewing the documentation for -viewWithTag: and running a few tests, it appears the answer to OP's question is - This behavior is already provided.
Return Value
The view in the receiver’s hierarchy whose tag property matches the
value in the tag parameter.
Discussion
This method searches the current view and all of its subviews for the
specified view.
I am concluding this to mean that 'view' is also a 'subview', thus limiting the scope of the search.
do this:
NSMutableArray *arrSameViewTag = [NSMutableArray array];
for(UIView *subview in [yourView subviews]) //your view to find subview
{
if(subview.tag == 123) //specific tah here
{
[arrSameViewTag addObject:subview]; //view found add in array
}
}
NSlog(#"arrSameViewTag : %#",arrSameViewTag);
To find specific like UIButton or any UIElement then like this:
NSMutableArray *arrSameViewTag = [NSMutableArray array];
for(id *subview in [yourView subviews]) //your view to find subview
{
if([subview isKindofClass[UIButton class]) //any UIElement of specific type here
{
UIButton *btn = (UIButton *)subview; //same UIElement mentioned for checking it
if(btn.tag == 123) //specific tah here
{
[arrSameViewTag addObject:subview]; //view found add in array
}
}
}
NSlog(#"arrSameViewTag : %#",arrSameViewTag)
For 1 level:
UIView *view;
for (int i = 0; i < viewToSearch.subviews.count; i++){
UIView *subview = viewToSearch.subviews[i];
if (subview.tag == tagToSeach){
view = subview;
break;
}
}
To search a view hierarchy with multiple levels:
__block UIView *view;
BOOL (^__block searchViewForTag)(UIView *,NSInteger) = ^(UIView *aView, NSInteger tag){
for (UIView *subview in aView.subviews){
if (subview.tag == tag){
view = subview;
return YES;
}
if (searchViewForTag(subview,tag)) return YES;
}
return NO;
};
NSInteger tagToSearchFor = 1;
searchViewForTag(viewToSearch,tagToSearchFor);
//Do something with view

iPhone - call UISwitch that is generated in a UIView when a button is pressed

To clarify my question, my program has three lightbulb on the screen (Customized UIButton)
when any lightbulb is pressed, I programatically generate a UIView with a switch on it
when I turn on the switch, corresponding lightbulb will light up (change its background image)
However, I have trouble accessing this UISwitch since I can't declare it publicly
My code goes something like this:
#property buttonA;
#synthesize buttonA;//all three buttons have their background image set to 'off.png'
- (IBAction)lightBulbPressed:(UIButton *)sender
{
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(1,1, 64, 64)];
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0,0,64,64)];
[mySwitch addTarget:self action:#selector(onOrOff) forControlEvents:UIControlEventValueChanged];
[myView addSubview:mySwitch]
[self.view addSubview:myView];
}
So what troubles me is how to program the selector onOrOff, so that it knows which switch is being touched and change the background image of corresponding button accordingly.
Think about your method:
- (IBAction)lightBulbPressed:(UIButton *)sender {
// your method
}
You already know who called it. This piece of information is stored in sender.
So you can save it and use later in onOrOff
By the way, if you are using UISwitch you have to check
UIControlEventValueChanged
and not UIControlEventTouchUpInside.
EDIT: To pass your sender you can store its value to a NSString *buttonTapped declared in your .h file
- (IBAction)lightBulbPressed:(UIButton *)sender {
if (sender == bttOne) {
buttonTapped = #"ButtonOneTapped";
} else if (sender == bttTwo) {
buttonTapped = #"ButtonTwoTapped";
} else if (sender == bttThree) {
buttonTapped = #"ButtonThreeTapped";
}
// your method
}
- (void)onOrOff {
if ([buttonTapped isEqualToString:#"ButtonOneTapped"]) {
// Button One
} else if ([buttonTapped isEqualToString:#"ButtonTwoTapped"]) {
// Button Two
} else if ([buttonTapped isEqualToString:#"ButtonThreeTapped"]) {
// Button Three
}
}
One way to do so, is taht you give them distinct tag numbers in IB, and in - (IBAction)lightBulbPressed:(UIButton *)sender method, get their tag. e.g. NSInteger pressedButtonTag = [sender tag];, and go from there.
Also, instead of alloc/init myView every time user presses a button, you can add that view in IB, add the switch to it, put in the hierarchy of the owner but not the view, and set an outlet to it in .h. Call it whenever you need it, and again, access the switch by tag e.g. ( UISwitch *mySwitch = (UISwitch *)[myView viewWithTag:kSwitchTag]; ) and do whatever you want to do (on or off), add it to the subview and remove it later. This is more efficient.

How to assign a value or title to a UIbutton instance so I can access it when I press the button?

I want to create a basic app where you have 8 numbered buttons, with a randomly generated number on each. You are given a total value, and have to click on buttons whose numbers add up to that value.
I need to show which buttons have been 'used' already (I hope to use the selected state for that, as I am using a custom button).
When you press a button, it needs to add the correct value to the 'totalSoFar and change the button to it's selected state.
The plan is that I currently have 8 UIButtons (b1, b2 etc). I have generated a random array of numbers, that I want to assign as the title of the button.
I have tried about a million variations on the theme of [b1 setTitle etc] but can't get it to work.
I have added a textview on top of the button (n1, n2...) that now displays my random numbers instead.
I have got it so that when you press a button, it gets the tag of that button, and then finds the matching position in the array, so I can use that value in the 'what's the total of all the buttons I have pressed' calculation. I cannot however figure out how to access the sender button in order to tell it to change to selected.
I'd much rather do this by just changing the title of the button, rather than having to have an extra textfield.
I am still quite new to Objective C, having previously only coded in actionscript for Flash, and I'm only asking after spending about 4 hours trying to search for a solution online (and swearing at my computer a lot...)
Here's what I have so far... I have tagged each button, so that b1 has a tag of 0, b2 has a tag of 1 etc...
-(IBAction) pressed:(id)sender {
int i;
UIButton *button = (UIButton *)sender;
for (i=0; i<8; i++) {
if ([button tag] == i)
{
//returns value in array as a string
NSString *temp2 = [pnumbers objectAtIndex:i];
//checks string value to see what total to add
if ([temp2 isEqualToString:#"1"]) {
total +=1;
}
if ([temp2 isEqualToString:#"2"]) {
total +=2;
}
if ([temp2 isEqualToString:#"3"]) {
total +=3;
}
if ([temp2 isEqualToString:#"4"]) {
total +=4;
}
if ([temp2 isEqualToString:#"5"]) {
total +=5;
}
if ([temp2 isEqualToString:#"6"]) {
total +=6;
}
if ([temp2 isEqualToString:#"7"]) {
total +=7;
}
if ([temp2 isEqualToString:#"8"]) {
total +=8;
}
if ([temp2 isEqualToString:#"9"]) {
total +=9;
}
}
}
}
I don't want to just make a new function for each separate button (as I plan to have 64 buttons in the end) in order to be able to access which button it was without lots of if and for statements. If nothing else, that seems like bad coding to me!
Hope this all makes sense...
I mostly just want to make the damn thing show the selectedState for the correct button once I've clicked on it. I can live with the textfields!
EDIT - for the record, I've now managed to get it to the selected state, by using
[b1 setSelected:FALSE];
at the start, and then adding
UIButton *button = (UIButton *)sender;
[sender setSelected:TRUE];
before the for loop. Still not sure how to get it to deselect the next time it is clicked though.
It seems like your code could be simplified:
- (IBAction) pressed:(UIButton *)sender {
int buttonIndex = [button tag];
total += [[pnumbers objectAtIndex:buttonIndex] intValue];
}
Many thanks to all who helped!
I finally managed to achieve what I wanted using this beautifully simple bit of code:
-(IBAction) pressed:(id)sender {
UIButton *button = (UIButton *)sender;
if ([sender isSelected] ==FALSE) {
[sender setSelected:TRUE];
int buttonIndex = [button tag];
total += [[pnumbers objectAtIndex:buttonIndex] intValue];
NSLog(#"%i", total);
}
else {
[sender setSelected:FALSE];
int buttonIndex = [button tag];
total -= [[pnumbers objectAtIndex:buttonIndex] intValue];
NSLog(#"%i", total);
}
}
Firstly, you're probably looking for -[UIButton setTitle:forState:], where state is probably going to be UIControlStateNormal. The other thing you might want to use is -[NSString intValue].
This would let you do
total += [temp2 intValue];
rather than your case statement.
First, you should be able to simplify your current code a bit:
- (void)pressed:(id)sender
{
UIButton *button = (UIButton *)sender;
total += [sender tag];
}
Then you can call the button's -setSelected: method to change its state:
- (void)pressed:(id)sender
{
UIButton *button = (UIButton *)sender;
total += [sender tag];
[button setSelected:YES];
}
When you create the buttons, use the following method to set its title:
- (void)setTitle:(NSString *)title forState:(UIControlState)state
If you use UIControlStateNormal as the argument, it will use the title for all three of the button's possible states.

Warning generated by UIButton setting code

I have a for loop setting the background images on buttons, basically the buttons are thumbnail previews of different items & can't be set statically, however the code gives an warning because it runs through all the UIViews but then calls setBackgroundImage which does not apply to all views. The warning is an irritation, I understand what it's complaining about, how can I get rid of it? (I don't want to turn off the warning, I want to fix the problem)
// For loop to set button images
for (UIView *subview in [self.view subviews]) // Loop through all subviews
{
// Look for the tagged buttons, only the 8 tagged buttons & within array bounds
if((subview.tag >= 1) && (subview.tag <= 8) && (subview.tag < totalBundles))
{
// Retrieve item in array at position matching button tag (array is 0 indexed)
NSDictionary *bundlesDataItem = [bundlesDataSource objectAtIndex:(subview.tag - 1)];
// Set button background to thumbnail of current bundle
NSString *picAddress = [NSString stringWithFormat:#"http://some.thing.com/data/images/%#/%#", [bundlesDataItem objectForKey:#"Nr"], [bundlesDataItem objectForKey:#"Thumb"]];
NSURL *picURL = [NSURL URLWithString:picAddress];
NSData *picData = [NSData dataWithContentsOfURL:picURL];
// Warning is generated here
[subview setBackgroundImage:[UIImage imageWithData:picData] forState:UIControlStateNormal];
}
}
You can either do this:
for (id subview in [self.view subviews])
So that the id type will stop any type checking... or check whether the object responds to the selector and call it like this:
if ([subview respondsToSelector:#selector(setBackgroundImage:forState:)]) {
[subview performSelector:#selector(setBackgroundImage:forState:)
withObject:[UIImage imageWithData:picData]
withObject:UIControlStateNormal];
}
Note that I coded that last part from memory.
A dangerous bit of code with so many assumptions, but...you would first do well to check the class of the UIView before sending it a setBackgroundImage message and then just simply cast your UIView to remove the warning:
if ([subview class] == [UIButton class]) {
[((UIButton *)subview) setBackgroundImage:[UIImage imageWithData:picData] forState:UIControlStateNormal];
}