iOS11: UIBarButtonItem with custom view not resizing on rotation - iphone

I have this:
And the icons get all out of wack when I rotate (they don't resize and reposition like they did in <11):
This is how I'm implementing the code. I set my UINavigationBars with UIBarButtonItem with custom image as follows:
- (void) loadNavigationBarButton:(UIBarButtonItem*)navigationBarButton withSpacerWidth:(CGFloat)spacerWidth barButtonDirection:(CGFloat)barButtonDirection
{
NSArray* items = #[navigationBarButton];
if (barButtonDirection == 0)
{
[self.navigationItem setLeftBarButtonItems:items animated:NO];
}
else
{
[self.navigationItem setRightBarButtonItems:items animated:NO];
}
}
And this is how I initialize one of the UIBarButtonItems:
- (void) loadDefaultRightButton
{
ButtonView *rightButtonView = [[ButtonView alloc] initWithFrame:CGRectMake(0, 0, 60.71090047393365, 44) image:[[[NextButtonIcon alloc] initWithHighlight:NO] imageForSize:CGSizeMake(60.71090047393365, 44)] highlightFrame:CGRectMake(0, 0, 60.71090047393365, 44) highlightImage:[[[NextButtonIcon alloc] initWithHighlight:YES] imageForSize:CGSizeMake(60.71090047393365, 44)] highlightOnTop:YES buttonViewType:ButtonViewTypeNext roundedCorners:NO enableDisabledView: NO doubleTap:NO singleTapGestureRecognizer:nil];
rightButtonView.delegate = self;
[rightButtonView.widthAnchor constraintEqualToConstant: 60.71090047393365].active = YES;
[rightButtonView.heightAnchor constraintEqualToConstant: 44].active = YES;
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithCustomView:rightButtonView];
[self loadNavigationBarButton:rightButton withSpacerWidth:21 barButtonDirection:1];
}
For some reason now, when I rotate to landscape, but UIBarButtonItems don't resize themselves like they used to. They stay big and overflow off the screen. Does anyone know why this is happening? My UIViewControllers take up the full screen fwiw.
UPDATE: Added images and other clarifying comments.

Related

How to design an iOS program with custom inputViews

Note, this is a DESIGN question, NOT a functionality question. I already know how to implement the following, I'm just trying to figure out the best way to design it.
I have an iOS app where a few UIViewControllers throughout the app have UITextFields with UIDatePicker input views. The code for this is below:
- (void) viewDidLoad
{
self.dateField.inputView = [self createDatePicker];
}
- (UIView *) createDatePicker
{
UIView *pickerView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, TOOLBAR_HEIGHT + KEYBOARD_HEIGHT)];
UIDatePicker *picker = [[UIDatePicker alloc] init];
[picker sizeToFit];
picker.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
picker.datePickerMode = UIDatePickerModeDate;
[picker addTarget:self action:#selector(updateDateField:) forControlEvents:UIControlEventValueChanged];
[pickerView addSubview:picker];
// Create done button
UIToolbar* toolBar = [[UIToolbar alloc] init];
toolBar.barStyle = UIBarStyleBlackTranslucent;
toolBar.translucent = YES;
toolBar.tintColor = nil;
[toolBar sizeToFit];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleDone target:self
action:#selector(doneUsingPicker)];
[toolBar setItems:[NSArray arrayWithObjects:flexibleSpace, doneButton, nil]];
[pickerView addSubview:toolBar];
picker.frame = CGRectMake(0, toolBar.frame.size.height, self.view.frame.size.width, pickerView.frame.size.height - TOOLBAR_HEIGHT);
toolBar.frame = CGRectMake(0, 0, self.view.frame.size.width, TOOLBAR_HEIGHT);
return pickerView;
}
- (void) doneUsingPicker
{
[self.dateField resignFirstResponder];
}
- (void) updateDateField: (UIDatePicker *) datePicker
{
self.dateField.text = [self.formatter stringFromDate:datePicker.date];
}
The problem is, I keep on having to paste this code throughout the app in different classes that have UITextFields with UIDatePicker inputviews. What would be the best way to design this so as to minimize duplicated code. I've thought about having a UIDatePickerableViewController superclass that contains this code, but this doesn't seem extensible. For instance, what if I soon have other types of input views that could be attached to text fields. How should I design this?
You can refactor code/methods shared between the classes in a common superclass, and inherit subclasses inside which you only modify the parts that are needed to be different.
Or, if you approach the problem from a different point of view: create a custom InputWiewWithDatePicker class and move the (self-)configuration and -initialization code inside the - init method of that class. This way you don't have to paste all this everywhere, and only a single line will be duplicated:
customControl = [[InputViewWithDatePicker alloc] init];
My first thought would be to create a new UIView subclass that contains a date picker and text field with the layout you desire. This can be done with a nib or in code. Anyplace you want to add this new kind of view, it's either a one-liner in viewDidLoad, or paint a UIView into a nib and change it's class to your new view class.
Subclass your desired layout, then when you allocate it, it will come with all the options you have defined.

Need Help Setting Up UISegmentedControl

I have a view that has a UISegmentedControl in its bottom UIToolBar with 2 segments. The view when loaded should default to view 1. Then when segment 2 is selected, it should switch to view 2, etc.
Right now, when I click segment 2, it hides the view 1, then switches to the 2nd view, but how do I keep the segmentedControl displayed? When view 1 is hidden, the control is hidden as well.
Do I need to create 3 views total? And have views 1 and 2 as subviews of the default view that only has the segmented control in it?
EDIT:
- (void)segmentedControl:(SVSegmentedControl*)segmentedControl didSelectIndex:(NSUInteger)index
{
LogResultsViewController* v1 = [[LogResultsViewController alloc] initWithNibName: #"LogResultsViewController" bundle:nil];
CalendarController* v2 = [[CalendarController alloc] initWithNibName: #"CalendarController" bundle:nil];
if (index == 0)
{
[self.view addSubview: v1.view];
}
else
{
[self.view addSubview: v2.view];
}
}
And this is the code used to load this view:
- (void)loadView
{
UIBarButtonItem *actionButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(dismissCalendarView)];
self.navigationItem.leftBarButtonItem = actionButton;
[actionButton release];
int statusBarHeight = 20;
CGRect applicationFrame = (CGRect)[[UIScreen mainScreen] applicationFrame];
self.view = [[[UIView alloc] initWithFrame:CGRectMake(0, statusBarHeight, applicationFrame.size.width, applicationFrame.size.height)] autorelease];
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.view.backgroundColor = [UIColor grayColor];
calendar.frame = CGRectMake(0, 0, calendar.frame.size.width, calendar.frame.size.height);
[self.view addSubview:calendar];
[calendar reload];
}
Yes, you seem to have solved your own problem. Your two swappable views need to be inside of a third view. If not, your switching control will be hidden when the parent view is hidden.
Yes, that's exactly what you need to do. Set up a container view that holds the toolbar and the other views. Then add and remove the other two views as subviews of the container view as needed.

How do I add a button on right side of the toolbar in a UISplitViewController?

Trying to add a button to the right side of the toolbar of the detailviewcontroller in a split-view based app. I used flexible space to get it to the right side. In portrait it works fine, but in landscape (when the menu button disappears), the button gets moved so that half of it is off the screen.
Here's the relevant code (in DetailViewController.m):
- (void) viewDidLoad
{
// initialize toolbar
toolbar = [[UIToolbar alloc] initWithFrame: CGRectMake( 0, 0, 768, 44 )];
titleLabel = [[UILabel alloc] initWithFrame: CGRectMake( 284, 3, 200, 35 )];
titleLabel.text = #"Title & Location";
titleLabel.textAlignment = UITextAlignmentCenter;
[toolbar addSubview: titleLabel];
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemFlexibleSpace target: nil action: nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle: #"Add Event" style: UIBarButtonItemStyleDone target: rootController action: #selector(parseDone)];
NSArray *buttonArray = [NSArray arrayWithObjects: flexibleSpace, doneButton, nil];
[toolbar setItems: buttonArray];
[doneButton release];
[flexibleSpace release];
[self.view addSubview: toolbar];
}
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
{
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray insertObject: barButtonItem atIndex: 0];
[toolbar setItems:itemsArray animated:NO];
}
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
{
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray removeObject:barButtonItem];
[toolbar setItems:itemsArray animated:NO];
[itemsArray release];
}
I recognize this problem from a project I worked on a while back. I think it only happened occasionally and I don't remember if we actually fixed it.
In your case it seems like it would be easier to just use the navigation bar and set rightBarButtonItem and leftBarButtonItem. That should solve your problem.
In fact, if you put your view controller in a UINavigationController you get the UINavigationBar and all the functionality of the navigation controller, if you choose to use it.
Well the problem was that I wasn't correctly resizing the toolbar when the iPad rotates to landscape mode. Fixed the problem by add this code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if( interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight ) {
[toolbar setFrame: CGRectMake( 0, 0, 700, 44 )];
}
else {
[toolbar setFrame: CGRectMake( 0, 0, 768, 44 )];
}
return YES;
}

Best Practice to Float a View over Another View?

I have a 320x460 view with a number of buttons, depending on the button pressed, a 280x280 view pops up over the 320x460 view (similar to the behavior of the UIAlertView) using code like this:
UIView *overlayView = [[UIView alloc] initWithFrame:CGRectMake(20, 200, 280, 280)];
overlayView.backgroundColor = [UIColor whiteColor];
[overlayView autorelease];
[overlayView addSubview:label]; // label declared elsewhere
[overlayView addSubview:backgroundImage]; // backgroundImage declared elsewhere
//... Add a bunch of other controls
[label release];
[backgroundImage release];
//... Release a bunch of other controls
[self.view addSubview:overlayView];
Everything works fine displaying the overlayView and all its controls.
The question I have is, how do I get rid of the overlayView once it's displayed? I want to make it not only not visible but to remove it completely, since the user will be popping up the overlayView repeatedly during use.
You need access to overlayView to remove it, I'd suggest adding this to the create side:
overlayView.tag = 5; // Or some other non-zero number
Then later you can use it like this:
-(void)removeOverlayView
{
UIView *overlayView = [self.view viewWithTag:5];
[overlayView removeFromSuperview];
}

Why does my UIToolBar scroll with my UITableView?

I'm having a bit of difficulty trying to build my view. Everything works out great up to the point where I need to insert a UIToolBar into my view. The tableView is placed where I expected it to be placed. The UIToolBar on the other hand, scrolls up and down with the table, it doesn't remain fixed as it should. It also looks rather odd when put on the screen -- I'm guessing because the calculation to place it isn't right? Attached to this question is a screenshot as well as the code I've used to build this. Thanks for your help in spotting out what I'm doing incorrect. Screenshot: http://dl-web.dropbox.com/u/57676/screenshots/broketoolbar.png
The code:
- (void)loadView
{
[super loadView];
// TableViews that wish to utilize tableView footers/headers should override this method.
UITableView *aTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
aTableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight);
aTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
aTableView.delegate = self;
aTableView.dataSource = dataSource;
self.tableView = aTableView;
self.view = tableView;
[aTableView release];
UIToolbar *toolbar = [UIToolbar new];
[toolbar setBarStyle:UIBarStyleBlackOpaque];
[toolbar sizeToFit];
CGFloat toolbarHeight = [toolbar frame].size.height;
CGRect mainViewBounds = self.view.bounds;
[toolbar setFrame:CGRectMake(CGRectGetMinX(mainViewBounds),
CGRectGetMinY(mainViewBounds) + CGRectGetHeight(mainViewBounds) - (toolbarHeight * 2.0),
CGRectGetWidth(mainViewBounds),
toolbarHeight)];
[self.view insertSubview:toolbar aboveSubview:self.tableView];
[toolbar release];
}
because self.view is tableView onto which you added toolbar.