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.
Related
I have aUITextField and below that 3 button. User can enter the amount inUITextField. And When user clicked the button belowUITextField it will add the amount inUITextField with amount written in button.
First button will add 100, Second will add 500 ad 3rd will add 1000. What is the best method to achieve it.
I try to implement following but got button.tag=0
/*Amount increment*/
- (IBAction)Btn_Incr100:(id)sender {
[self addTextFieldValue:nil];
}
- (IBAction)Btn_Incr500:(id)sender {
[self addTextFieldValue:nil];
}
- (IBAction)Btn_Incr1000:(id)sender {
[self addTextFieldValue:nil];
}
-(void)tagNumber{
Btn_Incr100.tag=1;
Btn_Incr500.tag=2;
Btn_Incr1000.tag=3;
}
-(void) addTextFieldValue:(UIButton*) button
{
int amount=[Txt_Amount.text intValue];
int AddAmount;
NSLog(#"button.tag%d",button.tag);
if (button.tag==1) {
AddAmount=100;
}
else if (button.tag==2) {
AddAmount=500;
}
else if(button.tag==3) {
AddAmount=1000;
}else{
AddAmount=0;
}
amount=amount+AddAmount;
Txt_Amount.text=[NSString stringWithFormat:#"%d",amount];
NSLog(#"%d",amount);
NSLog(#"%#",Txt_Amount.text);
}
Try using it by implementing tag
- (void)viewDidLoad {
[super viewDidLoad];
[self tagNumber];
}
-(void)tagNumber{
Btn_Incr100.tag=1;
Btn_Incr500.tag=2;
Btn_Incr1000.tag=3;
}
-(void) addTextFieldValue:(UIButton*) button
{
int amount=[Txt_Amount.text intValue];
int AddAmount;
int buttonTagIndex = button.tag;
switch (buttonTagIndex) {
case 1:
AddAmount=100;
break;
case 2:
AddAmount=500;
break;
case 3:
AddAmount=1000;
break;
default:
AddAmount=0;
break;
}
amount=amount+AddAmount;
Txt_Amount.text=[NSString stringWithFormat:#"%d",amount];
}
- (IBAction)btnAmountClick:(id)sender{
UIButton *button = sender;
[self addTextFieldValue:button];
}
With the help of this you can achieve:
-(void)displayvalue:(id)sender {
UIButton *resultButton = (UIButton *)sender;
NSLog(#" The button's title is %#." resultButton.currentTitle);
}
and now you can set this text inside your textfield.
Add this method as every button action.
-(void) addTextFieldValue:(UIButton*) button
{
NSString *string;
if ([button.text hasPrefix:#"+"] && [button.text length] > 1)
{
string = [string substringFromIndex:1];
}
int textFieldValue =[textField.text integerValue] + string.integerValue;
textField setText:[NSString stringWithFormat:#"%i",textFieldValue];
}
NSString *string;
if ([button.text hasPrefix:#"+"] && [button.text length] > 1)
{
string = [string substringFromIndex:1];
}
int textFieldValue =[textField.text integerValue] + string.integerValue;
textField setText:[NSString stringWithFormat:#"%i",textFieldValue];
or
connect separate actions
-(IBAction) onClick1: (id) sender]
{
NSLog(#"User clicked %#", sender);
textField.text = [textField.text integerValue] + 100
}
You can do this way -
The three buttons below your textfield, link them all to a common method say,
-(IBAction)addBtnClicked:(UIButton *)btn
Given tags to three buttons like for button 100,
btn1.tag=100..
then for button 500,
btn2.tag = 500..
then for button 1000, btn2.tag = 1000.
then in
-(IBAction)addBtnClicked:(UIButton *)btn
{
int value = -1;
if(btn.tag == 100)
{
value =[txtFldText.text intValue] + 100;
}
else if(btn.tag == 500)
{
value =[txtFldText.text intValue] + 500;
}
else if(btn.tag == 1000)
{
value =[txtFldText.text intValue] + 1000;
}
txtFldText.text = [NSString stringWithFormat:#"%d",value];
}
Simply you can do like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_txtAmount.text=#"0";
_btn100.tag=100;
_btn500.tag=500;
_btn1000.tag=1000;
}
- (IBAction)btnAmountClick:(id)sender
{
UIButton *btn=sender;
if (btn.tag==100)
{
[self addAmount:#"100"];
}
if (btn.tag==500)
{
[self addAmount:#"500"];
}
if (btn.tag==1000)
{
[self addAmount:#"1000"];
}
}
-(void)addAmount:(NSString*)strAmount
{
int amount=[_txtAmount.text intValue]+[strAmount intValue];
_txtAmount.text=[NSString stringWithFormat:#"%d",amount];
}
First set tag to every button like 0,1,2.
then connect IBOutlet of all button to single IBAction and
implement the IBAction as below.
- (IBAction)btnClicked:(id)sender
{
switch ([sender tag]) {
case 0:
{
NSString *s=self.txtField.text;
int add=[s intValue]+ 100;
self.txtField.text=[NSString stringWithFormat:#"%d",add];
break;
}
case 1:
{
NSString *s=self.txtField.text;
int add=[s intValue]+ 200;
self.txtField.text=[NSString stringWithFormat:#"%d",add];
}
break;
case 2:
{
NSString *s=self.txtField.text;
int add=[s intValue]+ 500;
self.txtField.text=[NSString stringWithFormat:#"%d",add];
}
break;
default:
break;
}
}
There's a better solution for this.
You can use tags smth differently, as they are.
Just tie your three buttons as actions to this method and set the tags to 100/500/1000
- (void)buttonAction:(id)sender {
textField.text = [NSString stringWithFormat:#"%li", (long)(textfield.text.intValue + sender.tag)];
}
I am creating a custom delegate UIAlertView's alert:buttonClickedAtIndex: method, but it is not working properly. I am subclassing a UIView, and I have two buttons that are tagged as 0 and 1. This still does not work when I go to check the delegate for my custom view. Here the code that I did.
Custom View
- (void) buttonTouchedWithIdentifier:(NSInteger)identifier
{
if (identifier == 0) {
[self.delegate alert:self didClickButtonWithTagIdentifier:0];
}
if (identifier == 1) {
[self.delegate alert:self didClickButtonWithTagIdentifier:1];
}
}
* in my showInViewMethod *
[self.dismissButton addTarget:self action:#selector(buttonTouchedWithIdentifier:) forControlEvents:UIControlEventTouchDown];
[self.continueButton addTarget:self action:#selector(buttonTouchedWithIdentifier:) forControlEvents:UIControlEventTouchDown];
self.dismissButton.tag = 0;
self.continueButton.tag = 1;
* in my view controller *
nextLevelAlert = [[ARAlert alloc] init];
nextLevelAlert.delegate = self;
[nextLevelAlert showInView:self.view
withMessage:[NSString stringWithFormat:#"Congratulations, you have completed level %i.\nWould you like to continue?", levelNumber]
dismissButtonTitle:#"Menu"
continueButtonTitle:#"Next Level"];
- (void)alert:(ARAlert *)alert didClickButtonWithTagIdentifier:(NSInteger)tagId
{
if (alert == nextLevelAlert) {
if (tagId == 0) {
NSLog(#"User does not want to continue.");
}
}
}
Now, nextLevelAlert has the delegate set to self, and I do have the delegate declared in my view controller's class. Also, when i do the showInView... for nextLevelAlert, it DOES appear, it is recognizing what button is being pressed.
My guess is your param is not a NSInteger but the button, you should change buttonTouchedWithIdentifier like this :
- (void) buttonTouchedWithIdentifier:(id)sender
{
UIButton *button = (UIButton*)sender;
NSLog(#"buttonTouchedWithIdentifier %#",#(button.tag));
if (button.tag == 0) {
[self.delegate alert:self didClickButtonWithTagIdentifier:0];
}
if (button.tag == 1) {
[self.delegate alert:self didClickButtonWithTagIdentifier:1];
}
}
Also when comparing two objects use isEqual: instead of ==
- (void)alert:(ARAlert *)alert didClickButtonWithTagIdentifier:(NSInteger)tagId
{
if ([alert isEqual:nextLevelAlert]) {
if (tagId == 0) {
NSLog(#"User does not want to continue.");
}
}
}
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 !
I'm making an app where I add a subview to a view using addSubview: on an IBAction. In the same way, when the button with that IBAction is touched again should call removeFromSuperview on that subview added on that IBAction:
PSEUDO CODE
-(IBAction)showPopup:(id)sender
{
System_monitorAppDelegate *delegate = (System_monitorAppDelegate *)[[UIApplication sharedApplication] delegate];
UIView *rootView = delegate.window.rootViewController.view;
if([self popoverView] is not on rootView)
{
[rootView addSubview:[self popoverView]];
}
else
{
[[self popoverView] removeFromSuperview];
}
}
You are probably looking for UIView's -(BOOL)isDescendantOfView:(UIView *)view; taken in UIView class reference.
Return Value
YES if the receiver is an immediate or distant
subview of view or if view is the receiver itself; otherwise NO.
You will end up with a code like :
Objective-C
- (IBAction)showPopup:(id)sender {
if(![self.myView isDescendantOfView:self.view]) {
[self.view addSubview:self.myView];
} else {
[self.myView removeFromSuperview];
}
}
Swift 3
#IBAction func showPopup(sender: AnyObject) {
if !self.myView.isDescendant(of: self.view) {
self.view.addSubview(self.myView)
} else {
self.myView.removeFromSuperview()
}
}
Try this:
-(IBAction)showPopup:(id)sender
{
if (!myView.superview)
[self.view addSubview:myView];
else
[myView removeFromSuperview];
}
UIView *subview = ...;
if([self.view.subviews containsObject:subview]) {
...
}
The Swift equivalent will look something like this:
if(!myView.isDescendantOfView(self.view)) {
self.view.addSubview(myView)
} else {
myView.removeFromSuperview()
}
Check the superview of the subview...
-(IBAction)showPopup:(id)sender {
if([[self myView] superview] == self.view) {
[[self myView] removeFromSuperview];
} else {
[self.view addSubview:[self myView]];
}
}
Your if condition should go like
if (!([rootView subviews] containsObject:[self popoverView])) {
[rootView addSubview:[self popoverView]];
} else {
[[self popoverView] removeFromSuperview];
}
Here we used two different views. Parent view is the view in which we are searching for descendant view and check wether added to parent view or not.
if parentView.subviews.contains(descendantView) {
// descendant view added to the parent view.
}else{
// descendant view not added to the parent view.
}
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;
}
}