I have a UISegmentedControl that I want to appear in an UIToolbar. It appears, but clicking it does not call the method that it should. Am I missing anything?
Code:
-(void)setupToolbars{
NSArray *segItemsArray = [NSArray arrayWithObjects: #"List", #"Day", #"Month", nil];
segmentedControl = [[UISegmentedControl alloc] initWithItems:segItemsArray];
segmentedControl.selectedSegmentIndex = 2;
[segmentedControl addTarget:self action:#selector(changeView) forControlEvents:UIControlEventTouchUpInside];//this line should make the segmented control call the correct method
UIBarButtonItem *segmentedControlButtonItem = [[UIBarButtonItem alloc] initWithCustomView:(UIView *)segmentedControl];
NSArray *barArray = [NSArray arrayWithObjects: todayButtonItem,flexibleSpace, segmentedControlButtonItem, flexibleSpace, nil];
[bottomToolbar setItems:barArray];
}
-(void)changeView{
NSLog(#"changeView");
...
}
You want to use the UIControlEventValueChanged event, not the UIControlEventTouchUpInside event.
Just building on top of what rmaddy stated. I would also suggest use of UIControlEventValueChanged event.
[segmentedControl addTarget:self action:#selector(didChangeSegmentControl:) forControlEvents:UIControlEventValueChanged];
-(void)didChangeSegmentControl:(UISegmentedControl*) control
{
if (control.selectedSegmentIndex ==0 )
{
//...
}
}
Related
I have a UIPickerView with 2 components. Selecting 1st components populates 2nd component. Looks like this:
Test Case:
Select any option in Component 0 and then pick any episode in Component 1 of picker and click Fitler which hides the picker.
Show the Picker again to select something else. The first component loads properly. The second component is blank like this screenshot:
Here's the code:
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{
UILabel* tView = (UILabel*)view;
if (!tView){
tView = [[UILabel alloc] init];
tView.textAlignment = NSTextAlignmentCenter;
// Setup label properties - frame, font, colors etc
//...
//adjustsFontSizeToFitWidth property to YES
if(pickerView == self.seasonEpiPickerView && component == 1){
tView.font= [UIFont systemFontOfSize:12];
tView.adjustsFontSizeToFitWidth = YES;
}
}
// Fill the label text here
if (pickerView == self.seasonEpiPickerView)
{
if (component == 0) {
if (row == 0) {
item = #"All";
} else {
//NSLog(#"c1:%ld", (long)row);
item = [NSString stringWithFormat:#"S%#", ((Season *)[self.media.seasonManager.seasonArray objectAtIndex:row-1]).seasonNr];
}
} else if (component == 1){
if(self.media.seasonManager && self.media.seasonManager.seasonArray && [self.media.seasonManager.seasonArray count]>0 ) {
Season* tempSeason = self.media.seasonManager.seasonArray[[self.seasonEpiPickerView selectedRowInComponent:0]-1];
item = [NSString stringWithFormat:#"%#.%# \"%#\"", tempSeason.seasonNr, [NSString stringWithFormat: #"%02d", [((Episode *)[tempSeason.episodeManager.episodeArray objectAtIndex:row]).episodeNr intValue]], ((Episode *)[tempSeason.episodeManager.episodeArray objectAtIndex:row]).title];
NSLog(#"c2:%ld:%#", (long)row, item);
}
}
}
tView.text = item;
return tView;
}
Edit:
Here's how I create the Picker in viewDidLoad
self.seasonPickerViewTextField = [[UITextField alloc] initWithFrame:CGRectZero];
[self.view addSubview:self.seasonPickerViewTextField];
self.seasonEpiPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
self.seasonEpiPickerView.showsSelectionIndicator = YES;
self.seasonEpiPickerView.dataSource = self;
self.seasonEpiPickerView.delegate = self;
//add the toolbar for the season picker
UIToolbar *toolBar= [[UIToolbar alloc] initWithFrame:CGRectMake(0,0,screenWidth,44)];
[toolBar setBarStyle:UIBarStyleBlack];
UIBarButtonItem *barButtonDone = [[UIBarButtonItem alloc] initWithTitle:#"Filter " style:UIBarButtonItemStylePlain target:self action:#selector(filterByEpisode:)];
UIBarButtonItem *flexible = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *barCancelButton = [[UIBarButtonItem alloc] initWithTitle:#" Cancel" style:UIBarButtonItemStylePlain target:self action:#selector(cancelPicker:)];
toolBar.items = [NSArray arrayWithObjects: barCancelButton, flexible, barButtonDone, nil];
self.seasonPickerViewTextField.inputAccessoryView = toolBar;
// set change the inputView (default is keyboard) to UIPickerView
self.seasonPickerViewTextField.inputView = self.seasonEpiPickerView;
EDIT 2
doing a delayed reload when the picker view is presented the second time reloads the second component correctly. This seems very hawkish.
- (IBAction)pickEpisodeButton:(id)sender
{
[self.seasonPickerViewTextField becomeFirstResponder];
/* None of the following commented lines of code have any effect*/
//[self.seasonEpiPickerView selectRow:1 inComponent:0 animated:NO];
//[self.seasonEpiPickerView selectRow:selectedSeason inComponent:0 animated:YES];
//[self.seasonEpiPickerView selectRow:selectedEpisode inComponent:1 animated:YES];
//[self.seasonEpiPickerView reloadComponent:1];
//set a 1.5 sec timer to go to the next screen
[NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:#selector(loadSecondComponent) userInfo:nil repeats:NO];
}
-(void)loadSecondComponent {
[self.seasonEpiPickerView reloadComponent:1];
}
I have custom UIBarButton items added to UINavigationBar as rightbarbuttonitems. I add two more items in UIBarButton when device goes to landscape mode. I am getting rotation call and I am correctly removing items from UIBarbuttons array based on device orientation, but my navigationbar item set never gets updates.
If i start with portrait mode, it shows what it suppose to. When I rotate to landscape new items are not added to navigation bar and vice versa extra item won't go when device go to portrait.
I am not sure how I can change navigationbaritems on device rotation. Per me I am doing all things correct.
-(void)setUpOnRotation:(BOOL)toPortrait{
_searchMessage = [[UILabel alloc] initWithFrame:CGRectMake(3.0, 0, 110, 20)];
_searchMessage.numberOfLines = 2;
_searchMessage.textColor = [UIColor blackColor];
_searchMessage.font = [UIFont systemFontOfSize:8.0];
_searchMessage.text = #"";
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 15, 130, 25)];
_searchBar.delegate = self;
_searchBar.showsCancelButton = NO;
UIBarButtonItem* doneButton = [BarButtons doneButtonWithTarget:self action:#selector(cancel)];
UIBarButtonItem *searchActivityItem = [[UIBarButtonItem alloc] initWithCustomView:_searchMessage];
UIBarButtonItem *searchItem = [[UIBarButtonItem alloc] initWithCustomView:_searchBar];
UIBarButtonItem *in = [BarButtons nativeButtonNamed:#"In"
title:#"In"
target:self
action:#selector(In)];
UIBarButtonItem *out = [BarButtons nativeButtonNamed:#"Out"
title:#"Out"
target:self
action:#selector(Out)];
NSMutableArray *itemsSet;
itemsSet = [NSMutableArray arrayWithObjects:in,
out,
searchItem,
searchActivityItem,
doneButton, nil];
if (toPortrait) {
if ([itemsSet containsObject:searchItem] || [itemsSet containsObject:searchActivityItem]) {
[itemsSet removeObject:searchActivityItem];
[itemsSet removeObject:searchItem];
}
}
[_searchBar release];
[searchItem release];
[_searchActivity release];
[_searchMessage release];
[searchActivityView release];
self.navigationItem.rightBarButtonItems = itemsSet;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self setUpOnRotation:UIInterfaceOrientationIsPortrait(toInterfaceOrientation)];
} -(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
[self setUpOnRotation:UIInterfaceOrientationIsPortrait(self.interfaceOrientation)];}
Note: setUpOnRotaion method is called from willAnimateRotationToInterfaceOrientation and viewWillAppear with UIInterfaceOrientationIsPortrait(self.intefaceOrientation) and it does give me correct result. I have debugged.
In willAnimateRotationToInterfaceOrientation change cehck for orientation
if([uidevice orientaiton]statusbarorientation]){
self.naviogationite.rightbarbuttonitems = #[btn1,btn2,btn3];
}
else{
self.naviogationite.rightbarbuttonitems = #[abtn1,abtn2,abnt3];
}
u can do like this
can u do like this
NSMutableArray *itemsSet;
if(!toPortrait){
itemsSet = [NSMutableArray arrayWithObjects:in,
out,
searchItem,
searchActivityItem,
doneButton, nil];
}
if (toPortrait) {
itemsSet = [NSMutableArray arrayWithObjects:in,
out,
doneButton, nil];
}
I have a segmented controll with two cells defined programmatically. When I go into my app both cells perform the same action. The first should open a webpage in Safari, the second opens an image and covers the current view for 5 seconds. Any pointers?
In the .m file
#property UISegmentedControl *segment;
- (void)viewDidLoad
{
UISegmentedControl *segment = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Publication", #"About", nil]];
self.tableView.tableHeaderView = segment;
[segment addTarget:self action:#selector(segmentPressed:) forControlEvents:UIControlEventValueChanged];
[self.tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:#"UITableViewCell"];
}
- (void)segmentPressed:(id)sender {
if (_segment.selectedSegmentIndex ==0) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"******"]];
}else if(_segment.selectedSegmentIndex ==1){
UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)];
imageView.backgroundColor = [UIColor redColor];
[imageView setImage: [UIImage imageNamed:#"MACSLoad#2x.png"]];
[self.view addSubview: imageView];
sleep(5);
imageView.hidden = YES;
}
}
You get that result because _segment is nil. You never assigned the segmented control you created to your property -- you assigned it to a local variable. So change this line,
UISegmentedControl *segment = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Publication", #"About", nil]];
to,
self.segment = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Publication", #"About", nil]];
Another way to do it, would be to get rid of the property all together, leave the code in viewDidLoad as it is, and change this,
- (void)segmentPressed:(id)sender {
if (_segment.selectedSegmentIndex ==0) {
to this,
- (void)segmentPressed:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex ==0) {
Unless you need to access the segmented control outside of its action method, there's no reason to create the property. It's better in any case to use the sender argument rather than a property (even if you have one) inside the action method.
I am programmatically adding a UISegmentedControl to a UINavigationController's toolbar (I am in a UITableViewController). I want the segmented control to look decent, not filling the entire bar. Also, I want it to rotate with the view and resize. This should be pretty easy but I think I'm missing something. I actually got it to work, but this is not clean code so I am hoping someone can tell me which settings/methods to use for a "proper" implementation.
Getter:
- (UISegmentedControl*)stockFilterSegmentedControl {
if (!_stockFilterSegmentedControl) {
_stockFilterSegmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"All",#"Holdings", nil]];
[_stockFilterSegmentedControl addTarget:self action:#selector(stockFilterControlPressed:) forControlEvents:UIControlEventValueChanged];
_stockFilterSegmentedControl.selectedSegmentIndex = 0;
_stockFilterSegmentedControl.autoresizingMask = UIViewAutoresizingFlexibleHeight;
CGRect newFrame = _stockFilterSegmentedControl.frame;
newFrame.size.height = self.navigationController.toolbar.frame.size.height * .8;
_stockFilterSegmentedControl.frame = newFrame;
}
return _stockFilterSegmentedControl;
}
Where we insert it:
- (NSArray*)navFooterToolbarArray {
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.stockFilterSegmentedControl];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *refresh = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(refresh:)];
return [NSArray arrayWithObjects:flexibleSpace, barButtonItem, flexibleSpace, refresh, nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Stocks";
self.toolbarItems = [self navFooterToolbarArray];
}
And to make it work I had to add:
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
NSLog(#"Did autorotate.");
CGRect newFrame = self.stockFilterSegmentedControl.frame;
newFrame.size.height = self.navigationController.toolbar.frame.size.height * .8;
self.stockFilterSegmentedControl.frame = newFrame;
}
What's the right way to do this?
Thanks,
Damien
The answer is actually really simple - you set the segmentedControlStyle on the segmented control to UISegmentedControlStyleBar and it will resize perfectly without any drama. Autoresizing masks work as expected.
Thanks,
Damien
All you should really need is something like:
_stockFilterSegmentedControl.frame = CGRectInset(self.navigationController.toolbar.bounds, 5, 5); //set to toolbar rect inset by 5 pixels
_stockFilterSegmentedControl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
You then won't have to do anything when the view rotates, it should just automatically resize to fit because of the autoresizingMask.
How can I change the title of a UIBarButtonItem? I have the following code which is called when an edit button is pressed on my UINavigationBar.
-(void)editButtonSelected:(id)sender {
NSLog(#"edit button selected!");
if(editing) {
NSLog(#"notediting");
[super setEditing:NO animated:NO];
[tableView setEditing:NO animated:NO];
[tableView reloadData];
[rightButtonItem setTitle:#"Edit"];
[rightButtonItem setStyle:UIBarButtonItemStylePlain];
editing = false;
}
else {
NSLog(#"editing");
[super setEditing:YES animated:YES];
[tableView setEditing:YES animated:YES];
[tableView reloadData];
[rightButtonItem setTitle:#"Done"];
[rightButtonItem setStyle:UIBarButtonItemStyleDone];
editing = true;
}
}
The edit button is changing color (so the line which sets the style is working), however the line which sets the title of the button is not working.
I've done the following to dynamically change the title of a UIBarButtonItem. In this situation I am not using a UIViewTableController and cannot use the standard editButton. I have a view with a tableView as well as other subviews and wanted to emulate the behavior of the limited UIViewTableController.
- (void)InitializeNavigationItem
{
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:2];
UIBarButtonItem* barButton;
barButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(addNewItem:)];
barButton.style = UIBarButtonItemStyleBordered;
[array addObject:barButton];
// --------------------------------------------------------------------------------------
barButton = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStyleBordered
target:self
action:#selector(editMode:)];
barButton.style = UIBarButtonItemStyleBordered;
barButton.possibleTitles = [NSSet setWithObjects:#"Edit", #"Done", nil];
[array addObject:barButton];
self.navigationItem.rightBarButtonItems = array;
}
- (IBAction)editMode:(UIBarButtonItem *)sender
{
if (self.orderTable.editing)
{
sender.title = #"Edit";
[self.orderTable setEditing:NO animated:YES];
}
else
{
sender.title = #"Done";
[self.orderTable setEditing:YES animated:YES];
}
}
Note that I didn't use the the UIBarButtonSystemItemEdit barButton, you cannot manually change the name of that button, which makes sense.
You also might want to take advantage of the possibleTitles property so that the button doesn't resize when you change the title.
If you are using a Storyboard/XIB to create/set these buttons, ensure that the Bar Button Item Identifier is set to Custom for the button which you'd want to control the title for.
I had this problem and resolved it by setting the UIBarButtonItem style to the custom type when it's initialised. Then the titles would set when changing their title values.
You may also want to set the possibleTitle value in the viewDidLoad method to ensure the button is sized correctly for all the possible titles it can have.
In my case what prevented the title being displayed was that in the xib I'd selected the Bar button item 'identifier' property as 'Cancel'.
I tried setting the title property even before assigning the button to the navigation bar, but the title was not being updated.
I made it like this:
And it started working just as I wanted.
If you look at the documentation of the title property, it is explicitly mentioned that you should set it before assigning it to the navigation bar. Instead of doing what you're doing right now, you can use two bar button items – one for done and one for edit, and set them alternatively.
Actually if all you want if switching between "Edit" and "Done", just use
self.navigationItem.rightBarButtonItem = self.editButtonItem;
It will handle this transition for you
Just switch out the buttons each time the user presses them.
- (void)setNavigationButtonAsEdit
{
UIBarButtonItem* editButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Edit", #"")
style:UIBarButtonItemStylePlain
target:self
action:#selector(editButtonPressed:)];
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObject:editButton];
}
- (void)setNavigationButtonAsDone
{
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Done", #"")
style:UIBarButtonItemStylePlain
target:self
action:#selector(editButtonPressed:)];
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObject:doneButton];
}
And then create an IBAction to handle the button press:
- (IBAction)editButtonPressed:(id)sender
{
NSString* buttonText = [sender title];
if ([buttonText isEqualToString:NSLocalizedString(#"Edit",#"")])
{
[self setNavigationButtonAsDone];
}
else
{
[self setNavigationButtonAsEdit];
}
}
Swift 3.0, 3.2, or 4.0
If your custom ViewController containing a tableView object follows the UITableViewController Delegate and Datasource protocols, you can append a system editBarButtonItem to your navigationItem.leftBarButtonItem(s) or navigationItem.rightBarButtonItem(s) with the following code:
func setupTableView() {
tableView.delegate = self
tableView.dataSource = self
navigationItem.rightBarButtonItem = editButtonItem
editButtonItem.action = #selector(CustomViewController.editTableView(_:))
}
#objc func editTableView(_ sender: UIBarButtonItem) {
tableView.isEditing = !tableView.isEditing
if tableView.isEditing {
sender.title = "Done"
} else {
sender.title = "Edit"
}
}
Try:
UIButton *rightButton;
rightButton = (UIButton*)self.navigationItem.rightBarButtonItem.customView;
[rightButton setTitle:#"Done" forState:UIControlStateNormal];
Because rightBarButtonItem.customView == “the button your added”.