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.
Related
This looks like a bug to me, but maybe someone can think of a workaround?
Basically if you have a custom UIToolbar, its button items will automatically hide when you present a UIActivityViewController, and reappear when you dismiss it. This is only the case on the iPhone. Being that UIActivityViewController doesn't hide the entire screen it just looks weird that buttons disappear behind the dimmed screen.
To replicate, simply start a single view project and use the following code on the view controller:
- (void)viewDidLoad {
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 40)];
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(didTapAction)];
toolbar.items = [NSArray arrayWithObject:button];
[self.view addSubview:toolbar];
}
- (void)didTapAction {
NSArray *items = [NSArray arrayWithObjects:#"Text", nil];
UIActivityViewController *sharing = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
[self presentViewController:sharing animated:YES completion:nil];
}
Found a workaround. Simply get rid of all the items before presenting, and add them back right after.
- (void)didTapAction {
NSArray *items = [NSArray arrayWithObjects:#"Text", nil];
UIActivityViewController *sharing = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
NSArray *barItems = toolbar.items;
toolbar.items = nil;
[self.navigationController presentViewController:sharing animated:YES completion:nil];
toolbar.items = barItems;
}
know it is quite old thread for but those who look this page for solution, here you go :
With iOS7, you can use this approach to show/hide your toolbar button :
if(// your code Condition)
{ self.toolbarBtn1.enabled = YES;
self.toolbarBtn1.tintColor = nil; }
else
{ self.toolbarBtn1.enabled = NO;
self.toolbarBtn1.tintColor = [UIColor clearColor]; }
Why do I get a crash "Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]" after setting rightBarButtonItem?
In my app, I have three buttons on the right hand side, one of which should alternate with the systemEditButton. So I set the buttons up withrightBarButtonItems (note the "s") and then change the right-hand one using rightBarButtonItem when appropriate.
With 5.0, Apple lets you set multiple items in the leftBarButtonItems and rightBarButtonItems of a NavigationBar. It also says you can change the outer one with leftBarButtonItem and rightBarButtonItem respectively ("The first item in the array can also be set using the rightBarButtonItem property").
Works fine the first time, but then it crashes when I put back the original button. Even worse, it doesn't object when I set it, it crashes later during the animation of UINavigationBar layoutSubViews. Checking rightBarButtonItems after setting rightBarButtonItems shows it correctly updated the array, but it crashes during layout.
Well, I've confirmed this with a test program (see below), and submitted a bug-report to Apple. The workaround is to read the Items array and hand it back a new one with the zeroth element updated.
//
// ViewController.m
// testBarButton
//
// Created by Hugh Mackworth on 3/4/12.
// Copyright (c) 2012 PineTree Software. All rights reserved.
//
#import "ViewController.h"
//#import <UIKit/UIKit.h>
//
//#interface ViewController : UIViewController {
//
//#private
// UIBarButtonItem * itemA;
//}
//
//#property (strong, nonatomic) UIBarButtonItem * itemA;
//
//#end
#implementation ViewController
#synthesize itemA; //#property (strong, nonatomic) UIBarButtonItem * itemA;
-(void) reportButtons {
NSLog (#"buttons: %#",self.navigationItem.rightBarButtonItems);
}
-(void) itemA:(id) sender {
NSLog(#"itemA hit");
[self reportButtons];
}
-(void) itemB:(id) sender {
NSLog(#"itemB hit");
self.navigationItem.rightBarButtonItem = self.itemA;
[self reportButtons];
}
-(void) itemC:(id) sender {
NSLog(#"itemC hit");
self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self reportButtons];
}
-(void) loadView {
self.view = [[UIView alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
self.itemA = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Alternative Edit",#"")
style:UIBarButtonItemStyleBordered
target:self
action:#selector(itemA:)];
UIBarButtonItem *itemB = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"B-Hit Second",#"")
style:UIBarButtonItemStyleBordered
target:self
action:#selector(itemB:)]; //fix with itemB2:
UIBarButtonItem *itemC = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"C-Hit First",#"")
style:UIBarButtonItemStyleBordered
target:self
action:#selector(itemC:)]; //fix with itemC2:
NSArray *rightItems = [NSArray arrayWithObjects:
self.itemA,
itemB,
itemC,
nil];
self.navigationItem.rightBarButtonItems = rightItems;
[self reportButtons];
}
-(void) swapRightItem: (UIBarButtonItem *) newRightItem {
NSMutableArray * newRightItems = [self.navigationItem.rightBarButtonItems mutableCopy];
[newRightItems replaceObjectAtIndex:0 withObject: newRightItem];
self.navigationItem.rightBarButtonItems = newRightItems;
[self reportButtons];
}
-(void) itemB2:(id) sender {
NSLog(#"itemB2 hit");
[self swapRightItem:self.itemA];
}
-(void) itemC2:(id) sender {
NSLog(#"itemC2 hit");
[self swapRightItem:self.editButtonItem];
}
#end
//APP DELEGATE:
/*
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController * viewController = [[ViewController alloc] init];
UINavigationController *watchNavController= [[UINavigationController alloc] initWithRootViewController:viewController ];
self.window.rootViewController = watchNavController;
[self.window makeKeyAndVisible];
return YES;
}
*/
-(void)reloadView{
NSLog(#"IN RELOAD VIEW ");
[[self tableView] reloadData];
}
- (void)viewDidLoad {
UIBarButtonItem * barButton = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator];
[self navigationItem].rightBarButtonItem = barButton;
[activityIndicator startAnimating];
[self callStudentsWebService];
[super viewDidLoad];
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
[self setTitle:#"Students"];
self.navigationController.toolbarHidden = NO;
self.navigationController.toolbar.barStyle = UIBarStyleBlack;
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithTitle:#"Add Student" style:UIBarButtonItemStyleBordered target:self action:#selector(addStudent)];
UIBarButtonItem *flexible = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *import = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize target:self action:#selector(addStudent)];
NSArray* toolbarItems = [NSArray arrayWithObjects:add,flexible,import, nil];
self.toolbarItems = toolbarItems;
}
Above is my Code in a Class which is a subclass of UITableViewController.
Now my problem is when I come onto the screen First Time it get the records from web service from the method [self callStudentsWebService] . Now i have a button in uitoolbar in the same view which updates the list . I am calling the reloadView method to refresh the List but it calls the numberOfRowsInSection and viewDidLoad method but does not call cellForRowAtIndexPath method. But when i goto other screen and come back again it does refresh my List from start.
What could be the reason ?? Please help i am new in iPad Development. And i m doing all this in iPad.
Thanks alot
EDITED
#interface StudentsList : UITableViewController {
DetailViewController *detailViewController;
UIToolbar *toolbar;
UIActivityIndicatorView *activityIndicator;
}
May be your data.count is 0? If there is some data it should call cellForRowAtIndexPath after [[self tableView] reloadData];
Do the refresh code in another separate method -(void)refreshData then call this whenever you want such as in -viewDidLoad or on a button tap...
Try to call -(void)reloadView from
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self reloadView];
}
For the first time I'm subclassing UIToolbar for creating ones with custom UIBarButton.
I'm doing this:
#interface CustomToolbar : UIToolbar
#end
#implementation CustomToolbar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// add buttons
UIBarButtonItem *myButton = [[UIBarButtonItem alloc] initWithTitle:#"Button" style:UIBarButtonItemStyleBordered target:self action:#selector(pressSignupButton:)];
// add buttons to the array
NSArray *items = [NSArray arrayWithObjects:myButton, nil];
[self setItems:items];
}
return self;
}
#end
Then in my view controller:
CustomToolbar *myToolbar = [[CustomToolbar alloc] init];
[self.navigationController.view addSubview:myToolbar];
The problem is that I can see the toolbar but there aren't buttons. Why?
NB: I prefer to have all programmatically without nib.
Does this work?
CustomToolbar *myToolbar = [[CustomToolbar alloc]
initWithFrame:CGRectMake(0,0,self.navigationController.view.frame.size.width, 44)];
[self.navigationController.view addSubview:myToolbar];
I have a NavigationBar app with two views: a parent and a sub view. In the sub view I'm adding a button to the right corner as follows:
- (void)viewDidLoad {
UIBarButtonItem *tempButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"lock-unlocked.png"] style:UIBarButtonItemStylePlain target:self action:#selector(lockScreen)];
self.navigationItem.rightBarButtonItem = tempButton;
[tempButton release];
}
When that button is clicked I want to change the image of this rightBarButtonItem and disable the leftBarButtonItem (which was added automatically by the controller). Basically have two states of a button, locked and unlocked.
Question 1:
The only way I can find how to change the image is to create a new UIButtonItem with a new image and replace rightBarButtonItem with that new one. But I'm wondering if there's a way to just change the image without creating a new UIBarButtonItem. Am I creating a memory leak if I keep creating new UIBarButtonItem?
Question 2:
How can I get a hold of self.navigationItem.leftBarButtonItem and disable/enable it? I don't create that one manually, it's created automatically for me by the controller. I don't see any method/property on UIBarButtonItem to enable/disable user interaction with it.
Question 1: Declare UIBarButtonItem *tempButton in the interface
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIBarButtonItem *tempButton;
}
#property (nonatomic, retain) UIBarButtonItem *tempButton;
and synthesize it in the implementation.
#synthesize tempButton;
Create the object in viewDidLoad similiar to how you are now.
- (void)viewDidLoad {
tempButtom = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"lock-unlocked.png"] style:UIBarButtonItemStylePlain target:self action:#selector(lockScreen)];
self.navigationItem.rightBarButtonItem = tempButton;
}
But don't release it here, release it in the dealloc method normally found at the bottom.
Then when lockScreen is called do
tempButton.image = [UIImage imageNamed:#"myImage.png"]
I don't have an answer for question 2, im afraid!
In regard to question 2, use the 'enabled' property:
self.navigationItem.leftBarButtonItem.enabled = NO;
I can't understand if you have a navigationController, but in this case to disable the back button you need to call:
self.navigationItem.hidesBackButton = YES;
Shouldn't the above have release the UILabel *l after the [self.window addSubView:l] call? That way it gets retained +1 when added to the Subview, but released -1 in the same branch. Otherwise, you must call disableLeftBarButtonItemOnNavbar:NO to release it. And while, you'll end up in the same place in the end, you aren't leaking, I think the static analysis tools they've built into XCode wouldn't like that being in a separate branch. Small detail :-)
- (void) disableLeftBarButtonItemOnNavbar:(BOOL)disable
{
static UILabel *l = nil;
if (disable) {
if (l != nil)
return;
l = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 160, 44)];
l.backgroundColor = [UIColor clearColor];
l.userInteractionEnabled = YES;
[self.window addSubview:l];
[l release];
}
else {
if (l == nil)
return;
[l removeFromSuperview];
l = nil;
}
}
I was not able to disable/grey out a NavBar button with:
self.navigationItem.leftBarButtonItem.enabled = NO;
...but hiding the back button works well!
self.navigationItem.hidesBackButton = YES;
Thanks Dzamir!
Using "hidesBackButton=YES" is really not an elegant solution, cause it HIDES the button which is not what we want. An acceptable work-around would be adding a UILabel to the window just over the back button at least disabling the touches on the button.
Add this method to your AppDelegate class:
- (void) disableLeftBarButtonItemOnNavbar:(BOOL)disable
{
static UILabel *l = nil;
if (disable) {
if (l != nil)
return;
l = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 160, 44)];
l.backgroundColor = [UIColor clearColor];
l.userInteractionEnabled = YES;
[self.window addSubview:l];
}
else {
if (l == nil)
return;
[l removeFromSuperview];
[l release];
l = nil;
}
}
You can call it like this from any view controller to disable:
MyAppDelegate *appDeleg = (MyAppDelegate *) [[UIApplication sharedApplication] delegate];
[appDeleg disableLeftBarButtonItemOnNavbar:YES];
To enable:
MyAppDelegate *appDeleg = (MyAppDelegate *) [[UIApplication sharedApplication] delegate];
[appDeleg disableLeftBarButtonItemOnNavbar:NO];
I think this code helps you,
UIButton *m_objbtnFlip= [[UIButton alloc] initWithFrame:CGRectMake(0,0,89, 37)];
[m_objbtnFlip setBackgroundImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"btn_purchased"
ofType:IMAGETYPE]]
forState:UIControlStateNormal];
[m_objbtnFlip setBackgroundImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"btn_allavailable"
ofType:IMAGETYPE]]
forState:UIControlStateSelected];
[m_objbtnFlip addTarget:self action:#selector(flipViews) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *objBarButtonItemRight = [[UIBarButtonItem alloc] initWithCustomView:m_objbtnFlip];
self.navigationItem.rightBarButtonItem=objBarButtonItemRight;
[objBarButtonItemRight release];
objBarButtonItemRight = nil;
And write action here,
-(void)flipViews {
// put action code here
}