KVO with two UIButtons - iphone

I have a custom UITableViewCell subclass that gets presented in a UITableView in a UIPopoverController. The UIPopoverController is presented from a UIBarButtonItem.
When selections in the UITableViewCell are made, I send a NSNotification to the UIViewController class that is presenting the UIPopoverController. The selections in the table update my view in my viewController.
Now, there is a requirement to have another UIBarButtonItem that does EXACTLY the same thing as one of the buttons in the UITableViewCell in the popover. Basically the use case is that this feature seems to be the most commonly used feature in our popover and they want an easy way to just turn it on and off from another button.
So what I did was create a new UIBarButtonItem, and have a target attached to it:
- (void)FilterOn:(id)sender {
isFilterOn = !isFilterOn;
if ([sender isKindOfClass:[UIBarButtonItem class]]) {
UIBarButtonItem *filter = (UIBarButtonItem *)sender;
if (isFilterOn) {
[filter setTitle:#"Filter On"];
[self DoFilter];
}
else {
[aboutMeBBI setTitle:#"Filter Off"];
[self ClearFilter];
}
}
}
So this part works. It updates the model, the title of the button changes. The problem is, let's say I turn filter on, then in the popover, I turn the filter off. I pass the notification to my viewController class to its normal update method that handles filtering and a bunch of other stuff. I added this simple snippet to when the filter button is pressed from the popover:
- (void)FilterSortOptionDidSelect:(NSNotification *)notification {
NSDictionary *userDict = [notification userInfo];
NSInteger theTag = [[userDict objectForKey:#"CellTag"] integerValue];
switch (theTag) {
case FILTER: {
// update Model
[self.FilterBarButtonItem setTitle:#"Filter off"];
}
break;
default:
break;
}
}
This isn't quite what I want though since if I click back on the filter button since for starters, if I click back on the Filter button, it'll still say Filter Off, and do the action for Filter Off, and then if I click it again, it'll do Filter on actions. I try to fake it in the switch statement by changing the title, but that isn't really what I want to do. I read a little about key value observing and I wasn't sure if I could use something like that here, to register my buttons state with that of a button in a UITableViewCell subclass in a UIPopoverController. If anyone has any ideas that would be great. Thanks.

Related

Creating a custom view in Interfacebuilder and using that in code

I have made a view in the application that shows a UITableView. It will be full of results (obviously) almost all the time, however when it does not have any results I want to show another view that inform the user about how he/she could populate the table.
I want to design that view in the interfacebuilder. I will have to check in the code whether the datasource is empty or not to toggle between the two different nibs. How do I instantiate and configure a view made in Interfacebuilder?
The easies way to do this is by adding the view in xib normally and make it visible
Design your both views, the table view and the other view, give the tableView a tag of 111 for example and give the otherview another tag 222 for example
Now in viewDidLoad
Get both the views
UIView *noDataView = [self.view viewWithTag:222];
UITableView *tableView = [self.view viewWithTag:111];
//Hide both of them or only the noDataView until you know if you have data from the dataSource or not
Check for your data source
//hasElements do you have any element to show?
if(hasElements)
{
noDatView.hidden = YES;
tableView.hidden = NO;
}
else
{
noDatView.hidden = NO;
tableView.hidden = YES;
}
You can load nib file based on condition.You can write category as follows:
self.view = (UIView *)[self loadNib:#"SecondView" inPlaceholder:self.view];
- (UIView *)viewFromNib:(NSString *)nibName
{
NSArray *xib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
for (id view in xib) { // have to iterate; index varies
if ([view isKindOfClass:[UIView class]]) return view;
}
return nil;
}
- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder
{
UIView *nibView = [self viewFromNib:nibName];
[nibView setFrame:placeholder.frame];
self.view = nibView;
//[self.view insertSubview:nibView aboveSubview:placeholder];
//[placeholder removeFromSuperview];
return nibView;
}
The other answers give you possible technical solutions but I would propose that if you are using the standard Apple design guidelines, you probably don't even need to worry about it. For instance, somewhere on your screen you should have a bar button item with the identifier "Add" (which shows the plus icon). Then rather than giving a long (often poorly localised) description of how to add items, just have a header for an empty section which says "No items" replacing items with whatever pluralised noun is appropriate for your table's items. For example, for an Archery related app I am working on:
Notice how the Edit button is currently disabled too, thus no explanation is needed as the only thing they can do at this point is tap the Add button (screenshots on the Appstore will have shown them what they can expect to see after this point).

Linking multiple buttons to one method with different jobs

I have a huge crazy scene in my story board that has 36 different buttons, and each one means something different when clicked on. I really don't want to go about creating 36 different methods, so how could I reference a button title or button name in a method that is called when one of the 36 buttons is pushed.
This is probably a simple question, but I'm new to iOS and Objective C...
Thanks!
You can create a single method, like so:
- (IBAction)buttonTapped:(id)sender{
// The button that was tapped is called "sender"
// This will log out the title of the button
//NSLog(#"Button: %#", sender.titleLabel.text);
//Edit: You need a cast in the above line of code:
NSLog(#"Button: %#", ((UIButton *)sender).titleLabel.text);
}
Then, you can use Interface Builder to connect to all of the buttons. You can have some sort of if/else logic to test which button was tapped.
You can check the titleLabel property, or you can assign an IBOutlet to each button and check for that.
For example:
if([sender isEqual:buttonOutlet1]){
//If this button is attached to buttonOutlet1
//do something
}
Alternatively, you can simply use the label of each button, not worrying about outlets.
A third option would be to generate and lay out the buttons in code, and then access them as elements of an array of buttons.
A fourth option would be to add tags to the buttons and check for the button's tag in your function.
Give each button a unique tag value. in the IBAction, sender.tag tells you which button was tapped.
The IBAction routine you set up to handle the button presses has a sender parameter. Examine that to decide.
-(IBAction) buttonPress: (id) sender {
UIButton *pressedButton = (UIButton *)sender;
NSString *buttonTitle = [pressedButton currentTitle];
if ([buttonTitle isEqualToString: #"SomeTitle"]) {
//do work for that button.
}
}
You can use a variety of NSString methods to compare or filter which button was pressed and handle it through if's or switches.
That's quite simple, but since you're new, here's an answer.
(According to Stanford cs193p course, 2010-2011 fall (that's what they did with the calculator app)) make a method that receives an argument, which is the UIButton.
for example:
- (IBAction) someMethodThatDoesSomething:(UIButton *)sender;
Then make if statements according to the sender.titleLabel.text
I don't know if there are any other solutions. Hope this helps!
-(IBAction)myButtonAction:(id)sender {
if ([sender tag] == 0) {
// do something here
}
if ([sender tag] == 1) {
// Do some think here
}
}
// in Other words
-(IBAction)myButtonAction:(id)sender {
NSLog(#"Button Tag is : %i",[sender tag]);
switch ([sender tag]) {
case 0:
// Do some think here
break;
case 1:
// Do some think here
break;
default:
NSLog(#"Default Message here");
break;
}

iPhone - call UISwitch that is generated in a UIView when a button is pressed

To clarify my question, my program has three lightbulb on the screen (Customized UIButton)
when any lightbulb is pressed, I programatically generate a UIView with a switch on it
when I turn on the switch, corresponding lightbulb will light up (change its background image)
However, I have trouble accessing this UISwitch since I can't declare it publicly
My code goes something like this:
#property buttonA;
#synthesize buttonA;//all three buttons have their background image set to 'off.png'
- (IBAction)lightBulbPressed:(UIButton *)sender
{
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(1,1, 64, 64)];
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0,0,64,64)];
[mySwitch addTarget:self action:#selector(onOrOff) forControlEvents:UIControlEventValueChanged];
[myView addSubview:mySwitch]
[self.view addSubview:myView];
}
So what troubles me is how to program the selector onOrOff, so that it knows which switch is being touched and change the background image of corresponding button accordingly.
Think about your method:
- (IBAction)lightBulbPressed:(UIButton *)sender {
// your method
}
You already know who called it. This piece of information is stored in sender.
So you can save it and use later in onOrOff
By the way, if you are using UISwitch you have to check
UIControlEventValueChanged
and not UIControlEventTouchUpInside.
EDIT: To pass your sender you can store its value to a NSString *buttonTapped declared in your .h file
- (IBAction)lightBulbPressed:(UIButton *)sender {
if (sender == bttOne) {
buttonTapped = #"ButtonOneTapped";
} else if (sender == bttTwo) {
buttonTapped = #"ButtonTwoTapped";
} else if (sender == bttThree) {
buttonTapped = #"ButtonThreeTapped";
}
// your method
}
- (void)onOrOff {
if ([buttonTapped isEqualToString:#"ButtonOneTapped"]) {
// Button One
} else if ([buttonTapped isEqualToString:#"ButtonTwoTapped"]) {
// Button Two
} else if ([buttonTapped isEqualToString:#"ButtonThreeTapped"]) {
// Button Three
}
}
One way to do so, is taht you give them distinct tag numbers in IB, and in - (IBAction)lightBulbPressed:(UIButton *)sender method, get their tag. e.g. NSInteger pressedButtonTag = [sender tag];, and go from there.
Also, instead of alloc/init myView every time user presses a button, you can add that view in IB, add the switch to it, put in the hierarchy of the owner but not the view, and set an outlet to it in .h. Call it whenever you need it, and again, access the switch by tag e.g. ( UISwitch *mySwitch = (UISwitch *)[myView viewWithTag:kSwitchTag]; ) and do whatever you want to do (on or off), add it to the subview and remove it later. This is more efficient.

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

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];
}