pageControl in navigationBar not centered - ios

i've added a pageControl to the titleView using the interface builder. The problem is that it is not centered at all. I could actually just do a lot of white spaces after the leftBarButton text, but it is not ideal. What would be the solution?

Instead of adding your pagecontroller from Storyboard try doing this
pageControl = [[UIPageControl alloc] init];
pageControl.frame = CGRectMake(x, y, xx, yy);
pageControl.numberOfPages = 2;
pageControl.currentPage = 0;
self.navigationItem.titleView = pageControl;

I came across this post while looking for an answer for the exact problem. I ended up solving it by adding UIPageControl inside an UIView and set the proper constraints to center itself inside the UIView. You can do this in storyboard easily and add this UIView to titleView. Hope this helps.

The title view is centered automatically (if it's possible), so it's probably being pushed to the left by the right bar button item. You should add a background color to your title view for debugging purposes, so you can see if this is true. If that's the problem, you need to make your titleView smaller so it doesn't run into either button.
The other possibility (which you could see if you had a background color) is that the page control is not centered in the titleView. If that's the problem, you need to add a centerX constraint to the page control.

Related

Autolayout with Navigation Bar - Remove Specific Constraint

I'm building an application for iOS, which is using a navigation controller. I want to put a view in the titleView, and have it fill the whole width of the navigation bar.
I'm calling setupNavBar in viewDidLoad of the view controller that is embedded in the navigation controller. Here is how I do:
func setupNavBar() {
let navBar = navigationController?.navigationBar
// navBar!.translatesAutoresizingMaskIntoConstraints = false
// navBar!.frame.size.height = CGFloat(100)
let searchBar = UIView(frame: navBar!.frame)
searchBar.bounds = CGRectMake(0, 0, navBar!.frame.width, navBar!.frame.height)
searchBar.backgroundColor = UIColor.brownColor()
navigationItem.titleView = searchBar
}
But the view (brown - "searchBar"), doesn't cover the full navigation bar:
So I figured out that the problem was related to Autoresizing and Constraints, because if I call navBar!.translatesAutoresizingMaskIntoConstraints = false, I can freely set the sizes of views frame, so there must be some constraints that change the view's bounds. But I would like to keep as much of the autolayout behaviour as possible.
Is there a way to only change the contraints on the titleView?
I'm doing everything programmatically, I don't use the storyboard or xib's!
EDIT:
But it doesn't seem like there is any constraints on either navigationItem or navBar:
for someObject in navigationItem.titleView!.constraints {
print(someObject)
}
It doesn't print any constraints. neither if I use navBar.constraints!
EDIT 2:
I have a screenshot from "View UI Hierarchy" from the debug navigator:
It seems that the view(brown) alligns with the Navigation Bar Back Indicator View, maybe this is a clue to what causes the problem?
How come the view is resized?
Two different suggestions here:
1. You can try the
navigationItem.titleView.sizeToFit()
Otherwise you could set the background colour of the navbar to brown as it appears you wish the brown bar to cover the entire width of the navbar. If you want to add other views on top of that you then can.
You could also try to make an outlet to the title view and add an NSLayoutConstraint using
navigationItem.titleView.addConstraint(NSLayoutConstraint: NSLayoutConstraint)
I am not entirely sure whether that will work, however.

Empty white space above UITableView inside a UIView

I'm trying to position a TableView inside my ViewController view but leaving a 44 height gap between the bottom of the navigation bar and the top of the table. I then wanted to place a UITextField inside that gap to act as a stationary header. For some reason, the TableView has an empty white space above the start of the "Prototype Cells". Its just white space. Here is what it looks like in the storyboard.
When viewing the app display, this is what it looks like:
When scrolling the table, it goes all the way up to the correct place:
Try to look in the 'attribute inspector' (in the right menu) of the Participants ViewController.
Check for the option 'Extend Edges' and uncheck the 'Under Top Bars', and then relocate your tableview.
Another possible solution is to just uncheck the option 'Adjust Scroll View Insets'.
The reason is that when the viewController extends its edges, let's say under the top bar, the tableView's scrollView automatically adjusts its inset top, so that the content of the tableView will start exactly under the top bar. But in your case this is not needed, since your tableView itself starts under the bar.
Focus on the ViewController and got to the Attribute Inspector tab:
Try this one:
self.tableView.contentInset = UIEdgeInsetsMake(-65, 0, 0, 0)
Just add this in you ViewDidLoad method
self.automaticallyAdjustsScrollViewInsets = NO;
change your table view style from grouped to plain
You should not need to change the default setting for Extend Edges.
Looks like the real problem is a blank table header view in your storyboard. It's showing in the screenshot you provided of your storyboard, right below the Enter Name view and right above the Prototype Cells view. Delete it.
My issues is, I set tableHeaderView as new UIView like this
self.tableHeaderView = UIView(frame: .zero)
Remove this line, the issue is gone. Try this:
//self.tableHeaderView = UIView(frame: .zero)
This is the 2022, iOS 15 solution if anyone stumbles upon this.
if #available(iOS 15.0, *) {
UITableView.appearance().sectionHeaderTopPadding = CGFloat(0)
}
I just found a solution for this.
In my case, i was using TabBarViewController, A just uncheck the option 'Adjust Scroll View Insets'. Issues goes away.
https://i.stack.imgur.com/qgQI8.png
For Objective-C folks, add this in your ViewDidLoad method.
[self.tableView setContentInset:UIEdgeInsetsMake(-20, 0, 0, 0)];

How to create and add UIButton with multiline label from code using autolayout?

There's are a lot of links how to size a label, however there's a lack of info how to resize UIButton according to its label size. Currently, I have screen view set with autolayout (all the system constraints are added from IB) and everything works fine, but need to add dynamic content at the bottom of the screen. I need to create and add random number of buttons with random length titles. So, here's code fragment for creating and adding the buttons:
// Loop
UIButton *myButton = [UIButton new];
UIButton.frame = CGRectMake(0, previousButtonOriginY, self.view.bounds.size.width, 20);
myButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
myButton.titleLabel.textAlignment = NSTextAlignmentLeft;
myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[myButton setTitle:#"very long title..." forState:UIControlStateNormal];
myButton.titleLabel.numberOfLines = 0;
[self.footerView addSubview:myButton];
The problem is the frame height of the button stays 20px but the label string is shown on three lines and so overlaps with the other button title. If I add [myButton sizeToFit] then button width is resized to fit all the text into one line and so the title goes beyond the screen.
If I add [myButton sizeThatFits:CGSizeMake(320, 100)] then resize is not working at all. I know sizeToFit should not be called at all because it's not the part of autolayout, however need suggestions on that how easily to make button fit its label to screen 320 width.
I feel I need to add system constraints from code, but haven't done that before, so not sure how it should look like. I probably need a ton of constraints to be added from code in order to get this simple thing working :)
Instead of using Autolayout, you could just use a collection view which better options for you to lay out elements such as buttons.
It is better able to handle layouts under rotation as well.
Or you can use this code, it worked for me...
For example, substitute your desired padding values here:
UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
-desiredRightPadding,
-desiredTopPadding,
-desiredLeftPadding);
Combined with the right autolayout constraints, you end up with an auto-resizing button which contains an image and text!
For this kind of customizations you'll need to create a subclass of UIButton. In the subclass you can add a customized label which benefits your needs. You can also override to setTitle:forState method to automatically update your customized label.

Screen bounds extends visible area

I'm trying to make a square (50 x 50) UIView in the lower right hand of my main view, but I'm confused about why it's not entirely visible. In this instance, only the tip of it is visible from the bottom. Am I confusing some concept?
CGFloat width = CGRectGetWidth(self.view.bounds);
CGFloat height = CGRectGetHeight(self.view.bounds);
UIView *transparentFloater = [[UIView alloc] initWithFrame:CGRectMake(width - 50.f, height - 50.0f, 50.0f, 50.0f)];
[self.view addSubview:transparentFloater];
Try to add the autoresizing mask:
transparentFloater.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
If I am not wrong, You have created your ViewController with xib and in the attributes of view, you have forgot to mention that you are using a "navigation bar" as "top bar".
Reason
So in ViewDidLoad, view in .xib with a height X is returned. But as you might have loaded the viewController using UINavigationController, after loading the height of view is decreased by 44pixels.
Suggestions :
1) Whenever you know that you are going to have navigation bar on top please mention it in .xib file as well.
For doing so click on the view in xib and select the option called topbar in attributes Inspector of utilities area
2) Call the following api
NSLog(#"In ViewDidAppear %#",NSStringFromCGRect(self.view.bounds));
in
viewDidLoad
viewDidAppear
to track whats happening with the bounds of view
You does not need to do anything just put
transparentFloater.backgroundColor = [UIColor redColor];
because your view (custom) is invisible (because your main view color and custom view color are same (white) ) may be. I tried your code in my demo project. it worked perfectly for me.

How do I get a UINavigationController to NOT change its view size when setting the translucent property?

I have an app where up until now I've been using a UINavigationController with a UINavigationBar that has its property translucent = YES. This means the UINavigationController's content view (i.e. the views from the view controllers you push) to be full-screen (minus status bar).
However, if you set the navigationBar.translucent = NO, this container view becomes 44pt shorter, as I suppose Apple has assumed you don't need any content under an opaque navigationBar.
... except if you're doing what we're doing and are employing a navigationBar that scrolls away (see This Post on how to do that) So I'd like to know if this is possible.
I want to have translucent = NO, but have everything behave as if it were still set to YES. I like the functionality of the translucent = YES, but I don't actually want the bar to be made translucent by UIKit.
What worked for me was to add
extendedLayoutIncludesOpaqueBars = true
in
viewDidLoad
something like this
override func viewDidLoad() {
super.viewDidLoad()
extendedLayoutIncludesOpaqueBars = true
}
Hope it will work for you as well
It's not necessarily a good answer but you could just offset your view that high if you're not translucent.
//This won't take into account orientation and probably other details
if(!self.navigationController.navigationBar.isTranslucent)
{
self.view.frame = CGRectMake(0,0,-44,self.view.bounds.size.height);
}
You could put that in your viewDidLoad or viewWillAppear and if you have a bunch of view controllers you can just subclass them all and put your logic in the subclass.
I found a solution that works, although it is indeed a bit of a hack.
The idea is to give the translucent nav bar an opaque backing. Unfortunately I'm not happy with the solution in that it's dirty and not encapsulated and introduces some potential issues, but i AM happy because it got the job done.
In my Application's base view controller class (i.e. MyViewController : UIViewController), in the viewDidLoad method, I instantiate a new ivar UIView *_navigationBarBG and give it the same frame as self.navigationController.navigationBar. I then set it's backgroundColor property to [UIColor whiteColor] although this is how you achieve some more tint I guess. [EDIT:If you wanted to be a purist (color values remaining exactly as they come from the .psd), you could make the _navigationBarBG a UIImageView and use your custom background there, and the background of the actual UINavigationBar you set to draw clear (or stretch a 1px transparent image if you wanted to use a typical 'change your navigation bar using an image' recipe that's somewhere on the internet)]
if(self.navigationController)
{
_navigationBarBG = [[UIView alloc] initWithFrame: self.navigationController.navigationBar.frame];
_navigationBarBG.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_navigationBarBG];
}
THEN, (and this is the crappy part, but I don't see any other way), I add this view as a subview. BUT, whenever you would normally make a call to [self.view addSubview: anyView], you have to make sure you call [self.view insertSubview: anyView belowSubview: _navigationBarBG];
if (_navigationBarBG)
[self.view insertSubview: anyView belowSubview:_navigationBarBG];
else
[self.view addSubview: anyView];
If you forget that, these added views will slide under your navbar background and look weird. So you need to know that this is a source of error.
WHY AM I DOING THIS? Again you might ask... I want to be able to have a scrolling navigation bar that scrolls out of the way when you scroll down your table view, thereby giving the user more screen space. This is done by using the scrollView delegate (scrollViewDidScroll:) and also viewWillAppear:
// FIRST DEAL WITH SCROLLING NAVIGATION BAR
CALayer *layer = self.navigationController.navigationBar.layer;
CGFloat contentOffsetY = scrollView.contentOffset.y;
CGPoint newPosition;
if (contentOffsetY > _scrollViewContentOffsetYThreshold && self.scrollingNavigationBarEnabled) {
newPosition = CGPointMake(layer.position.x,
22 - MIN((contentOffsetY - _scrollViewContentOffsetYThreshold), 48.0)); // my nav bar BG image is 48.0 tall
layer.position = newPosition;
[_navigationBarBG setCenter: newPosition]; // if it's nil, nothing happens
}
else
{
newPosition = kNavBarDefaultPosition; // i.e. CGPointMake(160, 22) -- portrait only
layer.position = newPosition;
[_navigationBarBG setCenter: newPosition]; // if it's nil, nothing happens
}
I was looking for an answer to this as I wanted my subviews to be at (0,0) and not (0,44)(in reference to the Screen bounds), but I could not find an answer on how to set this in the NavigationController, which I thought would be an included property.
What I ended up doing that was very simple is adding a subview to the navigation controller that was the width and height of the Navigation Bar, but then insert the subview below the Navigation Bar.
Now the setting is Translucent = YES, but it still appears solid and the subviews behave how I want.
EDIT: After re-reading your original post, I suppose if you're going to be rolling the nav bar away, you'll have to take into account hiding and showing the new subview as you do the same with the nav bar

Resources