I want to create an UIViewController with for buttons. I want the user to press that four buttons with specific order. What I have done until now is that i give a random tag number in every button with the following code:
-(void)prepareArray {
self.arary = [[NSMutableArray alloc]init];
while (self.arary.count <4) {
int value = arc4random()%4;
BOOL isFound = [[self.arary filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"intValue == %d",value]]] count];
if(!isFound)
[self.arary addObject:[NSNumber numberWithInteger:value]];
}
NSLog(#"%#", arary);
button1.tag = [[arary objectAtIndex:0]intValue];
button2.tag = [[arary objectAtIndex:1]intValue];
button3.tag = [[arary objectAtIndex:2]intValue];
button4.tag = [[arary objectAtIndex:3]intValue];
So my question is: how can I create a method in which I got an order of pressing the buttons from 0 to 3? I tried with case and with if statements and I can not figure this out?
-(IBAction)buttonPressed:(UIButton *)button{
[clickDictionary setObject:[NSString stringWithFormat:#"%d",button.tag] forKey:button.titleLabel.text];
NSLog(#"clickDictionary : %#", clickDictionary);
}
You can write method as above. This method will be called on every button click.
In clickDictionary you will get the button name and its tag.
You can sort this dictionary as per your need.
I solve my problem with the following method. Firstly I create my buttons with a for loop:
for (int count = 0; count < 4; count++)
{
self.theButtons = [UIButton buttonWithType:UIButtonTypeSystem];
self.theButtons = [[UIButton alloc] initWithFrame:CGRectMake(100, y, 100, 40)];
[self.theButtons setTitle:[NSString stringWithFormat:#"Press Me"] forState:UIControlStateNormal];
[self.theButtons setTag:[[data.randomArray objectAtIndex:count]intValue]];
[self.theButtons addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.theButtons setBackgroundColor:[UIColor purpleColor]];
[self.buttonArray addObject:theButtons];
[self.view addSubview:theButtons];
y=y+60;
}
and attach the tag for the buttons with:
self.randomArray = [[NSMutableArray alloc]init];
while (self.randomArray.count <4) {
int value = arc4random()%4+1;
BOOL isFound = [[self.randomArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"intValue == %d",value]]] count];
if(!isFound)
[self.randomArray addObject:[NSNumber numberWithInteger:value]];
}
Finally if i want to check in which order the user pushed the buttons I create another array:
- (void)buttonClicked:(UIButton*)button
{
NSLog(#"Button %ld clicked.", (long int)[button tag]);
int value = [button tag];
button.hidden = YES;
[buttonArray removeObject:button];
//When user taps a button another array created which stores the button tags
if([addIntArray indexOfObject:[NSNumber numberWithInt:value]] == NSNotFound) {
[addIntArray addObject:[NSNumber numberWithInt:value]];
}
and compare it´s button click with a static array.
Related
I have dynamic UISwitches that I create using the for loop. I give the tag value for each control to have an identity. I want to reach these values later, but I get 0 each time. What I'm doing wrong?
for(int i = 0;i < self.extraArray.count; i++) {
ProductPropertiesModel *model = (ProductPropertiesModel *)[self.extraArray objectAtIndex:i];
UISwitch *switchButton = [[UISwitch alloc] initWithFrame:CGRectZero];
switchButton.translatesAutoresizingMaskIntoConstraints = false;
switchButton.tag = [model Id];
[switchButton setOn:NO];
[self.view addSubview:switchButton];
[switchButton addTarget:self action:#selector(setState:)
forControlEvents:UIControlEventValueChanged];
}
-(void)setState:(id)sender
{
UISwitch *uiswitch = (UISwitch *)sender;
NSInteger tagInteger= uiswitch.tag;
NSLog(#"%#", [NSString stringWithFormat:#"%li",(long)tagInteger]);
}
The tag value is 0, but that is wrong.
I found the problem. I just made a typo. I noticed that I was writing a typo when I was taking json data. I noticed Id writing instead of id.
NSError *jsonError;
self.extraJsonArray = nil;
self.extraJsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&jsonError];
self.extraArray = [[NSMutableArray alloc]init];
for(int j = 0;j < self.extraJsonArray.count;j++){
#try {
//NSInteger *Id = (NSInteger *)[(NSNumber *)[[self.extraJsonArray objectAtIndex:j]objectForKey:#"Id"] integerValue]; Problem is here
NSInteger *Id = (NSInteger *)[(NSNumber *)[[self.extraJsonArray objectAtIndex:j]objectForKey:#"id"] integerValue];
double price = (double)[(NSNumber *)[[self.extraJsonArray objectAtIndex:j] objectForKey:#"price"] doubleValue];
NSString *property =(NSString *)[[self.extraJsonArray objectAtIndex:j] objectForKey:#"property"];
ProductPropertiesModel *model = [[ProductPropertiesModel alloc] init];
[model setId:Id];
[model setProperty:property];
[model setPrice:price];
[model setChecked:#"No"];
[self.extraArray addObject:model];
} #catch (NSException *exception) {
NSLog(#"%#", exception.reason);
} #finally {
}
}
I would recommend instead setting [model id] as tag, you should set array index as tag.
and then later on in the switch control method, you can get the value from array index, using the code.
ProductPropertiesModel *model = (ProductPropertiesModel *)[self.extraArray objectAtIndex:i];
Hope this helps.
Try this:
for (int i =0; i < self.extraArray.count; i++) {
CGRect frame = CGRectMake(x, y, height, width);
UISwitch *switchControl = [[UISwitch alloc] initWithFrame:frame];
//add tag as index
switchControl.tag = i;
[switchControl addTarget:self action:#selector(setState:) forControlEvents: UIControlEventValueChanged];
[switchControl setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:switchControl];
y= y+50.0;
}
- (IBAction) setState: (UISwitch *) sender {
NSLog(#"no.%d %#",sender.tag, sender.on ? #"On" : #"Off");
//use sender.tag , you know which switch you selected
}
I am using onegray's Radio button class in one of my projects. the one mentioned here: Best radio-button implementation for IOS
I am using these radio buttons for my answer choices on a quiz. when the user clicks the next button, the labels are populated with new choices. the only problem is that the old ones dont disappear. So when I click next, the new set of buttons are placed on top of the old ones.
what is the simplest way to first check to see if they already exist.. and if so.. delete them.. before displaying the new ones?
here is my code.
#interface LABViewControllerQuiz ()
#end
#implementation LABViewControllerQuiz
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
int counter =0;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_fileContents = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"quizQuestions" ofType:#"txt"] encoding:NSUTF8StringEncoding error: nil];
_theScanner = [NSScanner scannerWithString:_fileContents];
_separator = [NSCharacterSet characterSetWithCharactersInString:#"~"];
_lineBreak =[NSCharacterSet characterSetWithCharactersInString:#"#"];
_alreadyGeneratedNumbers =[[NSMutableArray alloc]init];
_numQuestions =0;
_userAnswers = [[NSMutableArray alloc]init];
_answerKey = [[NSMutableArray alloc]init];
[self nextQuestion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
- (IBAction)nextQuestion:(UIButton *)sender
{
_NextQuestionButton.enabled = YES;
_submitButton.enabled = NO;
NSLog(#"NumQuestion = %d", _numQuestions);
if (_numQuestions >9)
{
_NextQuestionButton.enabled = NO;
_submitButton.enabled = YES;
}else
{
int r = arc4random() %20;
while ([_alreadyGeneratedNumbers containsObject:[NSNumber numberWithInt:r]])
{
r = arc4random() %20;
}
[_alreadyGeneratedNumbers addObject:[NSNumber numberWithInt:r]];
while(![_theScanner isAtEnd])
{
NSLog(#"Location= %d", [_theScanner scanLocation]);
NSLog(#"Already Generated numbers:");
int i =0;
while (i < [_alreadyGeneratedNumbers count])
{
NSLog(#"%#", [_alreadyGeneratedNumbers objectAtIndex:i]);
i++;
}
NSString *line;
_lineArray = [[NSMutableArray alloc] init];
[_theScanner scanUpToCharactersFromSet:_lineBreak intoString:&line];
[_theScanner setCharactersToBeSkipped:_lineBreak];
NSScanner *inner = [NSScanner scannerWithString:line];
NSString *word;
int wordCount = 0;
NSLog(#"r = %d counter = %d", r, counter);
if (counter ==r)
{
while(![inner isAtEnd])
{
[inner scanUpToCharactersFromSet:_separator intoString:&word];
[inner setCharactersToBeSkipped:_separator];
[_lineArray insertObject:word atIndex:wordCount];
_questionText.text = [NSString stringWithFormat:#"Question %d \n %#", _numQuestions +1,[_lineArray objectAtIndex:0]];
wordCount++;
[_theScanner setScanLocation:0];
counter = 0;
}
[sender setHidden:YES];
NSMutableArray* buttons = [NSMutableArray arrayWithCapacity:4];
CGRect btnRect = CGRectMake(25, 420, 300, 30);
for (NSString* optionTitle in #[[_lineArray objectAtIndex:1], [_lineArray objectAtIndex:2], [_lineArray objectAtIndex:3], [_lineArray objectAtIndex:4]])
{
RadioButton* btn = [[RadioButton alloc] initWithFrame:btnRect];
[btn addTarget:self action:#selector(onRadioButtonValueChanged:) forControlEvents:UIControlEventValueChanged];
btnRect.origin.y += 40;
[btn setTitle:optionTitle forState:UIControlStateNormal];
[btn setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
btn.titleLabel.font = [UIFont boldSystemFontOfSize:17];
[btn setImage:[UIImage imageNamed:#"unchecked.png"] forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:#"checked.png"] forState:UIControlStateSelected];
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
btn.titleEdgeInsets = UIEdgeInsetsMake(0, 6, 0, 0);
[self.view addSubview:btn];
[buttons addObject:btn];
}
[buttons[0] setGroupButtons:buttons]; // Setting buttons into the group
[buttons[0] setSelected:NO]; // Making the first button initially selected
NSLog(#"the question is = %#", [_lineArray objectAtIndex:0]);
//NSLog(#"Line arrayINDEX %d = %#", wordCount,[_lineArray objectAtIndex:wordCount]); _numQuestions ++;
break;
}else
{
counter ++;
}
}
}
[_answerKey addObject:[_lineArray objectAtIndex:5]];
}
-(void) onRadioButtonValueChanged:(RadioButton*)sender
{
// Lets handle ValueChanged event only for selected button, and ignore for deselected
if(sender.selected)
{
NSLog(#"Selected: %#", sender.titleLabel.text);
}
}
Save buttons as an instance variable. You're already adding all your buttons into the array, you just throw the array out for some reason.
#interface LABViewControllerQuiz ()
#property (strong) NSMutableArray *buttons;
#end
And then this line:
NSMutableArray* buttons = [NSMutableArray arrayWithCapacity:4];
Becomes these lines:
if (self.buttons) {
[self.buttons makeObjectsPerformSelector:#selector(removeFromSuperview)];
[self.buttons removeAllObjects];
} else {
self.buttons = [NSMutableArray arrayWithCapacity:4];
}
For each of my buttons I am doing the same methods but using a different variable from my array, this does work fine but its a lot of code and I will have around 40 buttons by the end. I was wondering if I could use the button tag to match with the objectAtIndex in my array, so I will not need to re-write for each tag, Hope this question makes sense, below is my code so far:
- (IBAction)pressCountBtn:(id)sender
{
UIButton * btn = (UIButton *)sender;
int btag = btn.tag;
if(btag == 1)
{
self.presscount1 ++;
[self.pressCountArray replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:self.presscount1]];
if (self.presscount1 > 3)
{
self.presscount1 = 0;
[btn setTitle:[NSString stringWithFormat:#""] forState:UIControlStateNormal];
}
else
[btn setTitle:[NSString stringWithFormat:#"%i",self.presscount1] forState:UIControlStateNormal];
}
else if (btag == 2)
{
self.presscount2 ++;
[self.pressCountArray replaceObjectAtIndex:1 withObject:[NSNumber numberWithInt:self.presscount2]];
if (self.presscount2 > 3)
{
self.presscount2 = 0;
[btn setTitle:[NSString stringWithFormat:#""] forState:UIControlStateNormal];
}
else
[btn setTitle:[NSString stringWithFormat:#"%i",self.presscount2] forState:UIControlStateNormal];
}
else if (btag == 3)
{
self.presscount3 ++;
[self.pressCountArray replaceObjectAtIndex:2 withObject:[NSNumber numberWithInt:self.presscount3]];
if (self.presscount3 > 3) {
self.presscount3 = 0;
[btn setTitle:[NSString stringWithFormat:#""] forState:UIControlStateNormal];
}
else
[btn setTitle:[NSString stringWithFormat:#"%i",self.presscount3] forState:UIControlStateNormal];
}
You can do something like this:
- (IBAction)pressCountBtn:(id)sender
{
UIButton * btn = (UIButton *)sender;
int btag = btn.tag;
int curCnt = [[self.pressCountArray objectAtIndex:btag] intValue];
curCnt ++;
if (curCnt > 3)
{
curCnt = 0;
[btn setTitle:[NSString stringWithFormat:#""] forState:UIControlStateNormal];
}
else {
[btn setTitle:[NSString stringWithFormat:#"%i",curCnt] forState:UIControlStateNormal];
}
[self.pressCountArray replaceObjectAtIndex:btag withObject:[NSNumber numberWithInt:curCnt]];
}
You'll just have to make sure that all objects in self.pressCountArray are NSNumbers, which you can easily do when you initialize the array.
Getting the button index from an array of buttons is easy.
- (IBAction)pressCountBtn:(id)sender
{
if ([sender isKindOfClass:[UIButton class]]) {
UIButton *thisButton = (UIButton *)sender;
NSUInteger indexOfButton = [yourButtonArray indexOfObject:thisButton];
if (indexOfButton != NSNotFound) {
// Now use this indexOfButton for whatever you want
}
}
}
create a strong array to hold the values(count) for each button tag.
NSInteger numberOfRows=3;
NSMutableArray *array=[[NSMutableArray alloc] initWithCapacity:numberOfRows];
Then ,
- (IBAction)pressCountBtn:(id)sender
{
UIButton * btn = (UIButton *)sender;
int btag = btn.tag;
//add count first time for tag
if([[array objectAtIndex:btag] valueForKey:#"COUNT"]==NULL){
[[array objectAtIndex:btag] setValue:#"1" forKey:#"COUNT"];
}else{
//get count from array
NSInteger count=[[[array objectAtIndex:btag] valueForKey:#"COUNT"] integerValue];
count+=count;
if (count> 3)
{
count = 0;
[btn setTitle:[NSString stringWithFormat:#""] forState:UIControlStateNormal];
}
else
[btn setTitle:[NSString stringWithFormat:#"%i",count] forState:UIControlStateNormal];
//write the updated count back to array
[[array objectAtIndex:btag] setValue:[NSString stringWithFormat:#"%d",count] forKey:#"COUNT"];
}
}
I have several textfields in my scene which are added programatically according to the user preference. Is there a way to retrieve all textfield data at once and store them in an array corresponding to their order, so from top to bottom the data is added to an array.
for (int i = 0; i < _orderFormArray.count ; i++) {
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(220, x, 70, 20)];
[textField setPlaceholder:#"Enter Ammount"];
[textField setBorderStyle:UITextBorderStyleBezel];
[textField setTag:i];
[[self view] addSubview:textField];
textField.delegate = self;
x+=60;
}
My code which adds the UITextFields to the scene, maybe the tag will be of assistance.
you question itself is having half of the answer
NSMutableDictionary *contentsDic = [NSMutableDictionary array];
for (int i = 0; i < _orderFormArray.count; i++) {
UITextField *textField = [self.view viewForTag:i];
[contentsDic setObject:textField.text forKey:[NSString stringWithFormat:#"%d", i]];
}
You can add the textfield to a mutable array, or you can cycle through the view's subviews:
[self.view.subviews enumerateObjectsUsingBlock:^(UIView* obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[UITextField class]]) {
NSLog(#"%#", ((UITextField*)obj).text);
}
}];
I have a method that is called once in a while. it creates a button and gives it a frame and adds it on the self.view. The problem is that I don't want these buttons to overlap, so I am using a counter (integer) to keep the count of how many there are. Sometimes the counter goes wrong of +-1 and two buttons appear overlapping.
This is the code:
in my .h
int CountNumberOfBluetoothDevices;
in the .m
- (void) browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info{
NSLog(#"%#", peerID.description);
CountNumberOfBluetoothDevices = CountNumberOfBluetoothDevices + 1;
NSArray *keys = [BluetoothDeviceDictionary allKeys];
for (NSUInteger k = keys.count; k > 0; k--) {
MCPeerID *key = keys[k - 1];
UIButton *btn = BluetoothDeviceDictionary[key];
if ([key.displayName isEqualToString:peerID.displayName]) {
[btn removeFromSuperview];
NSLog(#"REMOVE DOUBLE");
CountNumberOfBluetoothDevices--;
[BluetoothDeviceDictionary removeObjectForKey:key];
}
}
if (CountNumberOfBluetoothDevices == 1) {
BluetoothDeviceButton = [[UIButton alloc] initWithFrame:CGRectMake(130, -200, 55,55)];
}else if (CountNumberOfBluetoothDevices == 2){
BluetoothDeviceButton = [[UIButton alloc] initWithFrame:CGRectMake(240, -200, 55,55)];
}else if (CountNumberOfBluetoothDevices == 3){
BluetoothDeviceButton = [[UIButton alloc] initWithFrame:CGRectMake(130, -125, 55,55)];
}else if (CountNumberOfBluetoothDevices == 4){
BluetoothDeviceButton = [[UIButton alloc] initWithFrame:CGRectMake(240, -125, 55,55)];
}
Is there a better way to detect this?
Don't use upper case variable and/or property names.
Change CountNumberOfBluetoothDevices = CountNumberOfBluetoothDevices + 1; to countNumberOfBluetoothDevices++;
Use [keys count] instead of keys.count.
The -200 in CGRectMake(130, -200, 55,55)]; is very strange an looks like you have some issues with your view hierarchy. Why is it negative?
Instead of this
NSArray *keys = [BluetoothDeviceDictionary allKeys];
for (NSUInteger k = keys.count; k > 0; k--) {
MCPeerID *key = keys[k - 1];
...
}
I would do
for (MCPeerID *key in [bluetoothDeviceDictionary allKeys]) {
...
}