Replace or extend UIBarButtonItem selector - iphone

I'm trying to make a custom UIToolbar which handles rotation and custom arrangement. When it's in portrait mode some of the barbuttonitems will not be visible, so I add a "more" button from which pops up a little view with these items. My problem is that when my current orientation is portrait and when I select a visible barbuttonitem ( which is not in popup ) I want to close the popup if it's open. I want the smae behavior for the uibarbuttons in the popupview to close the popup after tap.
So I'm trying to replace somehow the UIBarButtonItem's selector with my own, in which I call the already defined actions, like this :
-(SEL)extendOriginal:(UIBarButtonItem *) uibb
{
if (popup) popup.hidden = YES;
[uibb.target performSelector:uibb.action];
// return ?? do what ??
}
But how do I replace the original selector to call this custom method with my custom UIToolbar as its target ? Or how could I "extend" the original selector with this call ? Sorry if question is lame :)
Edit: In other words, I want 2 actions with 2 separate targets to be executed when UIBarButtonItem is tapped.
Thanks!

This -(SEL)extendOriginal:(UIBarButtonItem *) uibb doesn't make any sense.
I assume your are setting the target and the action of the bar button item somewhere. There you can set any method with one argument id or UIBarButtonItem* as the selector.
Therefore try to change your code to
- (void)myMethod:(UIBarButtonItem *) uibb
{
if (popup) popup.hidden = YES;
// do cool stuff here
}
and set the target as
[[UIBarButtonItem alloc] initWithTitle: #"Blabla" style: UIBarButtonItemStylePlain target: self action: #selector(myMethod:)];

Finally, I found a way to do it, not the prettiest, but it works.
In the custom toolbar class I created in its layout method a UITapGestureRecognizer to handle taps. I've set the cancelsTouchesInView to false and in the
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
method I'm returning true only for my toolbar's subviews.
This way the original target and action of each UIBarButtonItem remains the same and the supplementary code to handle my popup is the action of the UIGestureRecognizer.
Another problem was to distinguish between the tapped items on the toolbar (the tapped view in touch.view is some undocumented view, yay), eventually I did it with some BOOL iVars.
I hope this will help somebody with the same problem.

Related

iOS Determine button that was programmatically created

I have made a horizontal scroll view with images and buttons in it using a for loop, what i want to do now is when a button is pressed, open the image it corresponds to full screen. The issue im having is determining which button has been pushed. I am using :
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
then :
-(void)buttonPressed:(UIButton *)sender {}
What can i do to fix this? Thanks
Which button has been pushed
Create a property to store a tag. In the buttonPressed method set the property to sender.tag
Now you can know which was the button who got pressed last.
The sender is the button that the user has tapped, so when you create the buttons you could use the tag property and set it to an index of an array where you hold your images. But this could be a bit unstable if you change the order or amount of images or buttons for example so be prepared to check for that.
one way to do so is to keep references of your button (with a property, an attribute in your class) and test if it is the good one in your buttonPressed method
- (void)buttonPressed:(UIButton *)sender {
if (sender == self.myButton) {
// DO YOUR WORK HERE
}
}
you can also create a method for this and only this one button
by the way it is better to say
- (IBAction)buttonPressed:(UIButton *)sender
you then can set the target of your button in the interface builder interface
set tag for each button in the for loop but.tag=i;
-(void)buttonPressed:(UIButton *)sender {
if (sender.tag==1){
//display image 1
}
else if ....
}

Removing cancel button in UIImagePickerController?

I am developing an app for ios 5.
I need to remove the cancel button on UIImagePickerController i searched for this problem on the forum but didnt get exact answer can someone please help me with this?
That is because it is not possible to remove that cancel button. That is an inbuilt function and you can not make changes in the same.
Swift Version, compatible 4+
To remove the navigation bar :
imagePicker.view.subviews
.filter { $0.isKind(of: UINavigationBar) }
.forEach { $0.isHidden = true }
for removing the buttons only :
imagePicker.view.subviews
.filter { $0.isKind(of: UIButton) }
.forEach { $0.isHidden = true }
VoilĂ 
I will give the best method to achieve this:
First create a subclass of the UiImagePickerController
in the subclass respond to the UINavigationBarDelegate method
- (BOOL)navigationBar:(UINavigationBar *)navigationBar
shouldPushItem:(UINavigationItem *)item
you dont have to do anything like setting the delegate or adding a protocol, just override the method inside your custom UIImagePcikerController.
in this method return NO for the cancel item (which is the first one)
I did this with ELCImagePickerController
There isn't a way to remove only the cancel button. UIImagePickerController exposes a property called showCameraControls, which will hide the bottom bar with the cancel button and the camera button, as well as the controls for flash, HDR, and flip camera, giving you just the camera preview.
If you want to provide an experience without a cancel button, you'll have to create a camera overlay view of what you want.
Assuming you have code invoking UIImagePickerController, you can turn off camera controls like this:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setShowsCameraControls:NO];
Assuming you'll overlay it with your own view without the cancel button, you'll add this (assuming you have a UIView called cameraOverlay:
[imagePicker setCameraOverlayView:cameraOverlay];
This will hide Navigationbar itself along with the Cancel and Title
let videoPicker = UIImagePickerController()
for view in videoPicker.view.subviews {
if let navBar = view as? UINavigationBar {
navBar.isHidden = true
}
}
If you want to remove the cancel button alone, dig deep into navBar
When you present the UIImagePickerView try puting the below code
for (UIView *subview in view.subviews) {
NSLog(#"subviews=%#",subview);
NSString *className = [NSString stringWithFormat:#"%#", [subview class]];
}
By the above code you can get the navigation controller used for displaying the cancel button.. Once you get the navigationController Set its leftside button to nil..
I have not used it but hope it can be of help to you

iPhone iOS 4 UIButton toggle highlighted state on and off

I got a UIButton with style "Info Dark" set up in interface builder in my iPhone 4 app. One of the properties of the button is "Highlighted", which displays a white highlight around the button.
I would like to toggle this white highlight on and off, indicating if the button function is active or not.
The button is linked for "Touch up inside" event in the interface builder with this callback:
infoButton.highlighted = !infoButton.highlighted;
After the first touch, the highlight disappears and does not toggle as I expect it to. What else do I need to do to make the highlight toggle and display the state of the button?
Thank you!
Update:
When loaded from the interface builder, the button stays highlighted, even as the view appears/disappears. What causes this to happen is the "shows touch on highlight" interface builder property. If I assign the code above to another button, the info button highlights on and off as expected. However, the touches of the info button itself interfere with the above code, causing the button to lose the "touch" highlight
Update 2: I added another info button, directly below the first info button, in the interface builder and made it glow permanently. To create the appearance of the toggle, I hide and unhide the glowInfoButton below the real one. This works as expected:
infoButton.highlighted = NO;
glowInfoButton.highlighted = YES;
glowInfoButton.enabled = NO;
glowInfoButton.hidden = YES;
- (IBAction)toggleInfoMode:(id)sender {
// infoButton.selected = !infoButton.selected;
glowInfoButton.hidden = !glowInfoButton.hidden;
}
The Highlighted image is what displays when the UIButton is being pressed, and is controlled within the UIButton itself.
You're looking for the Selected property. You can set a Selected Image in IB, and then put a infoButton.selected = !infoButton.isSelected; in your TouchUpInside callback.
The highlighted property doesn't work like that, buttons aren't toggles.
It's just to know if the button is being pressed, if I'm correct.
If you want to implement that functionality, I recommend you subclass UIButton or UIControl.
Now that I see what you really were after I would advise subclass UIButton and check for a call to an event then toggle highlight state accordingly. You can do this without adding the dummy button.
in a custom button class implementation file place the following code, or similar:
#import "HighlightedButton.h"
#implementation HighlightedButton
BOOL currentHighlightState;
-(void)toggleHighlight:(id)sender {
self.highlighted = currentHighlightState;
}
-(void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
//get the string indicating the action called
NSString *actionString = NSStringFromSelector(action);
//get the string for the action that you want to check for
NSString *touchUpInsideMethodName = [[self actionsForTarget:target forControlEvent:UIControlEventTouchUpInside] lastObject];
if ([touchUpInsideMethodName isEqualToString:actionString]){
//toggle variable
currentHighlightState = !currentHighlightState;
//allow the call to pass through
[super sendAction:action to:target forEvent:event];
//toggle the property after a delay (to make sure the event has processed)
[self performSelector:#selector(toggleHighlight:) withObject:nil afterDelay:.2];
} else {
//not an event we are interested in, allow it pass through with no additional action
[super sendAction:action to:target forEvent:event];
}
}
#end
That was a quick run at a proper solution, there is a flicker on toggle that you may not like. I am sure if you play around with some changes that can be corrected. I tried it and actually like it for your stated case.
The highlighted state of a UIButton is simply setting the button's alpha to 0.5f. So if you set the button to not change on highlight, then just toggle the alpha between 0.1 and 0.5.
For example:
- (void)buttonPressed:(id)sender {
if((((UIButton*)sender).alpha) != 1.0f){
[((UIButton*)sender) setAlpha:1.0f];
} else {
[((UIButton*)sender) setAlpha:0.5f];
}
}
Perhaps what you really want is
infoButton.enabled = NO;
This will dim the button and disable touches when set to no, allow normal operation when set to YES.
or in your case:
infoButton.enabled = !infoButton.isEnabled;
to toggle the availability of same.
If you put this in your touchupinside event, of course it will work only the first time. After that is disabled and does not receive touch events. You would put it in another method that decides whether or not the button should be enabled.
If you truly want it to change each time it is pressed then you probably should use a switch or you may look at the -imageForState, -setTitle:forState and/or -setTitleColor:forState methods. If you want to toggle the appearance each time it is touched, you could change these.

How to dismiss keyboard when using DecimalPad

I have a UITableView with a custom cell that has a TextField. I have the DecimalPad comes up, and as we all know, there is no done key. I previously had resolved this type of issue when I had a "Decimal only" textfield on a normal UIView by handling the TouchesEnded event and then checking to see if the TextField was the first responder and if so, it would then resign, but if that technique could work now then I'm not able to figure out who's TouchesEnded I should be using (The UIView that everything is presented on, the UITableView, the Cell, the CellControler, the TextField.. I think I've tried everything).
I'm hoping there's another, cleaner way of dealing with this.
Anyone?
I think David has the best idea - here is some Monotouch code to get you started. You will need to put this in the View Controller where the decimal pad is being shown:
UIView dismiss;
public override UIView InputAccessoryView
{
get
{
if (dismiss == null)
{
dismiss = new UIView(new RectangleF(0,0,320,27));
dismiss.BackgroundColor = UIColor.FromPatternImage(new UIImage("Images/accessoryBG.png"));
UIButton dismissBtn = new UIButton(new RectangleF(255, 2, 58, 23));
dismissBtn.SetBackgroundImage(new UIImage("Images/dismissKeyboard.png"), UIControlState.Normal);
dismissBtn.TouchDown += delegate {
textField.ResignFirstResponder();
};
dismiss.AddSubview(dismissBtn);
}
return dismiss;
}
}
If you're targeting iOS 4.0 or greater you can create an inputAccessoryView containing a Done button to attach to the keyboard that will dismiss the keyboard when tapped. Here is an example from the documentation on creating a simple inputAccessoryView.
You could dismiss it when the user taps on the background; I think that's the most intuitive way.
In Interface Builder, change your View's class to UIControl. This is a subclass of UIView, so your program will work the same way, but you also get the standard touch events.
From here it's simple, create a method for the Touch Down event:
[numberField resignFirstResponder]
Of course it might be slightly different with MonoTouch -- unfortunately I don't know much about it, but wanted to help.
Hopefully you can use the concept, and modify your code accordingly.
Or you may just add some gesture to your main view.
For example:
//Just initialise the gesture you want with action that dismisses your num pad
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
UISwipeGestureRecognizer *swipeToHideNumPad = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(hideNumPad:)];
swipeToHideNumPad.delegate = self;
swipeToHideNumPad.direction = UISwipeGestureRecognizerDirectionDown;
[swipeToHideNumPad setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:swipeToHideNumPad];
}
//action
- (void)hideNumPad:(UIGestureRecognizer *)gestureRecognizer
{
[self.amountTextField resignFirstResponder];
}

How to programmatically replace UIToolBar items built in IB

I have a toolbar with various image buttons, created in Interface Builder.
I'd like to be able to programmatically replace one of the buttons with an activity indicator when pressed, and then put back the original button but change its color from white to yellow when the activity completes.
Is this possible with an IB built toolbar or must I look at building the whole toolbar programmatically and custom views?
Here is an example of what I did in a similar situation. I wanted to build the toolbar using Interface Builder but toggle one of the BarButtonItems based on whether or not it was "checked". In this example, there are a few key things to note. The following 2 member variables are defined for the class in the header file:
NSMutableArray *toolbarItems;
IBOutlet UIToolbar *toolbar;
NSUInteger checkUncheckIndex;
When I want to update the checked status, I call this function... Please note that there is a selector defined called checkUncheckClicked that is called when the particular button in the UIToolbar is clicked. And the UIToolbar is set up as an IBOutlet to toolbar. Alternately, you could hook up the UIBarButtonItem as an outlet itself and use that as your logic to identify the index of the button, or for that matter, you could hard-code the index of the button if things won't change over time. Finally, there is a checked.png and unchecked.png to alternate between that is included in the project.
- (void)updateBarButtonItemChecked:(BOOL)checked {
if (toolbarItems == nil) {
toolbarItems = [[NSMutableArray arrayWithArray:toolbar.items] retain];
checkUncheckIndex = -1;
for (NSUInteger i = 0; i < [toolbarItems count]; i++) {
UIBarButtonItem *barButtonItem = [toolbarItems objectAtIndex:i];
if (barButtonItem.action == #selector(checkUncheckClicked)) {
favoriteIndex = i;
break;
}
}
}
if (checkUncheckIndex != -1) {
UIBarButtonItem *barButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:checked ? #"checked.png" : #"unchecked.png"]
style:UIBarButtonItemStylePlain target:self action:#selector(checkUncheckClicked)] autorelease];
[toolbarItems replaceObjectAtIndex:checkUncheckIndex withObject:barButtonItem];
toolbar.items = toolbarItems;
}
}
And, of course toolbarItems and toolbar should be released in your dealloc for the class.
Hope this helps!
Here is the approach I used
It seemed to be much simpler to manage the toolbar entirely programatically so ....
In your view controller declare 1 or more sets of UIBarButtonItem items as property items also declare and hookup the toolbar as a UIToolbar property. Also declare 1 or more arrays to hold the items.
In the implementation
In viewDidLoad alloc and set your UIBarButtonItems for example
playButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemPlay
target:self
action:#selector(handlePlayClick)];
Flexible buttons (for alignment etc) are declared like this
flexButton1 =[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil action:nil];
There are several initMethods to handle the different types of buttons toolbars support. All follow a syntax similar to the above. Worth noting is the target and action settings. Target: would normally be self, action is the name of the function that button should trigger.
After alloc'ng your UIBarButtons add them to an array using initWithObjects.
Then to assign the buttons to the toolbar you would call
[toolbar setItems:<array name>];
Dont forget to dealloc your UIBarButtons and arrays at the end of your code.
Hope this helps. If you need more code let me know.
Rich D.
Swift
Much has changed since these answers have been posted. Here is a Swift 2.0 solution.
It matters not how the original UIBarButtonItem you are replacing has been created programmatically. All you need is the UIToolbar outlet. To replace, say, the 2nd item from the left, do this:
var toolbarItems = self.toolbar.items
let newItem = UIBarButtonItem(barButtonSystemItem: .Play, target: self, action: "play")
toolbarItems![1] = newItem
self.toolbar.setItems(toolbarItems, animated: true)
Swift has a much easier way. In my case, I am switching the play button with the pause button every touch.
#IBAction func playandPause(sender: UIBarButtonItem) { // Here we are creating an outlet. Hook this up to the bar button item.
for (index, button) in toolbarItems!.enumerate() { // Enumerating through all the buttons
if button === sender { // === operator is used to check if the two objects are the exact same instance in memory.
var barButtonItem: UIBarButtonItem!
if mediaplayer.playing {
mediaplayer.pause()
barButtonItem = UIBarButtonItem.init(barButtonSystemItem: .Play, target: self, action: #selector(playandPause(_:)))
}else {
mediaplayer.play()
barButtonItem = UIBarButtonItem.init(barButtonSystemItem: .Pause, target: self, action: #selector(playandPause(_:)))
}
toolbarItems![index] = barButtonItem // Replace the old item with the new item.
break // Break once we have found the button as it is unnecessary to complete the rest of the loop
}
}
}
I think it should be possible. You might either try creating an IBOutlet for that specific button in your ViewController class, and connect the button from IB to that outlet, or you can use the items property of that UIToolbar instance (you do have a reference to that, don't you?) and find the appropriate item in there, create a new NSArray with modified items, and set it back on that toolbar.items property.
HTH
A note on this - the toolbar will strip out any color in your icons, so you still won't be able to make it yellow. You'll need to change the image shape to indicate "on" instead.
Alternatively you'll need to load your BarButtonItems with UIButtons (use the initWithCustomView) and set the image of the button appropriately.
HTH
Try:
- (void)setTitle:(NSString *)title forItem:(int)item ofToolbar:(UIToolbar *)tb {
NSMutableArray *newItems = [tb.items mutableCopy];
UIBarButtonItem *old = [newItems objectAtIndex:1],
*titled = [[UIBarButtonItem alloc] initWithTitle:title style:old.style target:old.target action:old.action];
[newItems replaceObjectAtIndex:1 withObject:titled];
tb.items = newItems;
[titled release];
}
For the entire toolbar that you created in IB (that is to say, not the individual toolbar items), create an IBOutlet:
#IBOutlet weak var toolbarThatYouMade: UIToolbar!
This is an array of individual toolbar items, so you would access the leftmost member (for example) with a [0] index:
toolbarThatYouMade.items![0].image = UIImage(named: "New Image")
This code assumes that you have an image named "New Image" in your assets.
You can then trigger an image change for a toolbar item without having to access that specific item itself; for example, if you were using this for something like a media player, you could toggle pause/play images from:
a) the Pause/Play button itself,
b) the Stop button,
c) when you are notified of a change of player state,
or
d) something else entirely. (Be brave! Be bold! Be something else that begins with 'b'!)