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;
}
}
Related
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];
}
I have made a footer with 5 buttons, I want to disable the button once clicked till another button is clicked (means once another button is clicked then button should be re enable it). I am posting my code.
code
UIButton *btn = (UIButton *)sender;
NSInteger index= btn.tag;
[self setNavigationBarButtons:index];
switch (btn.tag)
{
case 1: // all media type
{ btn.enable=No;
messageToBeEdit =nil;
}
break;
case 2: // image type
{ btn.enable=No;
messageToBeEdit = nil;
}
break;
case 3: // video type
{ btn.enable=No;
messageToBeEdit = nil;
}
break;
case 4: // text type
{ btn.enable=No;
// forth button
break;
}
break;
case 5: // audio type
{//fifth button
btn.enable=No;
messageToBeEdit = nil;
}
break;
My issue is I can't able to click once i have clicked it, I want to reenable it once another button is clicked.
- (void) tapButton:(id)sender {
UIButton *btn = (UIButton *)sender;
NSInteger index= btn.tag;
[self setNavigationBarButtons:index]
//first enable all the other buttons
for(UIButton *b in [[btn superview] subviews]) {
if([b isKindOfClass:[UIButton class]]) {
b.enabled = YES; //reenable
}
}
btn.enabled = NO; //then disable tapped button
}
You don't need switch case here, as you're already getting tapped button.
You need to keep references of All the buttons, (eg Button1, Button2.. etc)
In your switch case, enable all other buttons. For instance, if user tapped on Button1, then enable all other buttons like
button2.enabled = YES;
button3.enabled = YES;
button4.enabled = YES;
button5.enabled = YES;
A better approach would be to keep IBOutletCollection of all the buttons and loop through the array to enable all other buttons.
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;
}
}
I have created 8 UIViews, I have a UIPicker and when the user selects something with the UIPicker I run the thread though a big if statement which I am not happy about.
I would like to know if what I am doing is okay? and also if the code I am using to load the view is how it should be done.. the code is below you will see I am simply loading the UIView once, then bringing it to the front layer... I would rather reload it entirely using remove from subview... but I couldn't get that to work..
Any one of the UIViews can be loaded at one time which is what is causing me issue.
#pragma mark - Picker Delegates
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
// ReloadView
if (row == 0) {
if (my1View == nil ) {
[self DrawView1];
}
[self.view bringSubviewToFront:my1View];
} else if (row == 1) {
if (my2View == nil ) {
[self DrawView2];
}
[self.view bringSubviewToFront:my2View];
}else if (row == 2) {
if (my3View == nil ) {
[self DrawView3];
}
[self.view bringSubviewToFront:my3View];
}else if (row == 3) {
if (my4View == nil ) {
[self DrawView4];
}
[self.view bringSubviewToFront:my4View];
}else if (row == 4) {
if (my5View == nil ) {
[self DrawView5];
}
[self.view bringSubviewToFront:my5View];
}else if (row == 5) {
if (my6View == nil ) {
[self DrawView6];
}
[self.view bringSubviewToFront:my6View];
}else if (row == 6) {
if (my7View == nil ) {
[self DrawView7];
}
[self.view bringSubviewToFront:my7View];
}else if (row == 7) {
if (my8View == nil ) {
[self DrawView8];
}
[self.view bringSubviewToFront:my8View];
}
}
The only other issue is that sometimes it will get stuck on one view when no matter what I pick nothing will load over it.
First of all, maybe to make it more beautiful you could think about a switch statement, but in terms of performance this doesn't matter:
switch (row) {
case 0:
if (my1View == nil ) {
[self DrawView1];
}
[self.view bringSubviewToFront:my1View];
break;
case 1:
if (my1View == nil ) {
[self DrawView2];
}
[self.view bringSubviewToFront:my2View];
break;
//THE OTHER CASES HERE...
default:
break;
}
About the rest:
I would suggest you put all the views into an array or dictionary and also have a variable currentView
#property (nonatomic, strong) UIView* currentView;
#property (nonatomic, strong) NSMutableDictionary* myViews;
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
// ReloadView
UIView* myNewView =
[self.myViews objectForKey:[NSString stringWithFormat:#"%d",(int)row]];
if (myNewView!=self.currentView) {
[self.currentView removeFromSuperview];
}
if (!myNewView) {
[self drawView:row];
}
[self.view addSubview:myNewView];
self.currentView = myNewView;
}
Make sure to initiate the myViews property in your viewDidLoad (or something similar) like this:
self.myViews = [NSMutableDisctionary new];
Also you need a new method for this row: [self drawView:row];, in this one you can just call your existing methods or copy your existing methods into this one!
In order to change as little as possible, you can use:
- (void)drawView:(NSInteger)row
{
switch (row) {
case 0:
[self DrawView1];
break;
case 1:
[self DrawView2];
break;
//THE OTHER CASES HERE...
default:
break;
}
}
I have an app that has a place-holder UIView (self.mainView) for viewControllers to be placed based on a tab selection. Using this technique is good because then only 1 of the views is loaded at any time, and I can create a ViewController class that operates with that view instead of having a monolithic controller that needs to understand all the views that may be in that place.
Here is some sample code I use to show the appropriate viewController into that place holder.
#property (weak, nonatomic) IBOutlet UIView *mainView;
#property (strong) UIViewController *currentController;
if (self.currentController) {
[self.currentController willMoveToParentViewController:nil];
[[self.currentController view] removeFromSuperview];
[self.currentController removeFromParentViewController];
self.currentController = nil;
}
switch (row) {
case 0:
self.currentController = [self.storyboard instantiateViewControllerWithIdentifier:#"AboutViewController"];
break;
case 1: {
...
}
break;
}
if (self.currentController) {
[self addChildViewController:self.currentController];
[self.mainView addSubview:self.currentController.view];
[self.currentController didMoveToParentViewController:self];
[self adjustMainView]; // my own method to adjust some constraints base on flags
[self.view layoutIfNeeded];
}
I developer your project and I can't see a problem in your code. Works fine. There is no problem in the code that you are showing. Maybe you should share more code to check it.
I tried to follow your style, however I changed small things.
You can found the project I created to test your code here.
I want to use a control I found on CocoaControls called SDNestedTable:https://github.com/serverdensity/ios-SDNestedTable
I have subclassed the SDNestedTableViewController class but I want to change the background color of the table cells and there is no provided way to do that.
The other classes in the library are SDGroupCell and SDSubCell which inherit from SDSelectableCell. SDSelectableCell contains the 3 methods to change the background depending on the state of the cell.
Here are the relevant methods in SDSelectableCell.m:
- (void) styleEnabled
{
for (UIView *view in checkBox.subviews) [view removeFromSuperview];
[checkBox addSubview:onCheckBox];
checkBox.alpha = 1.0;
itemText.alpha = 1.0;
self.backgroundView.backgroundColor = UIColorFromRGBWithAlpha(0x0d2e4d, 1.0);
}
- (void) styleDisabled
{
for (UIView *view in checkBox.subviews) [view removeFromSuperview];
[checkBox addSubview:offCheckBox];
checkBox.alpha = 1.0;
itemText.alpha = 0.4;
self.backgroundView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:1.0];
}
- (void) styleHalfEnabled
{
for (UIView *view in checkBox.subviews) [view removeFromSuperview];
[checkBox addSubview:onCheckBox];
checkBox.alpha = 0.45;
itemText.alpha = 0.7;
self.backgroundView.backgroundColor = UIColorFromRGBWithAlpha( , 1.0);
}
I can see two ways of doing this, but I'm a newb and want to verify the best way to handle this:
1) Just change the code in SDSelectableCell.m. I'd have to change 3 lines to set the 3 colors and then I'm done. However, I'm thinking it's bad practice to import libraries like this and just change the code. I can foresee issues in the future if someone working on the project has to reimport the library and doesn't know it was changed.
1a) I guess I could also just rename/refactor everything so that it isn't SD-whatever anymore, which at least would prevent someone else from thinking it's the original SDNestedTable library.
2) I could subclass SDSelectableCell and override those 3 methods. Although, this would require me to subclass every other class in the library, since they instantiate SDSelectable cell and I'd have to change all that.
3) Some other way? Categories and Extensions don't seem like they'd work, but maybe I'm missing something.
After giving the github code a quick look, it looks like they provide a simple way for you to setup the cells any way you'ld like. In your SDNestedTableDelegate implement the -mainTable:itemDidChange: method.
- (void)mainTable:(UITableView *)mainTable itemDidChange:(SDGroupCell *)item
{
SelectableCellState state = item.selectableCellState;
switch (state) {
case Checked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
case Unchecked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
case Halfchecked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
default:
break;
}
}
UPDATE
It looks like the library gives you the a place to format items and subitems when you subclass SDNestedTableViewController by overriding -mainTable:setItem:forRowAtIndexPath: and -item:setSubItem:forRowAtIndexPath:. Combining that with the above item did change code and extracting common functionality gives you:
- (void)PRIVATE_finalizeSelectableCell:(SDSelectableCell *)item
{
SelectableCellState state = item.selectableCellState;
switch (state) {
case Checked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
case Unchecked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
case Halfchecked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
default:
break;
}
}
- (void)mainTable:(UITableView *)mainTable itemDidChange:(SDGroupCell *)item
{
[self PRIVATE_finalizeSelectableCell:item];
}
- (SDGroupCell *)mainTable:(UITableView *)mainTable setItem:(SDGroupCell *)item forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self PRIVATE_finalizeSelectableCell:item];
return item;
}
- (SDSubCell *)item:(SDGroupCell *)item setSubItem:(SDSubCell *)subItem forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self PRIVATE_finalizeSelectableCell:subItem];
return subItem;
}