setting rightbarbuttonitem in navigation item to nil doesn't disappear - ios

I have an object with the class FSDDropdownPicker (a dropdown menu) and I want to edit one of the entries in my dropdown menu. Upon doing so I change the object to nil, and the right bar button item to nil yet the old dropdown menu remains even after instantiating the new dropdown and adding it to the right bar button item.
if(_picker){
// _picker.tableView.delegate = nil;
// _picker.tableView.dataSource = nil;
// _picker.delegate = nil;
self.navigationItem.rightBarButtonItem = nil;
// [_picker removeFromSuperview];
// _picker.view
}
_picker = [self.navigationItem addDropdownPickerWithOptions:[arr copy]];
_picker.delegate = self;
I also have functionality such that if the menu becomes empty then I erase the dropdown completely and just do
if([api.myGroups count]==0){
self.navigationItem.rightBarButtonItem = nil;
return;
}
However my rightBarButtonItem remains unchanged. Added Notes: I'm also using AMSlideMenu if that makes a difference but it really shouldn't.

Even after re-adding new picker, the FSDDropdownPicker keeps the old tableView still in the view hierarchy, so try calling [_picker removeFromSuperview]; before adding a new one.
Also there's no need to call [self.view setNeedsDisplay]; and nil the delegates and data source. Seems you just have to assign it again.
Additionally, the line self.navigationItem.rightBarButtonItem = _picker; is redundant as the category method addDropdownPickerWithOptions: on navigationItem already assigns the newly created picker to navigationItem.
EDIT: My bad, you need to call this code before creating new picker:
for (UIView *view in self.navigationController.navigationBar.superview.subviews) {
if ([view isKindOfClass:[UITableView class]]) {
[view removeFromSuperview];
}
}
Unfortunately the library doesn't take care of this by itself, so you either do it this way or create a pull request with a fix for the FSDDropdownPicker library.
EDIT EDIT:
If you're not using CocoaPods, you could try to put the table view and options definition in the header file - not a nice solution, but probably the easiest for you now. Move this
#property (strong, nonatomic) UITableView *tableView; and this #property (strong, nonatomic) NSArray *options; line to FSDDropdownPicker.h and you won't have to create new picker instance every time you want to add/delete an item. Just add/delete an item to options and reload the table view.

Related

Creating multiple Custom Views from XIB and adding them programmatically into ViewController

I will start off by describing what I'm trying to accomplish and then follow by describing what I've tried already. I am pretty sure what I've tried is NOT the best approach so please correct my approach as needed!
I have a ViewController.m and a Custom View which is laid out in CustomView.xib. The custom view has UIButtons and UILabels which are populated from an Array of Custom Objects.
The user flow should go as such: ViewController starts off showing CustomView with its labels populated by
CustomObjectArray[0] -> User presses button -> Another "copy" of CustomView slides into the view, over the previous version.
It's labels and buttons are populated by CustomObjectArray[1] -> User presses button -> repeat until end of Array.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So far I made a ViewController.m/h, a CustomView.m/h AND a CustomView.xib file. I used interface builder to do the layout.
On the "Custom Class" tab for the top-level View in XIB file, I type in "CustomView". I also drag IBOutlets from the XIB file to the CustomView HEADER (.h) file.
In the ViewController, under -(instancetype) init method, I create a custom view using the normal initWithNib method. And then I do:
self.view = CustomViewVariableName;
When I run the program, the view show's up fine. However, when I try to selector's, nothing's getting recognized by the buttons:
[currentCustomView.continueButton addTarget:self action:#selector(continueButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
What did I do wrong here?
More importantly, given my described goals up top, am I even doing this right? Do I need to have CustomView.m/h files? Or can I do the same thing with ONLY the XIB and the ViewController file. Remember that I need to have "multiple copies" and slide them on top of each other until the end of my custom objects array.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some more code as requested.
In ViewController:
- (instancetype)init
{
currentCustomView = [[[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:self options:nil] objectAtIndex:0];
self.view = currentQuizQuestionView;
.......
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[currentCustomView.continueButton addTarget:self action:#selector(continuePressed:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)continuePressed:(id)sender{
NSLog(#"Current position");
//[self moveInQuestion];
}
In CustomView.h:
#import <UIKit/UIKit.h>
#interface CustomView : UIView
#property (weak, nonatomic) IBOutlet UIButton *continueButton;
#end
In CustomView.m:
this is just the default page, I added nothing in this file.
CustomView.xib:
I'm not sure if I fully understand your requirements. Let's assume you would like to have several CustomViews as subviews of your ViewController and those subviews can be display each by each after pressing its own button.
First thing about adding subview:
self.view = CustomViewVariableName;
Since CustomsViews will be subviews according to my assumption, above line is an error. You probably would like to have something like this.
for (NSInteger i = 0; i < 5; i++) {
CustomView *v = [[CustomView alloc] initWithNib];
[v.button addTarget:self
action:#selector(continuePressed:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:v];
}
Second, I noticed you would like to have an array as a handler to refer all the subviews. We can add above CustomView into a mutable array by insert one more line into above for-loop.
[_customObjectArray addObject:v.button];
Finally, I created a simple project and tried to implement things you mentioned. Maybe you can take it for a reference. https://db.tt/Och2tzyG

iOS: Keeping a View constant or passing a view between various ViewControllers

I've got a custom library(devinross/tapkulibrary) which implements segmented controls. This segmented control is placed within a subview of main view. Now when I change the control on segmented controls then I change to new viewcontroller and redraw the segmented controls at exactly same place. But this is causing me some problems during animations in some cases.
Is it possible that I can assign the segmented control property of new view controller to current property and thereby using the same segmented over various view controllers.
// First.h
#property (weak, nonatomic) IBOutlet UIView *segmentedView;
#property (nonatomic, strong) TKMultiSwitch *multiswitch;
// First.m
- (void)viewDidLoad {
//multiSwitch initializations
[self.multiswitch addTarget:self action:#selector(changedSegmentedControl:) forControlEvents:UIControlEventValueChanged];
[self.segmentedView addSubview:self.multiswitch];
}
-(void) changedSegmentedControl:(id)sender {
switch(sender.indexOfSelectedItem)
{
case 1:
Second *controller = (Second*)[self.storyboard instantiateViewControllerWithIdentifier:#"secondvc"];
controller.multiswitch = self.multiswitch;
break;
}
}
// Second.h
#property (weak, nonatomic) IBOutlet UIView *segmentedView;
#property (nonatomic, strong) TKMultiSwitch *multiswitch;
// Second.m
- (void)viewDidLoad {
[self.multiswitch addTarget:self action:#selector(changedSegmentedControl:) forControlEvents:UIControlEventValueChanged];
[self.segmentedView addSubview:self.multiswitch];
}
-(void) changedSegmentedControl:(id)sender {
switch(sender.indexOfSelectedItem)
{
case 0:
First *controller = (First*)[self.storyboard instantiateViewControllerWithIdentifier:#"firstvc"];
controller.multiswitch = self.multiswitch;
break;
}
}
For case 1: in switch section of First.m file, I also tried following but out of luck:
[controller.segmentedView addSubView:self.multiSwitch];
Also note that I cannot use subviews and show them when segmented controls are changed. I've got to change view controllers.
EDIT : Video showing the what is working and what is not (Here 3 sections are there)
working: https://www.youtube.com/watch?v=lI368z9ntfM
problem: https://www.youtube.com/watch?v=oTU6tIq5ZW4
Ok, so I can't really understand some parts of how and why you want to do what you want to do.
From what I understood, you want to hide the 'First' controller and show the 'Second' controller instead, but in doing so, you don't want to release the 'multiswitch' control. I also assume you want to completely throw away 'First' and recreate it if necessary.
To be truthful, I don't really like your solution, but I also don't know a lot about what you are trying to do, so I will just try to give an answer based on the asumptions above.
Add the following lines before creating the Second controller, in changedSegmentedControl:.
// Remove 'self' as target. You don't want to receive signals in 'First' anymore, because once it will get released you will end up with a crash.
[self.multiswitch removeTarget:self action:#selector(changedSegmentedControl:) forControlEvents:UIControlEventValueChanged];
// Remove the segmented control from it's superview. It will be added in the 'Second' controller view hierarchy.
[self.multiswitch removeFromSuperview];
You are now set. You must also not forget to add 'Second' as target for the 'multiswitch' control.
In 'Second.m', method 'viewDidLoad', add :
[self.multiswitch addTarget:self action:#selector(changedSegmentedControl:) forControlEvents:UIControlEventValueChanged];
Of course, you must implement 'changedSegmentedControl:' in 'Second' as well.
You would be better off in reusing 'First' instead of 'Second' (Initiate a 'First' controller instead of 'Second' so that you already have the functionality for the 'multiswitch' control). If you need extra functionality, change 'Second' in order to inherit 'First' and add the extra code you need.

Issues with UINavigationItem changing properties at runtime

i have a Navigation Bar, wich contains a Navigation Item, which contains 2 Bar Buttons, these are created in the Storyboard, and i wanted to change 1 of the buttons at runtime, now this works:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UINavigationItem *thisNavBar = [self myNavigationItem];
thisNavBar.rightBarButtonItem = nil; // this works, it gets removed
UIBarButtonItem *insertBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(insertSkemaItem:)];
thisNavBar.rightBarButtonItem = insertBtn; // this also works, it sets the btn
}
Now, in my other method, which is called by another controller, it does not work
- (void)callChildChange {
...
// remove old btn
UINavigationItem *thisNavBar = [self skemaNavigationItem];
thisNavBar.rightBarButtonItem = nil; // does not work?
}
There is nothing wrong with the method, it runs just fine, but the nav btn item does not get removed ?
skemaNavigationItem is a Navigation item, declared in the .h file which links the navigation item i made via the storyboard.
Your UI items need to be added to your code (by ctrl-dragging) in the header file (.h) so they can be publicly accessed from other classes/view controllers.
Presuming you've done this, hiding a UI item is best done by using
relevantClass.yourViewObject.hidden = YES;
or if you really need to delete it for good,
[relevantClass.yourViewObject.view removeFromSuperView];
Edits
Options for changing target method:
Declare #property (nonatomic, assign) BOOL myButtonWasPressed; and:
- (IBAction) myButtonPressed
{
if (!self.myButtonWasPressed)
{
// This code will run the first time the button is pressed
self.myButton.text = #"New Button Text";
self.myButtonWasPressed = YES;
}
else
{
// This code will run after the first time your button is pressed
// You can even set your BOOL property back, and make it toggleable
}
}
or
- (IBAction) myButtonWasPressedFirstTime
{
// do what you need to when button is pressed then...
self.myButton.text = #"New Button Text";
[self.myButton removeTarget:self action:#selector(myButtonPressedFirstTime) forControlEvents:UIControlEventTouchUpInside];
[self.myButton addTarget:self action:#selector(myButtonPressedAgain) forControlEvents: UIControlEventTouchUpInside];
}
- (IBAction) myButtonWasPressedAgain
{
// this code will run the subsequent times your button is pressed
}

iOS - passing Sender (button) name to addSubview

I have a main view with 3 buttons. Clicking on any of the buttons adds a SubView.
The buttons have different titles and are all linked to IBAction "switchView"
The "switchView" code is below.
- (IBAction)switchView:(id)sender{
secondView *myViewController = [[secondView alloc] initWithNibName:#"secondView" bundle:nil];
[self.view addSubview:myViewController.view];
}
The "secondView" loads up correctly and everything works well.
The problem is I want to be able to know which button was the Sender.
I don't want to create 3 subviews, one for each button. The code and XIB would be absolutely the same>
The only difference would be a variable that I would like to set up in the second view (viewDidLoad method) depending on who is the Sender (which button was clicked)
Is this possible? Or I would need to create 3 subViews - one for each button?
Your help is greatly appreciated!
You can identify different buttons with the tag property.
e.g. with your method:
-(IBAction)switchView:(id)sender {
UIButton *button = (UIButton*)sender;
if (button.tag == 1) {
//TODO: Code here...
} else if (button.tag == 2) {
//TODO: Code here...
} else {
//TODO: Code here...
}
}
The tag property can be set via the InterfaceBuilder.
Hope this helps.
I think you can solve in 2 ways:
Create a property like:
#property (nonatomic, strong) IBOutlet UIButton *button1, *button2, *button3;
in your viewcontroller and link the buttons to them as referencing outlet on the XIB.
Give a different tag to each button on your xib and ask for the tag of the sender with UIButton *b=(UIButton*)sender; b.tag; like Markus posted in detail.
Solving my problem it all came down to transferring data between the mainView and subView.
In my mainView.h I declared an NSString and its #property
...
NSString *btnPressed;
}
#property(nonatomic, retain) NSString *btnPressed;
...
then in my mainView.m inside the switchView method I did this:
- (IBAction)switchView:(id)sender{
secondView *myViewController = [[secondView alloc] initWithNibName:#"secondView" bundle:nil];
btnPressed = [NSString stringWithFormat:#"%i", [sender tag]];
[myViewController setBtnPressed:self.btnPressed];
[self.view addSubview:myViewController.view];
}
This line in the code above actually takes care of transferring the data to the newly created subView:
[myViewController setBtnPressed:self.btnPressed];
Then in my secondView.h I declare exactly the same NSString *btnPressed and its #property (though this a completely different object than the one declared in main)
Then in my secondView.m I get the value of the button pressed I'm interested in.
- (void)viewDidLoad {
[super viewDidLoad];
int theValueOfTheButtonPressed = [self.btnPressed intValue];
}
This works well.
Don't forget to #synthesize btnPressed; as well as [btnPressed release]; in both mainView.m and secondView.m

How do I use If-Statements correctly?

I tried a few things myself, but couldnt really get the handle around it.
I wanna do two things:
First the user can press one of three buttons - They all link to the same ViewController, but when User Presses the first button three labels change accordingly in this second ViewController. And then the user can enter some data which will be displayed in the third view, also accordingly on which button was pressed in the first view.
I tried it with IF Statements, e.g. (IF ViewController.button1waspressed == True) and it didnt really work. I also tried it with tags e.g. (Button1.tag = 1)
Could someone give me a short example on how this could work?
FirstViewController.m
- (IBAction)switch:(id)sender;
{
SecondViewController *second =[[SecondViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
SecondViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
if (sender == self.button1) {
NSString *greeting = [[NSString alloc] initWithFormat:#"Randomtext"];
self.label.text = greeting;
}
}
The problem is obvious in this one, SecondViewController cant see the property from the first one. (And yes I imported the FirstViewController and vice versa)
Your buttons should all directly call IBActions (methods defined like so):
- (IBAction)doSomething:(id)sender;
Defining them as IBActions exposes them to be connected with the blue connection lines in interface builder. Once you've hooked them up and the method is being called, you can simply use an equality check on the sender parameter, which the calling button will automatically set as itself.
if (sender == self.myButton) {
// do something
}
Here I'm assuming that you've got a property called myButton in your ViewController, which would be an IBOutlet:
#property (nonatomic, retain) IBoutlet UIButton *myButton;
This exposes that property to be connected with the blue connection lines in interface builder, so your ViewController will know exactly which button you're talking about when you say myButton.

Resources