I'm adding a UIToolbar to the bottom of my UIViewController.
- (void)viewDidLoad {
[super viewDidLoad];
self.toolbar = [[UIToolbar alloc] init];
[self.view addSubview:self.toolbar];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIEdgeInsets safeInsets = self.view.safeAreaInsets;
self.toolbar.frame = CGRectMake(0, self.view.frame.size.height-(49.0f+safeInsets.bottom), self.view.frame.size.width, (49.0f+safeInsets.bottom));
}
This gives the UIToolbar the correct height. However, what happens on iPhone X is that the items are vertically centered in the toolbar, resulting in a pretty weird look.
Is there any way to move them to the top? Or should I use the safe area of the iPhone X in a different way?
Related
I have a class inherit from UINavigationBar and I want to add a separator line as its subview to separate the navigation bar and the navigation content.
The line's height is defined as following.
#define SEPERATOR_LINE_HEIGHT (1.0f / [UIScreen mainScreen].scale)
My code:
#interface MyPopNavigationBar : UINavigationBar
#end
#implementation MyPopNavigationBar {
UIView *separatorLine;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.clipsToBounds = YES;
self.translucent = NO;
separatorLine = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.bounds) - SEPERATOR_LINE_HEIGHT, CGRectGetWidth(self.bounds), SEPERATOR_LINE_HEIGHT)];
separatorLine.backgroundColor = [UIColor redColor];
separatorLine.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
[self addSubview:separatorLine];
}
return self;
}
This works well in both iOS 6 and iOS 8 (all Retina), but I can't see my separatorLine in iOS 7 (Retina, too)!
iOS 6 & 8:
iOS 7:
Besides, when I tried to set the separator line height to exact 1, it shows in all iOS versions.
separatorLine = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.bounds) - 1, CGRectGetWidth(self.bounds), 1)];
What's wrong?
Solved this by myself. It's the autoresizingMask's fault 😂. I strongly suspect this a bug of iOS7.
I print the recursiveDescription in lldb, only to find the height of separatorLine is autoresized to zero in iOS7! In contrast, the value is 0.5 in iOS8.
So, remove this line:
separatorLine.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
And set the frame in layoutSubviews method of MyPopNavigationBar again to make it correct:
- (void)layoutSubviews {
[super layoutSubviews];
separatorLine.frame = CGRectMake(0, CGRectGetHeight(self.bounds) - SEPERATOR_LINE_HEIGHT, CGRectGetWidth(self.bounds), SEPERATOR_LINE_HEIGHT);
}
Then the line displays in all iOS versions.
I have a subclass of UIScrollView and I am trying to add it to my view. For some reason when I add it in the viewDidLoad it works as expected. But when I try adding it in the viewWillAppear then it seems to change the contentSize (although when I print the contentSize it is 905 in either case)
This works as expected:
- (void)viewDidLoad
{
[super viewDidLoad];
diptic = [[DipticView alloc] initWithFrame:self.view.frame];
diptic.item = self.item;
[self.view addSubview:diptic];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
}
This cuts off the scrollView (both views are scrolled down all the way.)
- (void)viewDidLoad
{
[super viewDidLoad];
diptic = [[DipticView alloc] initWithFrame:self.view.frame];
diptic.item = self.item;
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.view addSubview:diptic];
}
Any ideas on why this might be happening?
EDIT:
I think the frame is being reset somewhere because if I do :
diptic = [[DipticView alloc] initWithFrame:CGRectMake(0, 0, 320, 200)];
I get the same results...
I’m adding a UISegmentedControl right under the NavigationBar in a UITableViewController. This is the code.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationBar = self.navigationController.navigationBar;
UIView *segmentView=[[UIView alloc] initWithFrame:CGRectMake(0, self.navigationBar.frame.size.height, self.navigationBar.frame.size.width, 50)];
[segmentView setBackgroundColor:[UIColor whiteColor]];
segmentView.alpha = 0.95;
self.tabSegmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Favourites", #"All", nil]];
self.tabSegmentedControl.frame = CGRectMake(20, 10, self.navigationBar.frame.size.width - 40, 30);
[self.tabSegmentedControl addTarget:self action:#selector(tabChanged:) forControlEvents:UIControlEventValueChanged];
[segmentView addSubview:self.tabSegmentedControl];
[self.navigationBar addSubview:segmentView];
[self.tabSegmentedControl setSelectedSegmentIndex:1];
}
The view and the SegmentedControl appear on the screen well, but they are not clickable. The selector doesn’t get executed when tapped on the SegmentControl; it doesn’t even switch tabs! In fact, the stuff that is underneath the segmentView (items in the TableView) get clicked when you tap on it. I have tried but failed to understand why this is happening! Any suggestions would be helpful!
You are adding a view below the bounds of its super view. You may see the view however you cannot click it because it is out of bounds. If you set the property of the navigation bar clipsToBounds to YES you should see that the view disappears. What you need to do is add the segment controller to the table view. Here is an example:
- (void)viewDidLoad
{
[super viewDidLoad];
...
[self.view addSubview: self.segmentView]; // need to keep a pointer to segmentView
self.tableView.contentInset = UIEdgeInset(self.segmentView.frame.size.height, 0,0,0);
}
-(void) scrollViewDidScroll:(UIScrollView*) scrollView{
CGRect rect = self.segmentView.frame;
rect.origin = self.tableView.contentOffset;
self.segmentView.frame = rect;
}
I am creating an app using iOS 5, and I want to work as follows:
MainViewController w/ NavigationBar, and i set on viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
NavViewController *nav = [[NavViewController alloc] init];
[self addChildViewController:nav];
[self.view addSubview:nav.view];
}
Like a "partial view" with some nav controls (my own/custom toolbar), and at NavViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect viewRect = CGRectMake(0, 0, 320, 200);
self.view.frame = viewRect;
self.view.backgroundColor = [UIColor redColor];
}
At this point I have MainViewController with a navigation subview and still have space (in MainViewController view) that another subview can be added using the actions NavViewController.
Is there a serious flaw in this logic? or I can keep developing ?
Thnks a lot.
I'm attaching a UIToolbar to my UITextView as its inputAccessoryView in order to add a button to dismiss the keyboard. This works great and it looks correct when the device is in portrait mode. But I'm having trouble figuring out how to resize the toolbar to the lower height used for toolbars when the device is in landscape mode.
I'm adding the toolbar in my text view's delegate's -textViewShouldBeginEditing: method:
if (!textView.inputAccessoryView) {
UIToolbar *keyboardBar = [[UIToolbar alloc] init];
keyboardBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
keyboardBar.barStyle = UIBarStyleBlackTranslucent;
UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissKeyboard:)];
[keyboardBar setItems:[NSArray arrayWithObjects:spaceItem, doneButton, nil]];
[spaceItem release];
[doneButton release];
[keyboardBar sizeToFit];
textView.inputAccessoryView = keyboardBar;
[keyboardBar release];
}
I get strange behavior from this code in landscape mode, though. If I start editing in landscape mode, the toolbar has the landscape height but the Done button is drawn half off the screen. If I then rotate to Portrait mode, the Done button is drawn in the correct location, and it remains in the correct location when I rotate back to landscape mode.
If I start editing in portrait mode, the toolbar is drawn with portrait height, but the Done button is drawn in the correct location. If I then rotate to landscape mode, the toolbar remains portrait height, but the Done button is still drawn in the correct position at least.
Any suggestions for how to get this to resize when the device rotates? I'm really hoping there's a more automatic way than manually plugging in the height magic numbers in one of the view controller's rotation events.
That's a tough problem. I've solved this in the past by adjusting the frame when the accessory view gets laid out after rotating. Try something like this:
#interface RotatingTextInputToolbar : UIToolbar
#end
#implementation RotatingTextInputToolbar
- (void) layoutSubviews
{
[super layoutSubviews];
CGRect origFrame = self.frame;
[self sizeToFit];
CGRect newFrame = self.frame;
newFrame.origin.y += origFrame.size.height - newFrame.size.height;
self.frame = newFrame;
}
#end
And using the the RotatingTextInputToolbar instead of the UIToolbar in your code, above.
Voila:
#interface AccessoryToolbar : UIToolbar #end
#implementation AccessoryToolbar
-(id)init
{
if (self = [super init])
{
[self updateSize];
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(orientationDidChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:NULL];
}
return self;
}
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
-(void)orientationDidChange:(NSNotification*)notification
{
[self updateSize];
}
-(void)updateSize
{
bool landscape = UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
CGSize size = UIScreen.mainScreen.bounds.size;
if (landscape != size.width > size.height)
std::swap(size.width, size.height);
if (size.height <= 320)
size.height = 32;
else
size.height = 44;
self.frame = CGRectMake(0, 0, size.width, size.height);
}
#end