I have implemented a UISegmentControl as the rightBarButton of my detailViewController.
This view controller displays that of the information passed through from a UITableView.
This UITableView's cells are populated with CoreData attribute values.
What I want to do is enable the user to go up and down in the list via the detailViewController. Instead of having to make the user have to go back to the rootViewController, they'll gain the ability to scroll through via the UISegmentControl.
I currently have this in my detailViewController.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Setting up UISegmentedControl
// Segmented Control - Custom right bar button with a view
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:
[UIImage imageNamed:#"arrowdown.png"],
[UIImage imageNamed:#"arrowup.png"],
nil]];
[segmentedControl addTarget:self action:#selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
segmentedControl.frame = CGRectMake(0, 0, 75, 30);
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl.momentary = YES;
UIBarButtonItem *segmentBarItem = [[UIBarButtonItem alloc] initWithCustomView:segmentedControl];
[segmentedControl release];
self.navigationItem.rightBarButtonItem = segmentBarItem;
[segmentBarItem release];
}
This is then attached to the following method, for detecting the tapped control.
- (void)segmentAction:(id)sender
{
UISegmentedControl* segCtl = sender;
// the segmented control was clicked, handle it here
if([segCtl selectedSegmentIndex]==0){
NSLog(#"You clicked the down arrow - the segment clicked was %d", [segCtl selectedSegmentIndex]);
}else {
NSLog(#"You clicked the up arrow - the segment clicked was %d", [segCtl selectedSegmentIndex]);
}
}
I am also curious as to whether or not anyone knows how to detect whether or not there is anymore to go to. So say, if the note loaded is in the first position, then the down arrow is disabled, and if the note loaded is in the last position, the up arrow is disabled. Is this even possible?
Any help would be greatly appreciated.
I'd suggest you to create a formal protocol MyDataSource which provides methods for accessing the data. As a minimum, there must be a method to get number of data objects and object for a specified index.
In your DetailViewController you should have a reference to an object which conforms to MyDataSource. I'd recommend you to use instance of RootViewController as a data source for DetailViewController.
You should also keep track of index of the object that is currently displayed in DetailViewController and update UI appropriately.
Related
I am fairly new to iOS development. My requirement is I am designing an app that contains 5 screens . I have a set of UI controls( 1 UIImageView 5 UIButtons acting like tab bars for each screen) that are common for all the screens. When a button is clicked only the bottom half of the view needs to change with a relevant details while the buttons stay intact(similar to tab control in windows).
Is there a way to achieve this design? Can I share UI controls across multiple screens without repetition in code or
Is there a way to change only the bottom half of the screen when a button is clicked?
You could have a separate class that would create your UIControls and then for each viewcontroller you call the appropiate method to get the UIControls you want.
#interface UIControlMaker : NSObject{
id controlmakerDelegate; // This is so that you can send messages to the viewcontrollers
}
#property (nonatomic,retain) id controlmakerDelegate; // Release it in dealloc method
- (id)initWithDelegate:(id)delegate;
- (UIView *)createCommonUIControls;
In the implementation file
#implementation UIControlMaker
#synthesize controlmakerDelegate;
- (id)initWithDelegate:(id)delegate{
if(self = [super init]){
[self setControlMakerDelegate:delegate];
return self;
}else
return nil;
}
- (UIView *)createCommonUIControls{
UIView *uicontrolsHolder = [[UIView alloc] initWithFrame:CGRectMake(2,40,320,50)];
// Create as many uicontrols as you want. It'd be better if you have a separate class to create them
// Let's create a button for the menuItem
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0 , 0, 50, 35)];
button.backgroundColor = [UIColor clearColor];
[button setTitle:#"Button 1" forState:UIControlStateNormal];
[button addTarget:controlmakerDelegate action:#selector(buttonOnClick) forControlEvents:UIControlEventTouchUpInside];
[uicontrolsHolder addView:button];
[button release];
// Add more uicontrols here
retun [uicontrolsHolder autorelease];
}
Then in your viewcontrollers create an instance of UIControlMaker and call the createCommonUIControls method which will return a View that you can add to your viewcontroller. Hope that was clear.
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 do have the code for this, but since it's in so many files, I'll only narrow it down and post it if necessary. I believe I might just be missing some method call or thread thing... I have a navigation controller with a table view as its view and a toolbar with three buttons.
Touching one of the three buttons causes a method to be called that changes the table view's dataSource, reloads the table, and also changes the titles (and possibly number) of buttons on the toolbar (# of buttons can be 0~3).
There is also a rightBarButtonItem that pushes on a modal vc which, upon dismissal, changes the dataSource and reloads the table and buttons as well.
The problem: touching a button (#1) causes immediate effects: the buttons are redrawn with new titles and the tableView's data reloaded. But when the modal vc is dismissed (table's setter properties should cause data to be reloaded before viewWillAppear of the table vc), everything is fine except for the buttons! The correct number of UIBarButtonItems appear on the toolbar, but their titles are blank. I NSLog'd inside the method that sets the toolbarItems property, and after the log says "UIBBI array set", the buttons appear, with [blank] titles, then 4-5 seconds later, the titles appear (long after the method to set them has returned).
Do I need to be doing something in a different thread? Pushing this tvc on has no problems, and the method described in #1 also does not produce the same blank-then-titled effects... So, I'm stumped. Sorry for the LENGTHY explanation...trying to be complete. But any help would be very appreciated!
Code which is called when the self.resultsArray is updated (from this view, the previous one which pushes it on, or the modal:
- (void)updateBestGuessesButtons
{
if (self.resultsArray.count == 0 || self.resultsArray.count == 1 || !self.bestGuesses) {
[self.navigationController setToolbarHidden:YES animated:YES];
return;
}
[self.navigationController setToolbarHidden:NO animated:YES];
NSMutableArray *toolbarItems = [[NSMutableArray alloc] initWithObjects:[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil
action:nil], nil];
for (NSString *guess in self.bestGuesses) {
UIBarButtonItem *button = [[UIBarButtonItem alloc]
initWithTitle:guess
style:UIBarButtonItemStyleBordered
target:self
action:#selector(removeWordsWithLetter:)];
[toolbarItems addObject:button];
}
[toolbarItems addObject:[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil
action:nil]];
[self setToolbarItems:toolbarItems animated:YES];
}
It looks like you have to set the title of the UIButton for all states,
[myButton setTitle:#"Foo" forState:UIControlStateNormal];
[myButton setTitle:#"Foo" forState:UIControlStateHighlighted];
[myButton setTitle:#"Foo" forState:UIControlStateSelected];
// .. and so on
OK -- my resolution to this issue was to move the button creation to the viewDidLoad event.
i am trying to implement an action sheet that contains a picker view and a segmented control bar with a previous button, next button and done button like the image as follows http://imgur.com/8wVMy. I currently am able to make it look like this http://imgur.com/AXn6H. I was wondering if someone could help me get the picker view to sit on the bottom and just make it look a little better. Thanks for any help.
Unless you're targeting very old versions of iOS (i.e. versions earlier than 3.2), the best way to do it is to take a completely different approach.
As of 3.2, any UIResponder (which includes all UIViews) can return a UIView from its inputView property to show that view instead of the keyboard when the view becomes the first responder. This even works for views that normally don't become first responder or don't display the keyboard at all. It's simple:
Design your popup view, as you would any other view.
Ensure that your widget view returns YES from canBecomeFirstResponder.
Ensure that your widget view returns an instance of your popup view from inputView.
More details are available in the documentation.
Also, BTW, if you're on an iPad you should probably use a UIPopoverController to display a UIPickerView instead of either of these methods. Apple may actually require this if you intend to get your app in the app store.
The next and previous buttons are actually showing your images to segmentedController Within a toolbar. To get it You have to define the segmentedController and UIToolbar on. H. Next add the DataSource and UIPickerView
Then in the viewDidLoad create objects and define Their properties. For example:
if (keyboardToolbar == nil) {
keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
[keyboardToolbar setBarStyle:UIBarStyleBlackTranslucent];
segControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Anterior", #"Siguiente", nil]];
[segControl setSegmentedControlStyle:UISegmentedControlStyleBar];
[segControl setTintColor:[UIColor blackColor]];
segControl.frame = CGRectMake(5, 7, 150, 33);
segControl.momentary = YES;
[segControl addTarget:self action:#selector(segSelected:) forControlEvents:UIControlEventValueChanged];
UIBarButtonItem *extraSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *aceptar = [[UIBarButtonItem alloc] initWithTitle:#"Hecho" style:UIBarButtonItemStyleDone target:self action:#selector(cerrarTeclado:)];
//aceptar.width = 70.0f;
[keyboardToolbar setItems:[[NSArray alloc] initWithObjects: extraSpace, aceptar, nil]];
[keyboardToolbar addSubview:segControl];
}
I am currently adding a UISegmentedControl to the toolbar in the navigation controller programmatically (as seen below).
This approach works fine, I have my UISegmentedControl, it fires the selector that I have setup no problems.
Problem is - I would like to use the selectedIndex of this control in order to query my data model and present a different view of data for each 'segment' - but I am having trouble getting the selectedIndex.
In my travels I have been consulting the 'Top Songs' example code provided by Apple.
In this code they build up their interface via UISegmentedControl object in the view controller and IB. In doing so they can access the UISegmentedControl's selectedIndex. I am adding mine programmactically and do not have this freedom.
'SHOULD' I have a UISegmentedControl defined in my view controller? If so, if I want to continue building my menu programmactically, how do I go about accessing the information from the control buried within the navigation controller's UIToolBar?
I'm clearly missing something basic. Any assistance is always greatly appreciated :)
[self.navigationController setToolbarHidden:NO];
// Set up the edit and add buttons.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
NSArray *tabitems = [NSArray arrayWithObjects:#"ONE", #"TWO", #"THREE", #"FOUR", nil];
UISegmentedControl *tabs = [[UISegmentedControl alloc] initWithItems:tabitems];
[tabs addTarget:self
action:#selector(pickedSegment:)
forControlEvents:UIControlEventValueChanged];
tabs.segmentedControlStyle = UISegmentedControlStyleBar;
tabs.frame = CGRectMake(60, 8, 180, 30);
tabs.selectedSegmentIndex = 0;
//[self.navigationController.navigationBar addSubview:tabs];
[self.navigationController.toolbar addSubview:tabs];
[tabs release];
You need to have tabs defined in your .h file -
#interface YourViewController : UIViewController
....
UISementedControl *tabs;
....
#end
....
#property (nonatomic, retain) UISegmentedControl *tabs;
Then, after the [tabs release]; line, you should still be able to access the object, as it is a retained property - access the selectedItemIndex as normal.