Trouble Displaying UIMenuController When Cell Tapped In UITableView - iphone

I'm trying to display a custom UIMenuController when a User long presses on a cell in a grouped UITableView. However, I can't seem to get the UIMenuController to display after successfully detecting the long press. Any help is greatly appreciated.
MyViewController.h
#interface MyViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>
UITableView *table;
#property (nonatomic, retain) IBOutlet UITableView *table;
#end
In the cellForRowAtIndexPath I attach my Long Press Gesture Recognizer
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:SectionsTableIdentifier] autorelease];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
[cell addGestureRecognizer:longPress];
[longPress release];
Here is my handleLongPress action method
-(void)handleLongPress:(UIGestureRecognizer *)longPress {
if (longPress.state == UIGestureRecognizerStateBegan) {
CGPoint pressLocation = [longPress locationInView:self.table];
NSIndexPath *pressedIndexPath = [self.table indexPathForRowAtPoint:pressLocation];
UIMenuItem *first = [[UIMenuItem alloc] initWithTitle:#"Save" action:#selector(saveRecent)];
UIMenuItem *second = [[UIMenuItem alloc] initWithTitle:#"Edit" action:#selector(editQuery)];
UIMenuController *menuController = [UIMenuController sharedMenuController];
menuController.menuItems = [NSArray arrayWithObjects:first,second,nil];
[menuController setTargetRect:longPress.view.frame inView:longPress.view.superview];
[menuController setMenuVisible:YES animated:YES];
[pressedIndexPath release];
}
}
The Action methods for the Edit and Save just display a UIAlertView. I also implemented the below method to ensure that when the UIMenuController is displayed only Save and Edit options will be present
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
BOOL canPerform = NO;
if (action == #selector(saveRecent)) {
canPerform = YES;
}
if (action == #selector(editQuery)) {
canPerform = YES;
}
return canPerform;
}
I'm also claiming MyViewController to be first responder
-(BOOL)canBecomeFirstResponder {
return YES;
}

I believe you need to have a view claiming firstResponder status in order to present the UIMenuController. I don't see that happening in your code.
I wrote up directions for using the UIMenuController as an answer to this question:
Customize UIMenuController

Related

UIImagePickerController startVideoCapture with custom overlay

I am using UIImagePickerController with a custom overlay to record a video in my app. For the implementation of the UIImagePickerController, I have used the code from a great Ray Wenderlich tutorial.
I have hidden the controls for the camera, and created a simple custom overlay view. This has worked and loads fine.
I have then created a toolbar and buttons for the view, to record the video:
- (BOOL) startCameraControllerFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
// Displays a control that allows the user to choose movie capture
cameraUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
cameraUI.allowsEditing = NO;
cameraUI.delegate = delegate;
//Overlay view and toolbar setup
// creating overlayView
UIView* overlayView = [[UIView alloc] initWithFrame:cameraUI.view.frame];
// letting png transparency be
float width = 320;
float AR = (4.0/3.0);
float toolbar_height = 480 - (AR*width);
UIToolbar *toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, (AR*width), 320, toolbar_height)];
//toolBar.tintColor = [UIColor colorWithRed:(252/255.) green:(0/255.) blue:(48/255.) alpha:1];
toolBar.tintColor = [UIColor colorWithRed:(49/255.) green:(52/255.) blue:(49/255.) alpha:1];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *RecordBarButtonItem = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:#selector(recordPressed:)];
UIBarButtonItem *CancelBarButtonItem = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(imagePickerControllerDidCancel:)];
NSArray *buttons = [NSArray arrayWithObjects: CancelBarButtonItem, flexibleSpace, RecordBarButtonItem, flexibleSpace, nil];
[toolBar setItems: buttons animated:NO];
[overlayView addSubview:toolBar];
[overlayView.layer setOpaque:NO];
overlayView.opaque = NO;
cameraUI.showsCameraControls = NO;
cameraUI.cameraOverlayView = overlayView;
[controller presentViewController: cameraUI animated: YES completion:nil];
return YES;
}
My button recordBarButtonItem calls recordPressed which is given by:
- (void) recordPressed: (UIImagePickerController *) picker {
NSLog(#"lets record");
[picker startVideoCapture];
}
So the 'lets record' appears on the log, but I receive an NSInvalidArgumentException error for the startVideoCapture. I know theres something obviously wrong with the way im trying to start the video capture through the button press, but I cant figure it out. Still quite a novice at iOS so forgive me if the solution is simple!
Cheers,
Mike
The problem is that the action you attach to the initWithBarButtonSystemItem call doesn't pass the UIImagePickerController instance along.
What I would do is set the UIImagePickerController as a property of your class and access that property from your action, like this:
In your .h:
#property (nonatomic, strong) UIImagePickerController *cameraUI;
In your .m:
- (BOOL) startCameraControllerFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
...
self.cameraUI = [[UIImagePickerController alloc] init];
...
UIBarButtonItem *RecordBarButtonItem = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:#selector(recordPressed)]; // Removed the ':'
...
}
- (void) recordPressed {
NSLog(#"lets record");
[self.cameraUI startVideoCapture];
}
Actually I've just quickly tested it in some code I've gotten open, the sender for your action on the button press is UIBarButtonItem *. So there's a couple of things you can do, you can either go down the root of
UIBarButtonItem *senderButton = (UIBarButtonItem *)sender;
if(senderButton.image == UIBarButtonSystemItemCamera)
{
//Handle behaviour
}
Or set the tag variable for each button and skip the image check and look at the tags instead, which might make the logic a bit easier.

Odd behavior UIActionSheet + UITableView: rows disappear

I've a UITableView with some static cells in it. One of them shows a UIActionSheet when touched. Here goes the code for it:
viewDidLoad: initialize controls.
- (void)viewDidLoad
{
[super viewDidLoad];
[self initializeControls];
}
initializeControls: add gesture recognizer to the label within the cell in order to show the UIActionSheet.
- (void)initializeControls {
[...]
// Places Label
self.placeNamesLabel.userInteractionEnabled = YES;
tapGesture = \
[[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(didPlaceNamesLabelWithGesture:)];
[self.placeNamesLabel addGestureRecognizer:tapGesture];
tapGesture = nil;
[...]
}
didPlaceNamesLabelWithGesture: initialize UIActionSheet, add a UITableView from StoryBoard and a Close button.
- (void)didPlaceNamesLabelWithGesture:(UITapGestureRecognizer *)tapGesture
{
// Show UITableView in UIActionView for selecting Place objects.
placesActionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:nil
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
[placesActionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
CGRect tableFrame = CGRectMake(0, 40, 0, 0);
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
AddArticlesPlacesViewController *placesView = [storyBoard instantiateViewControllerWithIdentifier:#"PlacesForArticle"];
placesView.managedObjectContext = self.managedObjectContext;
placesView.view.frame = tableFrame;
[placesActionSheet addSubview:placesView.view];
placesView = nil;
UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:#"Close"]];
closeButton.momentary = YES;
closeButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);
closeButton.segmentedControlStyle = UISegmentedControlStyleBar;
closeButton.tintColor = [UIColor blackColor];
[closeButton addTarget:self action:#selector(dismissPlacesActionSheet:) forControlEvents:UIControlEventValueChanged];
[placesActionSheet addSubview:closeButton];
closeButton = nil;
[placesActionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
[placesActionSheet setBounds:CGRectMake(0, 0, 320, 485)];
}
dismissPlacesActionSheet: close UIActionSheet.
-(void)dismissPlacesActionSheet:(id)sender {
[placesActionSheet dismissWithClickedButtonIndex:0 animated:YES]; }
Everything works and the UITableView populates fine from Core Data. So where is the problem? The point is that when any row is tapped, the entire table gets empty (I can't post images yet, sorry).
I've tried to add a new custom row with a button that fires a push segue to the AddArticlesPlacesViewController; this works fine and the behavior is as expected. So the problem is between UIActionSheet and UITableView.
Here are the interfaces for both view controllers:
Main.
#interface AddArticleViewController : UITableViewController <NSFetchedResultsControllerDelegate, [...]>
[...]
#property (weak, nonatomic) IBOutlet UILabel *placeNamesLabel;
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
[...]
#end
Secondary.
#interface AddArticlesPlacesViewController : UITableViewController <NSFetchedResultsControllerDelegate>
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#end
I'm stuck. What am I doing wrong?
Regards.
Pedro Ventura.
you can use tableview's delegate method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
NSLog(#"indexpath-->%d",indexPath.row);
if (indexPath.row==0 || indexPath.row == 2 )
{
NSLog(#"row %d",indexPath.row);
}
if (indexPath.row==1)
{
actionsheet=[[UIActionSheet alloc]initWithTitle:#"Sample" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil, nil];
[actionsheet showInView:self.view];
}
}
And you can use UIActionsheetDelegate's method for Selected Button:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(#"index==>%d",buttonIndex);
NSLog(#"cancel");
}

Hide UIPickerview On Done Button in UITableView

I have UITextField in each Cell of UITableview and I have added UIPickerview as inputView of UITextField and showing with Done button at its tool bar
My question is how can I hide this this pop up (Picker + toolbar) on click of done button ?
and show selected value of picker in text box in particular cell ?
Thanks and Regards
Edit : Code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
PremiumProductsDescriptionCell *cell = (PremiumProductsDescriptionCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[PremiumProductsDescriptionCell alloc] initShoppingCartCellWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
ShopProduct *p = (ShopProduct *)[[ShopProduct GetShoppingCart] objectAtIndex:indexPath.row];
cell.Quantity.text = [NSString stringWithFormat:#"%d",p.Quantity];
UIPickerView *quantityPicker = [[UIPickerView alloc] init];
quantityPicker.dataSource = self;
quantityPicker.delegate = self;
UIToolbar *myToolbar = [[UIToolbar alloc] initWithFrame:
CGRectMake(0,0, 320, 44)];
UIBarButtonItem *doneButton =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:#selector(hideKeyBoard)];
quantityPicker.tag = indexPath.row;
[myToolbar setItems:[NSArray arrayWithObject: doneButton] animated:NO];
cell.Quantity.inputAccessoryView = myToolbar;
cell.Quantity.inputView = quantityPicker;
cell.Quantity.delegate = self;
return cell;
}
Solved :
I have taken currentTextBox a variable and added following method and resizing its first responder in done button's click :)
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
currentTextBox = textField;
}
UIPopOver cant be dismissed from their class and you need to dismiss it from the calling class.
You have to call dismiss method from popover calling class, when user presses the done button
-(void)doneButtonClikd
{ ParentClass *viewController=[ParentClass alloc]init];
[viewController dismissPopOver];
}
I think this will solve your problem
For your inputview-
-(void)doneButtonclikd
{ [selectedTextfield resignFirstResponder];
}
Dont forget to save the currently selected textfield.
Assuming you put the UIPickerView in a popover, here's how to do it:
UIPopoverController* popover = ....
UIBarButtonItem* doneButton = ....
[doneButton addTarget:self action:#selector(closeMe)
forControlEvents:UIControlEventTouchUpInside]
// ....
- (void)closeMe
{
// Assuming popover is really a field or something...
[popover dismissPopoverAnimated:YES];
}
Use [self.view endEditing:YES] method.

UIMenuController Custom Items

I have created a UIMenuController and have set it a custom menu item like so:
UIMenuController *menuController = [UIMenuController sharedMenuController];
UIMenuItem *item1 = [[UIMenuItem alloc] initWithTitle:#"Do This" action:#selector(item1)];
[menuController setMenuItems:[NSArray arrayWithObject:item1]];
But I wanted that object to be the only one to appear so I added this code:
- (BOOL)canPerformAction: (SEL)action withSender: (id)sender {
BOOL answer = NO;
if (action == #selector(item1))
answer = YES;
return answer;
}
The problem is it still shows other## Heading ## items, such as "Select", "Select All" and "Paste".
This may have something to do with this being displayed in a UITextView.
But how do I stop if from displaying all other items?
I think this is one of the few cases where you want to subclass UITextView. I just tried this with the following code, and the only menu item that is shown is my Do Something item.
From my TestViewController.m
#implementation TestViewController
- (void) doSomething: (id) sender
{
NSLog(#"Doing something");
}
- (void) viewDidLoad
{
UIMenuController *menuController = [UIMenuController sharedMenuController];
UIMenuItem *item = [[[UIMenuItem alloc] initWithTitle: #"Do Something"
action: #selector(doSomething:)] autorelease];
[menuController setMenuItems: [NSArray arrayWithObject: item]];
}
#end
Code for my MyTextView.h:
// MyTextView.h
#import <UIKit/UIKit.h>
#interface MyTextView :UITextView {
}
#end
Code for MyTextView.m:
// MyTextView.m
#import "MyTextView.h"
#implementation MyTextView
- (BOOL) canPerformAction:(SEL)action withSender:(id)sender
{
return NO;
}
#end

MKMapView Annotation Callout Button to DetailView?

I have annotations in a MKMapView with Callouts. In this Callouts there's a "Right-Arrow" Button. When clicking on it, I want to open a Detail View, an extra UIViewController with its own nib file etc. I use following code:
In my MapViewController:
- (void)showDetails:(id)sender {
// the detail view does not want a toolbar so hide it
[self.navigationController setToolbarHidden:YES animated:NO];
NSLog(#"pressed!");
[self.navigationController pushViewController:self.detailViewController animated:YES];
NSLog(#"pressed --- 2!");
}
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(Annotation *) annotation {
if(annotation == map.userLocation) return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
customPinView.pinColor = MKPinAnnotationColorRed;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
UIImageView *memorialIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"googlemaps_pin.png"]];
customPinView.leftCalloutAccessoryView = memorialIcon;
[memorialIcon release];
return customPinView;
}
The button works, because when I give a NSLog inside the showDetais method, it's printed to the console. The problem is, that NOTHING happens. When clicking the button, it's like there isn't any button. There's no debug error or exception, just nothing.
the MapView header looks something like this:
#interface MapViewController : UIViewController <MKMapViewDelegate> {
MKMapView *map;
NSMutableDictionary *dictionary;
EntryDetailController *detailViewController;
}
#property (nonatomic,retain) IBOutlet MKMapView *map;
#property (nonatomic,retain) IBOutlet EntryDetailController *detailViewController;
Maybe someone of you can help me :)
Thanks!
Check if you have navigation controller for your viewController, if it is just a viewController then it cannot push a viewController because it does not have navigation controller in it.
I've had the same problem in the past and so I just used a different code to switch views:
-(IBAction)showDetails:(id)sender
{
NSLog(#"button clicked");
MapViewController *thisMap = (MapViewController *)[[UIApplication sharedApplication] delegate];
detailViewController *detailView = [[detailViewController alloc]initWithNibName:#"detailViewController" bundle:nil];
[thisMap switchViews:self.view toView:dvc.view];
}
It's a pretty basic view switching method and it works fine for me.
Isn't detailViewController uninitialized? You don't show all your code but I believe you might have things a bit jumbled up preparing the view and pushing it.
Why are you declaring the detailViewController as an IBOUTlet?
Also, I think you might want/intend to do this on your detailViewController not in this controller:
[self.navigationController setToolbarHidden:YES animated:NO];
You don't show all your code. But i guess, you just forget to initialise self.detailViewController.
try to add this in your viewDidLoad method:
self.detailViewController = [[[DetailViewController alloc]init]autorelease];