I was following the tutorial at http://www.youtube.com/watch?v=YgeuauhsDhQ to create the previous, next, done button above the keyboard that slides up with the keyboard.
However, I noticed he is doing it to a specific view and I do not want to have to copy / paste this into every view that has a text field. I tried making a class for this but then realised that he resigns the keyboard based on the field that is currently in focus.
Is anyone aware of a class already out there so I do not have to create this for every view controller that has a text field? Or know how I can modify his version to work as a class I could import into my view controllers?
Sorry I am sorta new to iPhone development.
//KeyboardToolbar.h
#import <Foundation/Foundation.h>
#interface KeyboardToolbar : NSObject
{
UIToolbar *keyboardToolbar;
}
#property (nonatomic, retain) UIToolbar *keyboardToolbar;
-(void)resignKeyboard:(id)sender;
-(void)previousField:(id)sender;
-(void)nextField:(id)sender;
#end
and
//KeyboardToolbar.m
#import "KeyboardToolbar.h"
#implementation KeyboardToolbar
#synthesize keyboardToolbar;
- (void)loadToolbar
{
if (keyboardToolbar == nil) {
keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 44.0)];
UIBarButtonItem *previousButton = [[UIBarButtonItem alloc] initWithTitle:#"Previous" style:UIBarButtonItemStyleBordered target:self action:#selector(previousField:)];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithTitle:#"Next" style:UIBarButtonItemStyleBordered target:self action:#selector(nextField:)];
UIBarButtonItem *extraSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(resignKeyboard:)];
[keyboardToolbar setItems:[[NSArray alloc] initWithObjects:previousButton, nextButton, extraSpace, doneButton, nil]];
}
}
- (void)resignKeyboard:(id)sender
{
//Resign the keyboard here? I would need to get the element with the keyboard then hide it.
}
#end
How would I make this class more dynamic so I can use it in all of my views with very little copy / pasting into each controller.
I'm new at this too but I think I can help. I did something similar. I set up a helper object to act as delegate for whatever view controller the user was currently interacting with. You'll write your code for making the toolbar appear. You'll implement those methods in the .m file of your helper (delegate) class. Add your helper class as an observer for the UIKeyboardDidShowNotification. So, in the viewDidLoad of my UIViewControllers, I set the delegate to my helper object. Then, when a keyboard appears on that current view controller, the notification is sent to the delegate (helper object).
Here's a little code to clarify:
In init method of helper object:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
Then, in the .m file of your helper object, in keyboardWasShown:, call [self makeToolbar] or whatever your methods are called. Sorry for the verbosity. Like I said, I'm pretty new but I hope this helps.
EDIT: So I made a simple little test/illustration. Here's the .h for my ViewController class. This is the ViewController that will contain the UITextFields, both of which bring up a keyboard and add a toolbar to it via a delegate method. Sorry for the lengthy response, but I thought it would be most useful to just give you all of what got it working for me.
#import <UIKit/UIKit.h>
#import "TextFieldDelegate.h"
#interface ViewController : UIViewController <UITextFieldDelegate> {
//Outlets for 2 UITextFields, added in IB. Selecting either will add the toolbar to your keyboard as long as the delegate is assigned and the methods in the delegate are implemented as shown.
IBOutlet UITextField *myTextField;
IBOutlet UITextField *myOtherTextField;
//we'll need to set the delegate for this class, so go ahead and declare a variable and make it a property (and synthesize it in the .m).
id delegate;
}
#property (nonatomic, strong) id delegate;
#end
ViewController.m:
#implementation ViewController
#synthesize delegate;
//removed method stubs and only left my modifications to the template.
- (void)viewDidLoad
{
[super viewDidLoad];
//create an instance of your delegate class and set it as the view controller's delegate.
//the text fields need their parent as the delegate, and the parent in turn assigns the helper class as its delegate.
//really this is the whole point, that you can just assign delegates to your view
//controllers and text fields and they can all access the one method implementation
//instead of each having to implement it separately themselves.
[myTextField setDelegate:self];
[myOtherTextField setDelegate:self];
TextFieldDelegate *myDelegate = [[TextFieldDelegate alloc] init];
[self setDelegate: myDelegate];
//set the delegate's currentViewController property so that we can add a subview to this View.
[delegate setCurrentViewController:self];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
//set the delegate's current text field property so that we can resignFirstResponder.
[delegate setCurrentTextField:textField];
}
#end
Now here's the delegate class:
TextFieldDelegate.h:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface TextFieldDelegate : UIViewController <UITextFieldDelegate> {
UIViewController *currentViewController;
UITextField *currentTextField;
UIToolbar *keyboardToolbar;
CGSize kbSize;
}
- (void)loadToolbar;
#property (nonatomic, strong) UIViewController *currentViewController;
#property (nonatomic, strong) UITextField *currentTextField;
#end
And the implementation of the delegate:
TextFieldDelegate.m:
#import "TextFieldDelegate.h"
#implementation TextFieldDelegate
//synthesize properties so that View Controllers can set them as needed.
#synthesize currentViewController, currentTextField;
- (id)init {
self = [super init];
if (self) {
//register for the keyboard did show notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
}
return self;
}
- (void)keyboardWasShown:(NSNotification *)aNotification {
//get the keyboard size for positioning the toolbar. (depending on where you want it, I guess, I was just imagining it directly above the keyboard.
NSDictionary *info = [aNotification userInfo];
kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//call the method to make the toolbar appear.
[self loadToolbar];
}
- (void)loadToolbar
{
if (keyboardToolbar == nil) {
//setting the position of the toolbar.
CGRect frameRect = self.view.frame;
frameRect.size.height -= kbSize.height;
keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, frameRect.size.height - 60.0, 320.0, 60.0)];
//your code for toolbar setup.
UIBarButtonItem *previousButton = [[UIBarButtonItem alloc] initWithTitle:#"Previous" style:UIBarButtonItemStyleBordered target:self action:#selector(previousField:)];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithTitle:#"Next" style:UIBarButtonItemStyleBordered target:self action:#selector(nextField:)];
UIBarButtonItem *extraSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(resignKeyboard:)];
[keyboardToolbar setItems:[[NSArray alloc] initWithObjects:previousButton, nextButton, extraSpace, doneButton, nil]];
//this line sends a message to the currently active view controller, telling it to add as a subview the toolbar that we have just created.
[[currentViewController view] addSubview:keyboardToolbar];
}
}
- (void)resignKeyboard:(id)sender {
[currentTextField resignFirstResponder];
[keyboardToolbar removeFromSuperview];
//set the toolbar to nil so that when you touch the other text field, it will build again.
keyboardToolbar = nil;
}
#end
So, there it is. Like I said, I'm new as well. But I hope this helps.
#jostster
EDIT: Oh, if you move the call to the custom delegate method loadToolbar into the ViewController's textFieldDidBeginEditing method, it works. In ViewController.m
- (void)textFieldDidBeginEditing:(UITextField *)textField {
//set the delegate's current text field property so that we can resignFirstResponder.
[delegate setCurrentTextField:textField];
[delegate loadToolbar];
}
And then you can just remove the [self loadToolbar] call from keyboardWasShown in the delegate implementation.
EDIT: to get your next and previous buttons working, first give your delegate a property: NSArray *textFieldArray. Then, in your view controller, create an array of your text fields (we'll call it tfArray), and then do [delegate setTextFieldArray:tfArray]; Then implement your previousField: and nextField: methods something like this:
- (void)previousField:(id)sender {
//get the index in the array of your currently active textField
int activeIndex = [textFieldArray indexOfObject:currentTextField];
//make sure you're not going to try to access an empty spot in the array
if (activeIndex > 0) {
UITextField *previousField = [textFieldArray objectAtIndex:activeIndex - 1];
[previousField becomeFirstResponder];
}
}
//same again but with a plus sign
- (void)nextField:(id)sender {
int activeIndex = [textFieldArray indexOfObject:currentTextField];
if (activeIndex < 1) {
UITextField *nextField = [textFieldArray objectAtIndex:activeIndex + 1];
[nextField becomeFirstResponder];
}
}
There might be a cleaner way to do this but the amount of code is so minimal that I don't feel like typing it twice is that big of a deal. That's the gist of it though and if you had a whole lot of text fields to advance through, you would just want to say something like:
if (activeIndex < [textFieldArray count]) {
//advance to the next textField
}
I found this project on Github that might be useful.
https://github.com/rexfinn/RFKeyboardToolbar
Related
I have a class that subclasses ABNewPersonViewController. As I understand, when the Done button in the navigation bar is clicked, the delegate method
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person
gets called. But before entering the delegate method, the changes will be saved to address book.
What I need is, as soon as the save button gets pressed. I need to load a UIView with 2 buttons asking the user,
whether he wants the changes and
whether he should abort the changes made,
But this should be done before the changes are reflected in the address book. And only on the click of the first button in the UIView, that the changes should be saved in the address book.
On the click of the 2nd button, the view should disappear and I should return to the view controller class from where the UIView is loaded.
My question is, how will I load the view on save button click, before the changes are reflected in the address book
I have created a custom save button
UIBarButtonItem *okBtn = self.navigationItem.rightBarButtonItem;
UIBarButtonItem *saveBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:okBtn.target action:okBtn.action];
self.navigationItem.rightBarButtonItem =saveBtn;
[saveBtn release];
On the save button action, the control goes to the delegate method
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person` .
I want the control go to my custom method, where I can load my UIView before the edits are saved in the address book.
Edit:
When I load the ABNewPersonViewController
ABPersonViewController *displayVcardViewController = (ABPersonViewController*)[self.navigationController visibleViewController];
ABRecordRef person = displayVcardViewController.displayedPerson;
EditAddressNewPersonDetailViewController *newVCardViewController = [[EditAddressNewPersonDetailViewController alloc] init];
newVCardViewController.displayedPerson = person;
newVCardViewController.newPersonViewDelegate = self;
newVCardViewController.isEditingMode = YES;
[self.navigationController setToolbarHidden:YES];
[self.navigationController pushViewController:newVCardViewController animated:YES];
[newVCardViewController release];
Isn't this strong reference already or else Where should I include the strong reference.
On
- (void)actionSave:(UIBarButtonItem *)sender {
if([[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil]) {
[self.myView setFrame:CGRectMake(0, 0, 320, 480)];
[[UIApplication sharedApplication].keyWindow addSubview:self.myView];
UIActionSheet * action = [[UIActionSheet alloc]initWithTitle:#""
delegate:self
cancelButtonTitle:#"Do"
destructiveButtonTitle:#"Cancel"
otherButtonTitles: nil];
action.tag = 101;
[action showInView:self.view];
[action release];
}
}
I am loading a UIView with UIAlertView over it.
Update: Starting with iOS 7.0, ABNewPersonViewController is not subclassable anymore and this won't work.
First, keep a reference to the default rightBarButtonItem before overriding it.
If you're subclassing ABNewPersonViewController, your viewDidLoad would look like:
- (void)viewDidLoad {
[super viewDidLoad];
// Store the old button item into a custom property
// #property (nonatomic, retain) UIBarButtonItem *defaultRightBarButtonItem;
self.defaultRightBarButtonItem = self.navigationItem.rightBarButtonItem;
UIBarButtonItem *saveBtn = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self
action:#selector(actionSave:)];
self.navigationItem.rightBarButtonItem = saveBtn;
[saveBtn release];
}
And you call the default action on the default target in your custom action method:
- (void)actionSave:(UIBarButtonItem *)sender {
// Do what you want to do before the data is saved
// ....
// ....
// Trigger the default action
[self.defaultRightBarButtonItem.target
performSelector:self.defaultRightBarButtonItem.action
withObject:self.defaultRightBarButtonItem.target];
}
i'm trying to build a quiz that sets the value of a UILabel dynamically through code.
i've done this successfully before, but for some reason it's not working this time. i suspect it's because the structure of this app is different. i've tried different fixes but haven't been able to get it to work.
the way my app is set up, i have a view controller with a view that has a segmented control. when you press one of the switches on the segmented control, it inserts a subview like this:
menuTable.hidden = YES;
additionPracticeController *additionPractice = [[additionPracticeController alloc]
initWithNibName:#"additionPractice"
bundle:nil];
self.addPracticeController = additionPractice;
[self.view insertSubview:additionPractice.view atIndex:0];
[additionPractice release];
the view controller for that subview displays its view like this:
- (void)viewWillAppear:(BOOL)animated{
firstNumberString = [NSString stringWithFormat:#"%d",arc4random() % 10];
firstNumberLabel.text = firstNumberString;
secondNumberLabel.text = secondNumberString;
[super viewWillAppear:animated]}
my outlets are connected and i can get the values to appear by setting them statically from the nib (even though that's not what i want). i've tried to set firstNumberString equal to all sorts of values, but nothing shows up when i set the values through code.
i'd really appreciate it if someone could help me solve this problem.
It sounds like you have the label connected in Interface Builder. I would need to see more code to know exactly what you are doing wrong. Make sure you are using a property for your label. The below code is a simple example of how this works.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
IBOutlet UILabel *_displayMessage;
}
#property (nonatomic, retain) UILabel *displayMessage;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize displayMessage = _displayMessage;
- (void)viewDidLoad
{
[super viewDidLoad];
self.displayMessage.text = #"Text Changed!";
}
- (void)viewDidUnload
{
self.displayMessage = nil;
[super viewDidUnload];
}
- (void)dealloc
{
[_displayMessage release];
[super dealloc];
}
#end
Instead of making your class a subclass of UIControl just implement this method below. When the user hits done or return the keypad will resign
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
To make the text field dismiss when the user taps outside of the text field.
Place this in ViewDidLoad:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
Place this method within the class:
-(void)dismissKeyboard
{
[aTextField resignFirstResponder];
}
Also if you want to dismiss the text field from another button spefically and not just a screen tap. Then just call this from within the button.
[your_textfield_name resignFirstResponder];
I have a UINavigationController (to use like a wizard page) which I create programmatically and I need to display a "Cancel" button to cancel the process in any UIViewController.
Creating the UINavigationController:
FirstVC *firstVC = [[[FirstVC alloc] initWithNibName:#"FirstPage" bundle:nil] autorelease];
firstVC.delegate = self;
navigationController = [[UINavigationController alloc] initWithRootViewController:firstVC];
[self.view addSubview:navigationController.view];
Adding Cancel Button:
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(cancelRequestNewLeave:)];
navigationController.topViewController.navigationItem.rightBarButtonItem = cancelButton;
[cancelButton release];
But when I push a second page to UINavigationController the cancel button is not shown on the UINavigationBar. If I go back to first page, the cancel button is there. So, apparently the button is added only for the first view. I believe this is because I'm not subclassing UINavigationController, because I need to use it in a subview. But I don't know how to set the rightBarButtonItem in a UINavigationController which is created programmatically.
navigationController.topViewController.navigationItem.rightBarButtonItem = cancelButton;
Can someone shed a light on this?
Thanks in advance.
The navigation item is per view controller. The navigation bar draws its contents from the navigation item of the view controller whose view it's currently framing, which corresponds to the view controller at the top of the navigation controller's stack.
You basically need each view controller to stick a cancel button in its navigation item. You can do any of the following:
Copy-paste the code into all relevant view controllers.
Move the code into a utility function or class and call that.
Create a common superclass for all relevant view controllers that handles setting up the cancel button for its subclasses.
You can also subclass UINavigationcontroller and overide few methods like this:
- (id)initWithRootViewController:(UIViewController *)rootViewController {
self = [super initWithRootViewController:rootViewController];
if (self) {
[self setCloseButtonToController:rootViewController];
}
return self;
}
- (void)dismissController {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)setCloseButtonToController:(UIViewController *)viewController {
UIBarButtonItem *closeItem = [[UIBarButtonItem alloc] initWithTitle:#"Close" style:UIBarButtonItemStylePlain target:self action:#selector(dismissController)];
[viewController.navigationItem setRightBarButtonItem:closeItem];
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[super pushViewController:viewController animated:animated];
[self setCloseButtonToController:viewController];
}
You can instead adopt the UINavigationControllerDelegate protocol in the class which creates the UINavigationController instance. You can also create the cancelButton in advance and then implement navigationController:willShowViewController:animated: like this,
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
viewController.navigationItem.rightBarButtonItem = cancelButton;
}
You will have to remember to create and hold the cancelButton and not release it. This will also mean cancelRequestNewLeave: will have to be a method in class that creates the UINavigationController instance which is what it is right now I guess.
create CommonViewController
create FirstViewController (extends from CommonViewController)
create SecondeViewController (extends from CommonViewController)
add function common functions in the CommonViewController
like that
CommonViewController.h
#interface CommonViewController : UIViewController
-(void) initializeCartBarButton;
#end
CommonViewController.m
#import "CommonViewController.h"
#interface CommonViewController ()
#end
#implementation CommonViewController
-(void) initializeCartBarButton {
UIBarButtonItem *cartBarButton = [[UIBarButtonItem alloc] init];
cartBarButton.title = #"cart";
[cartBarButton setTarget: self];
[cartBarButton setAction: #selector(goToCart:)];
self.navigationItem.rightBarButtonItem = cartBarButton;
}
- (IBAction) goToCart:(id)sender {
NSLog(#"");
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#import "CommonViewController.h"
#interface FirstViewController : CommonViewController
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeCartBarButton];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import "CommonViewController.h"
#interface SecondViewController : CommonViewController
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeCartBarButton];
}
#end
note: you can add the code of initializeCartBarButton in the viewDidLoad of CommonViewController and delete this fuction from CommonViewController and from child class's
This is how I did it with UINavigationController subclass that is capable of dismissing every viewController pushed into it.
class CustomNavigationController: UINavigationController, UINavigationControllerDelegate{
//TODO: Use when we have more right bar button types.
var rightBarButtonType: RightBarButtonType = .Close
enum RightBarButtonType{
case Close
}
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
// MARK: Private Functions
private func addRightBarButtonTo(viewController: UIViewController){
let barButtonItem: UIBarButtonItem!
switch self.rightBarButtonType {
case .Close:
barButtonItem = UIBarButtonItem(image: UIImage(named: "ic_close_white"), style: .Done, target: self, action: #selector(CustomNavigationController.dismiss(_:)))
}
viewController.navigationItem.rightBarButtonItem = barButtonItem
}
// MARK: UINavigationController Delegate
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
self.addRightBarButtonTo(viewController)
}
#objc func dismiss(sender: AnyObject){
self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
}
You'll need to add the button in every view controller. You cannot do it by setting one once or sharing one between view controllers (in a sensible fashion). A good place to add the button is in the viewDidLoad method of your view controllers. You can create one basic UIViewConteoller subclass for them if you feel this gets to repetitive.
You can add a custom 'Cancel' UIButton directly to the NavigationBar's view instead of using the UIBarButtonItem.
UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
cancelButton.imageView = // Some custom image
cancelButton.frame = CGRectMake(...); // Something far to the right.
[self.navigationController.navigationBar addSubview: cancelButton];
The normal way to do this is to add that cancel button to the navigationItem of every single view controller in your navigation stack. The above approach can make it simpler by allowing you to write less code, but it is a tiny bit of a hack.
Add this code in your rootview viewDidLoad method and implement the cancelMethod in rootview controller.This will be available in all the view controllers. you can adjust the button location by changing button frame.For orientation change you have manually adjust the location of button.
UIButton *btnCancel = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnCancel addTarget:self
action:#selector(cancelMethod)
forControlEvents:UIControlEventTouchDown];
[btnCancel setBackgroundImage:[UIImage imageNamed:#"image"]
forState:UIControlStateNormal];
btnCancel.frame = CGRectMake(280, 27, 45, 25);
[self.navigationController.view addSubview: btnCancel];
I have made a table containing an array editable (you can delete rows) by swiping and clicking delete. However, I am trying to make it so you click the edit button in the navbar and the red minus sign comes up next to each cell.
I am using the code from my book but the tableView variable is not working. I can't figure out how it is working in the book but not in my project.
I think it is because the book's class is a subclass of UITableViewController while mine is a UIViewController with a UITableViewController Object in it. So how can I get this to work?
I have an IBOutlet for tableView in my interface file too.
Here is the relevant code:
#import "RoutineTableViewController.h"
#import "AlertPrompt.h"
#implementation RoutineTableViewController
#synthesize myArray;
#synthesize myData;
- (void)viewDidLoad
{
myArray = [[NSMutableArray alloc] init];
myData = [[NSMutableArray arrayWithContentsOfFile:#"mydata"] retain];
if (myData == nil)
{
myData = [NSMutableArray array];
}
UIBarButtonItem * addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(showPrompt)];
[self.navigationItem setLeftBarButtonItem:addButton];
[addButton release];
UIBarButtonItem *editButton = [[UIBarButtonItem alloc]initWithTitle:#"Edit" style:UIBarButtonItemStyleBordered target:self action:#selector(toggleEdit)];
self.navigationItem.rightBarButtonItem = editButton;
[editButton release];
[super viewDidLoad];
}
-(IBAction)toggleEdit:(id)sender
{
[self.tableView setEditing: !=self.tableView.editing animated:YES];
if (self.tableView.editing)
[self.navigationItem.rightBarButtonItem setTitle:#"Done"];
else
[self.navigationItem.rightBarButtonItem setTitle:#"Edit"];
}
You need to set the editingStyle of each UITableViewCell to be UITableViewCellEditingStyleDelete. This should be done when creating the cell within the table view's delegate (tableView:cellForRowAtIndexPath:)
This might look like I am assuming you are a total newbie, but trust me, many people forget this (I'm not saying I'm an expert either), but you should check if your edit button is connected to the corresponding IBOutlet in Interface Builder.
EDIT: Forgot to ask, is your button an IBOutlet (IB element)? Or is it created programmatically? If the second is true, then you should NOT use IBActions for programmatically created objects (hence Interface Builder Action = IBAction)
I have a viewcontroller which contains an instance variable containing a dictionary object with a bunch of data. The view is fairly complex and contains several subviews that i instantiate and embed from seperate view files(To avoid having a thousand lines of UI code in the actual viewcontroller) - But how do these subviews, which exists in their own files, get access to my dictionary object from the viewcontroller?
So when im editing the DescriptionView.m file - How do i get access to the contents of the locationData dictionary object from the ViewController?
Hope you understand what i mean.
Here's a snippet from the ViewController:
CaseViewController.h
#import "DescriptionView.h"
#interface CaseViewController : UIViewController {
NSDictionary *locationData;
DescriptionView *descriptionView;
}
#property (nonatomic, retain) NSDictionary *locationData;
#property (nonatomic, retain) DescriptionView *descriptionView;
#end
CaseViewController.m
- (void)loadView {
UIView *view = [[UIView alloc] init];
descriptionView = [[DescriptionView alloc] initWithFrame:CGRectMake(0, 130, 320, 237)];
descriptionView.hidden = NO;
[view addSubview:descriptionView];
self.view = view;
[view release];
}
Ideally you should never access any properties of viewcontroller from the view.
The main idea of MVC architecture is that viewcontroller tells it's views what to render and not vise versa.
So you just have to provide all the data that your view needs for rendering during it's initialization:
- (void)loadView {
UIView *view = [[UIView alloc] init];
descriptionView = [[DescriptionView alloc] initWithFrame:CGRectMake(0, 130, 320, 237) paramDict: self.locationData]; descriptionView.hidden = NO;
[view addSubview:descriptionView];
[descriptionView release]; // BTW add this line here (or in dealloc) or you'll have a leak
self.view = view; [view release];
}
If you need to update your view dynamically, then you should add some methods to your view and call them from viewcolnroller.
E.g.:
DescriptionView.m:
-(void) updateWithDict:(NSDictionary*) udict;
If you need to perform some actions when some button in DescriptionView is pressed (or any other user interaction) a good idea would be declaring a protocol like DescriptionViewDelegate (or smth like that):
-(void) descriptionViewButton1Pressed:(DescriptionView*) dview;
-(void) descriptionViewButton2Pressed:(DescriptionView*) dview;
then make your CaseViewController a delegate and implement that methods there.
The simpliest way to have a reference to its viewcontroller from a view is to extend UIView:
#interface MyView: UIView {
UIViewController *mViewController;
}
Then in loadView
MyView *view = [[MyView alloc] init];
view.mViewController = self;