Hide the NSDatePicker with NSClickGestureRecognizer - objective-c

I am developing an app in Objective-C with Cocoa.
I have an NSDatePicker in my app, which I would like to hide after clicking anywhere in the application.
I have:
NSView *mainView - main NSView containing all application elements.
NSDatePicker *datePicker - picker which I would like to hide.
And I am trying to do it this way:
NSClickGestureRecognizer *click = [[NSClickGestureRecognizer alloc] initWithTarget: self action:#selector(hideCalendar:)];
[mainView addGestureRecognizer: click];
...
-(void) hideCalendar:(NSGestureRecognizer*)rec{
[datePicker setHidden:YES];
}
I know there can be only one NSGestureRecognizer of the each type and every element in mainView stops working as it should. So is there a way to call original action of NSClickGestureRecognizer in the hideCalendar: function?
I also tried implement my own NSGestureRecognizer. But to be honest, I don't really know which functions to implement.
How should I hide the datePicker when I click somewhere outside of it while preserving the original behaviour of the rest of the view elements?
Best regards!

Related

Objective C / UIBackBarButtonItem Why can't change view

I've ran into an interesting and strange question while messing around with a project.
After spending like 3 hours doing it, I found out you can't change the view of the UIBackBarButtonItem, only the UILeftBarButtonItem, so if I want to implement a custom back button, I hide the UIBackButtonItem and display a UILeftBarButtonItem which does the popping.
Now I find it odd, that you can't change the UIBackBarButtonItem's view, but you can change the UILeftBarButtonItem and the UIRightBarButtonItem's views.
Can someone explain me why would Apple do this?
Actually, you can. Use UIBarButtonItem's instance method setBackButtonBackgroundImage:forState:barMetrics:.
So if you want to change the background image for all your back buttons, your code should like something like:
UIImage *backButtonBgImageNormal = [[UIImage imageNamed:#"back_button_bg.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(5, 15, 5, 5);];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonBgImageNormal forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
Use delegate method of UINavigationController, such like
#pragma mark -
#pragma mark - UINavigationController Delegate Methods
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
//// customize you own stuff here;
UINavigationBar *morenavbar = navigationController.navigationBar;
UINavigationItem *morenavitem = morenavbar.topItem;
morenavitem.rightBarButtonItem.tintColor = [UIColor blackColor];
}
I think I have a comprehensive solution for you.
1) From experience, it's just best to not bow to limitations of BarButtonItems. I suggest you create a simple UIButton, customise it to your liking. maybe add an action to its touch events..brand it with custom background and title colors...etc.. keep a reference to this button, maybe as a property.
2) Then, you create an instance of UIBarButtonItem using the UIBarButtonItem initializer -initWithCustomView, you sneak in the UIButton instance as this custom view in the init and have complete control over it.
3) Finally, you just do this.
self.navigationItem.LeftBarButtonItems = #[ourUIBarButtonItem].
The navigation bar has an Array property "leftBarButtonItems" for series of left buttons, and rightBarbuttonItems for the right side. Just replace this with your own array, containing the UIbarButtonItem, that containing your button, and you having a reference to your button.
And now you can completely control you button that is properly in the navigation bar.
NOTE! - Once you provide such a leftBarButtonItem, the stock Apple BackButton is gone.

dynamically generated ui bar button needs to push to popover using segue

zThis is based on a question I asked here which I have made good progressed already:
custom uitableviewcell will not display label texts
I basically followed the tutorial that was provided for me.
http://brianflove.com/2012/12/10/how-to-create-an-ipad-popover-view/
QUESTION
Now my issue is, I have to dynamically generate my ui bar buttons as if I just drag and drop it on the storyboard I am limited to one on the left and one on the right. This is my code to generate my button
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithTitle:#"Button" style:UIBarButtonItemStyleBordered target:self action:#selector(getMenu:)];
self.navigationItem.leftBarButtonItems = [[NSArray alloc] initWithObjects:btn, nil];
}
Based on that tutorial I need to use a segue to popover the uitableview that I need. But that will require me to have an anchor point like so
So my question is, how do I add an anchor point to that UIBarButtonItem? I've been searching and I keep finding something regarding creating a custom popover class? Is this accurate?
I solved this issue by creating an invisible UIView on the Navigation Bar itself and then use that as the anchor point for the segue. The issue with that is the "arrow" of the popover when the uiviewcontroller gets displayed is awkwardly placed. Still trying to figure that out.
This is where I got the answer from
https://stackoverflow.com/a/14514837/639713

Instant / Autosave in IOS

For background: I'm a Windows automation and data translation "expert" (or so they say grins) in my day job. I've been dabbling with Objective-C coding off and on since I bought my first Mac in 2004.
I'm working on an IOS app. My data container class knows how to save and load from disc, and each object responds to an instance method of -(void)saveToImpliedFilename{} or -(void)save:(NSString *)filename {}. There's a static call to load the data files from storage and create distinct data objects from them (they're fairly lightweight objects, so I'm not worried about loading several at a time). The app's domain is such that many of them won't ever be loaded at once anyway.
+(NSArray *)loadData {}
That's all working fine and wonderful. In storage the objects are stored as Xml and life is good.
Where I'm having trouble is when trying to modify the tutorials so that two things happen for me:
Quick note: I'm using the tutorial as a basis for POC coding, then I'll go back and start over with the "real" coding, reusing my data objects and some of the other utility I've built along the way.
Here's my list of goals and the issues:
I want the table view to tell the data objects to save at pretty much every "edit" event. The only one I can consistently get to work is reorganizing the table's order. (the save button and adding a new entry works fine)
entering a new entry into the list creates a nice modal editor with a save and a cancel button which work wonderfully. But if I edit an existing entry, I can't reproduce the save buttons' behaviors. Each time I try, the buttons' events no longer fire. I can't figure out where I'm going wrong.
I'm using the "Editable Table View" project from this tutorial series as my basis: http://www.aboutobjects.com/community/iphone_development_tutorial/tutorial.html
In the following code, the [self isModal] test is where the save/cancel buttons are made visible and wired up. Bringing up the new-entry screen is apparently the only time it's modal. I tried wiring this stuff up so that the buttons were created all the time, but again, the events never fire for either one. The next block below is where the editable table view is called explicitly with the NEW functionality, but the nonModal view of the same tableview is called by the select event on the selector table.
So...
// code snipped for the new/modal editor
- (void)viewDidLoad {
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
// If the user clicked the '+' button in the list view, we're
// creating a new entry rather than modifying an existing one, so
// we're in a modal nav controller. Modal nav controllers don't add
// a back button to the nav bar; instead we'll add Save and
// Cancel buttons.
//
if ([self isModal]) {
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self
action:#selector(save)];
[[self navigationItem] setRightBarButtonItem:saveButton];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(cancel)];
[[self navigationItem] setLeftBarButtonItem:cancelButton];
}
// do stuff here to display my object...
}
// this code is called from the selection table to explicitly add a new data object.
- (void)add {
vhAddVehicleViewController *controller = [[vhAddVehicleViewController alloc] initWithStyle:UITableViewStyleGrouped];
id vehicle = [[Vehicle alloc] init];
[controller setVehicle:vehicle];
[controller setListcontroller:self];
UINavigationController *newNavController = [[UINavigationController alloc] initWithRootViewController:controller];
[[self navigationController] presentViewController:newNavController animated:YES completion:nil];
}
// this is where it's called on the table selection to show the same view without the save/cancel buttons.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
vhAddVehicleViewController *controller = [[vhAddVehicleViewController alloc] initWithStyle:UITableViewStyleGrouped];
NSUInteger index = [indexPath row];
id vehicle = [[self vehicles] objectAtIndex:index];
[controller setVehicle:vehicle];
[controller setTitle:[vehicle Vehiclename]];
[[self navigationController] pushViewController:controller animated:YES];
}
I'm assuming the issue is that presenting it makes it modal, where as pushing it doesn't...? That's fine. But when I take out the test for modal to try to keep the buttons working, no joy. The buttons draw and click when tapped, but the events don't fire.
HALP! :-)
Thanks much.
-- Chris (I logged in with my Google account so at the top of the page I'm showing as "user1820796") shrug
You forgot to call [super viewDidLoad];
Update
Try removing the cancel button that goes on the left side when pushing the view controller. See if save starts working. I think the problem is you should not add a left button to the navigation bar when the view controller is pushed.
Which method signature are you using?
- (void)save
{
NSLog(#"Saving");
}
Or
- (void)save:(id)sender
{
NSLog(#"Saving");
}
I still think this was related to push/popping the view rather than presenting the view. I switched it all to presentation and it's working how I want now.
Thanks for the assistance guys. Quite a different paradigm than I'm used to on the GUI stuff, but I'm getting there.
thanks!

Menu Accessible Throughout My App - How do I code this?

I have an app that's pretty much a large presentation of a companies product.
I have some additional functionality which I need to be accessible throughout my app.
The intended functionality for this toolbar is that it'll sit as a small, subtle tab along the bottom of the screen. When you tap the tab, the menu will expand upward (i.e. animate it's frame.y property), allowing you to tap any of the buttons contained within the menu.
The difficulty I'm having is that the app currently spans over several view controllers, and as I need this accessible throughout, in the interest of not duplicating code it would seem appropriate to make this ViewController also, that I would just load into my other view controllers, but this, by all accounts isn't recommended by Apple.
How can I build this menu functionality without duplicating code? I've tried a few things but cannot get the menu to display on my view.
Below, I'll show what I have at the moment.
Code that will sit on any view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
ToolboxMenu *toolboxMenu = [[ToolboxMenu alloc] init];
[self.view addSubview:toolboxMenu.view];
}
Code that builds the toolbar:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Creating View");
self.view = [[UIView alloc] initWithFrame:CGRectMake(0,0,88,209)];
self.view.backgroundColor = [UIColor clearColor];
UIImageView *toolboxImage = [[UIImageView alloc] initWithImage:[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"popup_toolbox" ofType:#"jpg"]]];
toolboxImage.frame = self.view.frame;
[self.view addSubview:toolboxImage];
}
In the above code, the NSLog fires when the menu is initialised, but I see no menu.
Rather than try to inject this into every view, I would recommend creating a separate UIWindow and float it over the main UIWindow. This is how the keyboard is implemented. Doing it that way will avoid any changes to any of the existing views. You will need to handle device rotation by hand for it, but that shouldn't be too difficult.
IIRC Apple's TabViewController was designed differently in that it's backwards to how you describe above. A TabViewController is the main or master ViewController with siblings being the display ViewControlers. Basically you have one TabViewController that will tab between views.
I would recommend you either redesign your view hierarchy OR extend UIViewController with a class that manages and displays the lower tab menu. Then you can easily init a single class that handles that in each of your views.

How do I add a navigation bar's Done button to a popover's passthroughViews?

I'm working in an iPad app that has a split view with a navigation controller in the detail view. The deepest view that can be in the navigation stack is an edit view where the user can edit data. I put an edit button as the rightBarButtonItem and when editing starts, change it to a done button.
When editing commences and the user touches on a particular field, I present a popoverview with a list of possible choices filtered by what they are typing - a form of autofill based on all the values of that field in all other objects.
This works fine, except if you try touching on the done button. The popover eats this touch and dismisses itself. So the user has to touch done again.
I tried using the uipopovercontroller's passthroughViews property, but UIBarButtonItem is not a view and there is no documented way to get the view for the done button or even the navigation bar. I can access the variable in gdb, but it isn't accessible via KVC.
Any ideas on how I can prevent the need to tap done twice?
I've thought about a gesture recognizer on the window, but that seems messy and I'd have to handle rotation.
In case anyone gets here from google, copypaste from other question:
The only solution I found for now is to create UIBarButtonItem with custom UIButton using
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
//code for styling button
UIBarButtonItem *b = [[[UIBarButtonItem alloc]
initWithCustomView:button]
autorelease]
and then
popoverController.passthroughViews = [NSArray arrayWithObject:b.customView];
But be prepared - you cannot create UIButton that looks like UIBarButtoItem. I ended up with creating image that reassembled UIBarButtonItem.