I add two BooleanCheck in my form(A and B).
I want the form can do this
when I click A. its value will be YES;
and then I click B. B Value be YES and A be NO.
Simply, they only one of them can be isChecked
-(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue
{
// super implmentation MUST be called
[super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue];
if ([rowDescriptor.tag isEqualToString:#"aCheck"]){
if(aCheck.value==YES)
bCheck.value = NO;
}
}else if ([rowDescriptor.tag isEqualToString:#"bCheck"]){
if(bCheck.value==YES)
aCheck.value = NO;
}
}
I'm not sure what is your aCheck and bCheck, but the idea is to reload the tableview or rows after changing the values of the affected rowDescriptors
-(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue
{
// super implmentation MUST be called
[super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue];
if ([rowDescriptor.tag isEqualToString:#"aCheck"]){
if(aCheck.value==YES)
bCheck.value = NO;
}
}else if ([rowDescriptor.tag isEqualToString:#"bCheck"]){
if(bCheck.value==YES)
aCheck.value = NO;
}
//
// The idea is to reloadData or reload indexPaths
//
XLFormRowDescriptor *rowA = [self.form formRowWithTag:#"aCheck"];
XLFormRowDescriptor *rowB = [self.form formRowWithTag:#"bCheck"];
NSIndexPath *ipA = [self.form indexPathOfFormRow:rowA];
NSIndexPath *ipB = [self.form indexPathOfFormRow:rowB];
[self.tableView reloadRowsAtIndexPaths:#[ipA,ipB] withRowAnimation:UITableViewRowAnimationNone];
}
Related
I have an array of buttons:
pokemon_cards = [[NSMutableArray alloc] init];
[pokemon_cards addObject:self.cardButton1];
[pokemon_cards addObject:self.cardButton2];
[pokemon_cards addObject:self.cardButton3];
later in some method I want to do a BOOL check to see if ALL of them are NOT selected simultaneously. In other words, if ALL of them are not selected notify user, otherwise proceed, even if just one of them is selected.
Here is what i've done but its not working and I can't figure out how to do this without adding the buttons in the loop to a temporary array:
-(BOOL)userCanProceedToTurn {
for (UIButton *button in pokemon_cards) {
if (![button isSelected]) {
// This only works for OR condition I want it to work for &&
return NO;
} else {
return YES;
}
}
}
So this is what I want it to do pretty much but the function above doesn't work for &&:
if (![self.cardButton1 isSelected] && ![self.cardButton2 isSelected] && ![self.cardButton3 isSelected]) {
//notify users they must selected at least one card
} else {
}
But i don't know which cards will be added to the array, that depends on the user, so I don't know how to check for that in the for loop
EDIT
I have implemented the code as suggested below. and as mentioned before this does not the && check that I was concerned with.
For example i need to make sure ALL cards are not currently in the 'not selected' state. but if one of those 3 cards are then they can proceed, even if the other two aren't. but with the check below, it will not proceed because the else statement is in the loop as well so everytime the loop is ran the buttons that aren't selected cause it to not proceed because the loop is ran 3 times.
here is my complete bool method, everything else works fine except the button one:
-(BOOL)userCanProceedToTurn {
if (self.energyAmount == 0) {
UIAlertView *view .. tell users they need energy before proceeding
return NO;
}
if (self.usernameLabel.text.length == 0) {
//Tell user they are not signed in
return NO;
}
NSLog(#"button is %lu", (unsigned long)pokemon_cards.count);
for (UIButton *button in pokemon_cards) {
if ([button isSelected]) {
NSLog(#"button.tag == %lu",button.tag);
return YES;
} else {
UIAlertView *view .. tell users they need to select at least one card
//this gets called because the loop is ran as many times there are buttons so inevitably i'll get an error. Which is why this works for the first button only, because it stops looping after it found that one since it was the first once selected
return NO;
}
}
return YES;
}
Do you actually need to know the state of each button?
Why not take the opposite approach:
- (BOOL)userCanProceedToTurn {
for (UIButton *button in pokemon_cards) {
if ([button isSelected]) {
return YES;
}
}
return NO;
}
EDIT
As a rule of thumb, methods that return a BOOL value should start with a flag set to YES or NO and only invert that flag, never setting it back to its original value. So basically, start with with BOOL result = YES and only flip it to NO, never ever flip it back to YES. This will have the pseudo-security of preventing something bad to happen.
Here's your method rewritten with this concept:
- (BOOL)userCanProceedToTurn {
BOOL isEverythingOK = NO;
NSString *message = nil;
if (self.energyAmount != 0) {
isEverythingOK = YES;
} else {
message = #"You need energy before proceeding.";
}
if (self.usernameLabel.text.length != 0) {
isEverythingOK = YES;
} else {
message = #"You are not signed in.";
}
for (UIButton *button in pokemon_cards) {
if ([button isSelected]) {
isEverythingOK = YES;
} else {
message = #"You need to select at least one card"
}
}
if (!isEverythingOK) {
UIAlertView *alert = [[UIAlertView alloc] initWith use the message here]
}
return isEverythingOK
}
We can sum up the questions, answers and comments. You can use these methods to do what you want :)
- (BOOL)userCanProceedToTurn
{
// Check Username
if (self.usernameLabel.text.length == 0)
{
[self showMessage: #"You are not signed in."];
return false;
}
// Check Energy
if (!(energyAmount > 0))
{
[self showMessage: #"You need energy before proceeding."];
return false;
}
// Check Cards
for (UIButton *button in pokemon_cards)
{
if ([button isSelected])
{
return true
}
}
[self showMessage: #"You need to select at least one card"];
return false;
}
- (void)showMessage:(NSString *)title
{
[[[UIAlertView alloc] initWithTitle: title message: nil delegate: nil cancelButtonTitle: #"OK" otherButtonTitles: nil] show];
}
If you need to know which buttons are selected then try
-(BOOL)userCanProceedToTurn
{
NSMutableArray *pokemon_cards_temp = [[NSMutableArray alloc] init];
for (UIButton *button in pokemon_cards)
{
if ([button isSelected])
{
[pokemon_cards_temp addObject:button];
}
}
// Do what you want with the selected buttons
if ([pokemon_cards_temp count] > 0)
{
return true;
}
else
{
return false;
}
}
This happens only on device and not on simulator..
I have two custom views and both have a UITextField in them(Child1 and Child2).
Both these views are placed on another UIView (Say viewA).
Now my requirement is such that when text is entered in one of the textfield I need to clear the other text fields content, so in the textFieldDidChange: method I inform viewA and than it iterates over its subview finds Child1 and sets its properties. But as soon as I access the textField of this Child1 to enable its userInteraction or and set its text to nil. This textfield now becomes the first responder.
I am not really sure why it does that. You can look at the below code to get more info.
Method inside viewA:
for (UIView *view in [self subviews])
{
if ([view isKindOfClass:[ChildView class]])
{
ChildView *concernedCustomerView = (ChildView *)view;
if (concernedCustomerView.typeOfCompartment == CompartmentTypeNone)
{
[concernedCustomerView.checkBoxButton setSelected:NO];
[concernedCustomerView.countSwitch setOn:NO animated:YES];
concernedCustomerView.countTextField.userInteractionEnabled = YES;
concernedCustomerView.countTextField.alpha = 1.0f;
concernedCustomerView.countTextField.text = nil;
}
}
}
Method inside custom Child View
-(void)textFieldDidChange:(id)sender
{
NSString *note = _countTextField.text;
note = [note stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
//If we are checking note for nil it should be before calling trimming white space
if (note && note.length > 0)
{
[_checkBoxButton setSelected:YES];
if (note.length == 3 && note.integerValue == 999)
{
[_countSwitch setOn:YES animated:YES];
_countTextField.userInteractionEnabled = NO;
_countTextField.alpha = 0.5f;
_countTextField.text = nil;
// [_countSwitch sendActionsForControlEvents:UIControlEventValueChanged];
}
}
else
{
[_checkBoxButton setSelected:NO];
}
if ([self.delegate conformsToProtocol:#protocol(ChildViewDelegate)] &&
[self.delegate respondsToSelector:#selector(adjustStateOfOtherControls:andCheckBoxStatus:)])
{
[self.delegate adjustStateOfOtherControls:_typeOfCompartment andCheckBoxStatus:_checkBoxButton.selected];
}
}
Do not set the view object to nil because they are alive and your controller is still active,
try to set _countTextField.text = #""; so that your textfield become empty.
Just a suggest:
1) Instead of manual iterate subviews you can assign tag to child views and uitextfields e.g:
child1View.tag = 100;
child2View.tag = 200;
...
textField1.tag = 10;
textField2.tag = 20;
then get child references from parent viewA by:
UIView *child1View = [viewA viewWithTag:100];
UIView *child2View = [viewA viewWithTag:200];
2) Set child views textfield delegate to a common viewcontroller
3) Handle one single
- (void)textFieldDidBeginEditing:(UITextField *)textField
4) Iniside this method check
if(textField.tag==10)
{
do stuff
}
else if(textfield.tag==20)
{
do other stuff
}
Hope it helps !
in my ios app, i have a view with several cells called PersonalDetailTVC. After selecting a value on another view the app returns to PersonalDetailTVC, and I want that the background color of certain cell changes depending on the new value, but the colour only changes when I return to the view again. Can you help me, please?
#import "PersonDetailTVC.h"
#implementation PersonDetailTVC
#synthesize delegate;
#synthesize person = _person;
#synthesize selectedRole;
#synthesize personFirstnameTextField = _personFirstnameTextField;
#synthesize personSurnameTextField = _personSurnameTextField;
#synthesize personRoleTableViewCell = _personRoleTableViewCell;
#synthesize groupColorTableViewCell = _groupColorTableViewCell;
- (void)viewDidLoad
{
NSLog(#"Setting the value of fields in this static table to that of the passed Person");
//self.personNameTextField.text = self.person.name;
self.personFirstnameTextField.text = self.person.firstname;
self.personSurnameTextField.text = self.person.surname;
self.personRoleTableViewCell.textLabel.text = self.person.inRole.name;
self.groupColorTableViewCell.textLabel.text = self.person.hasColor.color;
self.selectedRole = self.person.inRole; // ensure null role doesn't get saved.
if ([self.person.hasColor.color isEqual:#"Grey"]){
self.groupColorTableViewCell.backgroundColor = [UIColor colorWithRed:21.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1];
}
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
[tgr setCancelsTouchesInView:NO];
[self.tableView addGestureRecognizer:tgr];
[super viewDidLoad];
}
- (void)viewDidUnload
{
//[self setPersonNameTextField:nil];
[self setPersonFirstnameTextField:nil];
[self setPersonSurnameTextField:nil];
[self setPersonRoleTableViewCell:nil];
[self setGroupColorTableViewCell:nil];
[super viewDidUnload];
}
- (IBAction)save:(id)sender
{
NSLog(#"Telling the PersonDetailTVC Delegate that Save was tapped on the PersonDetailTVC");
self.person.firstname = self.personFirstnameTextField.text; // Set Firstname
self.person.surname = self.personSurnameTextField.text; // Set Surname
[self.person setInRole:self.selectedRole];
[self.person setHasColor:self.selectedRole];// Set Relationship!!!
[self.person.managedObjectContext save:nil]; // write to database
[self.delegate theSaveButtonOnThePersonDetailTVCWasTapped:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender // !
{
if ([segue.identifier isEqualToString:#"Person Role Segue"])
{
NSLog(#"Setting PersonDetailTVC as a delegate of PersonRoleTVC");
PersonRoleTVC *personRoleTVC = segue.destinationViewController;
personRoleTVC.delegate = self;
personRoleTVC.selectedPerson = self.person;
}
else {
NSLog(#"Unidentified Segue Attempted!");
}
}
- (void)dismissKeyboard {
[self.view endEditing:TRUE];
}
- (void)roleWasSelectedOnPersonRoleTVC:(PersonRoleTVC *)controller
{
self.personRoleTableViewCell.textLabel.text = controller.selectedRole.name;
self.groupColorTableViewCell.textLabel.text = controller.selectedRole.color;
self.selectedRole = controller.selectedRole;
NSLog(#"PersonDetailTVC reports that the %# role was selected on the PersonRoleTVC", controller.selectedRole.name);
[controller.navigationController popViewControllerAnimated:YES];
}
#end
As far as i can see, you're not changing a color anywhere in the provided code. While reading the code, i noticed a few things, so i thought i share it with you, maybe it helps:
If I understand correctly you are using a UITableViewCell without a UITableView. This is actually not a problem as UITableViewCell derives from UIView, but the cell will not have the behaviour of a UITableViewCell (because this is usually controlled by a UITableView). When adding a UITableViewCell manually as a subview, the cell will have the default behaviour of a UIView.
In your save: method I see the following 2 lines:
[self.person setInRole:self.selectedRole];
[self.person setHasColor:self.selectedRole];// Set Relationship!!!
Are you intentionally passing self.selectedRole to a property hasColor (or setHasColor: method)? Since I don't know the types of these objects this might be OK, but looks like you should set a color there.
In the roleWasSelectedOnPersonRoleTVC: method your are currently setting the text property twice:
self.personRoleTableViewCell.textLabel.text = controller.selectedRole.name;
self.groupColorTableViewCell.textLabel.text = controller.selectedRole.color;
Shouldn't that last line be something like this?
self.groupColorTableViewCell.textLabel.textColor = controller.selectedRole.color;
I am trying to implement a custom implementation of switching buttons so that only one can be selected at a time. I have run into a weird error where I init an object using [[ajdSwitchButton alloc] init]. In the init I set a class property as follows self.currentSelection = 2.
The issue is that between the init and the first call to an IBAction method, the value is changed to 0. I cannot figure out why. Here is the relevant code:
ajdSwitchButton.h
#import <UIKit/UIKit.h>
#interface ajdSwitchButton : UIView
#property (nonatomic) NSInteger currentSelection;
// Button Outlets
#property (nonatomic, strong) IBOutlet UIButton *buttonOne;
#property (nonatomic, strong) IBOutlet UIButton *buttonTwo;
// Button Actions
- (IBAction)buttonPress:(id)sender;
- (IBAction)buttonPressTwo:(id)sender;
// Instance Methods
- (void)switchButtonState:(UIButton *)button;
#end
ajdSwitchButton.m
#import "ajdSwitchButton.h"
#implementation ajdSwitchButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_currentSelection = 2;
}
return self;
}
// Handles button press actions for buttonOne
- (IBAction)buttonPress:(id)sender {
NSLog(#"%#", self);
// Y button pressed
if (self.currentSelection == 2) {
// No button is selected
// Highlight and select buttonOne
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else if (self.currentSelection == 1) {
// No was previously selected
// Unselect NO and select YES
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else {
// Y button already pressed
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
}
self.currentSelection = 0;
}
- (IBAction)buttonPressTwo:(id)sender {
// N button pressed
NSLog(#"%i", self.currentSelection);
if (self.currentSelection == 2) {
// No button is selected
// Highlight and select buttonOne
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
} else if (self.currentSelection == 0) {
// Yes was previously selected
// Unselect YES and select NO
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else {
// N button already pressed
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
}
self.currentSelection = 1;
}
// Switches the look and state of the button
- (void)switchButtonState:(UIButton *)button {
if (!button.selected) {
button.highlighted = YES;
button.selected = YES;
} else {
button.highlighted = NO;
button.selected = NO;
}
}
#end
I link an instance of ajdSwitchButton to an IBOutlet view within ViewController. Any help would be greatly appreciated.
EDIT: I pasted some NSLogs to check the memory value of the object directly after the init and as soon as the IBAction method is called. Here is the before and after:
<ajdSwitchButton: 0x746d2e0; frame = (0 0; 0 0); layer = <CALayer: 0x7472c40>>
<ajdSwitchButton: 0x7471b10; frame = (77 232; 180 83); autoresize = TM+BM; layer = <CALayer: 0x7471bf0>>
IBOutlets init through initWithCoder:(NSCoder)aDecoder, so you need to implement this method.
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
// Initialization code
_currentSelection = 2;
}
return self;
}
You are doing it in your code...
That might be a silly mistake or you need that.. please check your code :
- (IBAction)buttonPress:(id)sender {
NSLog(#"%#", self);
// Y button pressed
if (self.currentSelection == 2) {
// No button is selected
// Highlight and select buttonOne
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else if (self.currentSelection == 1) {
// No was previously selected
// Unselect NO and select YES
[self performSelector:#selector(switchButtonState:) withObject:self.buttonTwo afterDelay:0.0];
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
} else {
// Y button already pressed
[self performSelector:#selector(switchButtonState:) withObject:self.buttonOne afterDelay:0.0];
}
/* SEE HERE */
self.currentSelection = 0;
}
The issue is in your question itself.
You are initializing the variable in:
- (id)initWithFrame:(CGRect)frame
{
}
You already mentioned that you are creating the object using [[ajdSwitchButton alloc] init].
You are calling init not initWithFrame so the variable never get initialized.
So implement a function like:
- (id)init
{
self = [super init];
if (self) {
// Initialization code
_currentSelection = 2;
}
return self;
}
Hi im trying to use segmented control to swap between three map views however its not working.
My IBAction method is as follows.
- (IBAction)segmentSwitch:(id)sender {
NSLog(#"inside segmented switch");
NSLog(#"selected segment %#",selectedSegment);
if (selectedSegment == 0) {
mapView.mapType = MKMapTypeStandard;
}
else{
mapView.mapType = MKMapTypeHybrid;
}
}
I have declared UISegementedControl as an outlet and connected it to the xib view. I have also connected this method with touch down/touch up inside/outside. It still doesn't print the NSLog commands given above. Which means this method is not accessed at all?
Quick summary of how to set up a UISegmentedControl in IB for those dealing with more than two segments:
IBOutlet UISegmentedControl *segmentControl; in #interface (or set it as #property)
- (IBAction)segmentedControlIndexChanged:(id)sender; in .h before #end
drag "Segmented Control" into view and change "Style" to Plain, Bordered, or Bar
increment # of "Segments"
Choose "Segment" and edit the "Title" making sure "Enabled" is checked
Connect your segmentedControl to Files Owner
Connect your segmentedControlIndexChanged: action and select "Value Changed" NOT "Touch up Inside"!!
add some code, maybe a switch statement if you have say 4 segments:
-(IBAction)segmentedControlIndexChanged:(id)sender {
NSLog(#"segmentedControlIndexChanged");
switch (segmentControl.selectedSegmentIndex)
{
case 0:
{
NSLog(#"dateSegmentActive");
dateSegmentActive = YES;
noteSegmentActive = NO;
typeSegmentActive = NO;
userIDSegmentActive = NO;
[yourTable reloadData];
}
break;
case 1:
{
NSLog(#"noteSegmentActive");
dateSegmentActive = NO;
noteSegmentActive = YES;
typeSegmentActive = NO;
userIDSegmentActive = NO;
[yourTable reloadData];
}
break;
case 2:
{
NSLog(#"typeSegmentActive");
dateSegmentActive = NO;
noteSegmentActive = NO;
typeSegmentActive = YES;
userIDSegmentActive = NO;
[yourTable reloadData];
}
break;
case 3:
{
NSLog(#"userIDSegmentActive");
dateSegmentActive = NO;
noteSegmentActive = NO;
typeSegmentActive = NO;
userIDSegmentActive = YES;
[yourTable reloadData];
}
break;
default:
break;
}
}
In recent iOS versions, you need the braces for each case: or you will get errors. This also shows some bool flagging to keep track of what segment is active, maybe for your willDisplayCell method.
Hope you have selected the right method ValueChanged and also you have connected the outlet of your method properly.
The only thing you need to do now is to replace your code with your code.
- (IBAction)segmentSwitch:(UISegmentedControl *)sender
{
NSLog(#"inside segmented switch");
NSLog(#"selected segment %d",sender.selectedSegmentIndex);
if (sender.selectedSegmentIndex == 0)
{
mapView.mapType = MKMapTypeStandard;
}
else
{
mapView.mapType = MKMapTypeHybrid;
}
}
Try replacing this code with your code.
Hope this helps you.
You should use the ValueChanged action for detecting the the switch of segments.
Is selectedSegment your UISegmentedControl?
Then you code should be like:
- (IBAction) segmentSwitch:(id)sender {
if (self.selectedSegment.selectedSegmentIndex == 0) {
mapView.mapType = MKMapTypeStandard;
} else{
mapView.mapType = MKMapTypeHybrid;
}
}