UIBarButtonSystemItem.FixedSpace for nav bar padding not working - ios

i'm attempting to add a done button to my nav bar (built directly UINavigationBar not with a controller). The done button appears fine, the action works, but it has no padding from the edge of the nav bar.
i tried adding a second bar button item with fixed space but it has no effect.
what's even weirder to me is that when i tried adding the button twice [rightButton,rightButton]
it made space for 2 buttons but only the first one showed up the second one didn't actually appear.
thanks for you help i've attached some code and photos for reference.
let rightButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: "doneAction:")
let rightButtonPadding = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
rightButtonPadding.width = 50
let items = UINavigationItem()
items.title = name.uppercaseString
items.rightBarButtonItems = [rightButton,rightButtonPadding]
items.hidesBackButton = true
navBar.pushNavigationItem(items, animated: false)

change the order to [rightButtonPadding ,rightButton]
From Documentation:
"Items are displayed right-to-left in the same order as they appear in
the array. Thus, the first item in the array is the rightmost item and
other items are added to the left of the previous item."

Try to play with UIBarButtonItemStyleDone/UIBarButtonItemStylePlain. Also please check this thread: iOS7 excessive navigationbar button padding

Related

Why does UIToolBar turn transparent/translucent when table view scrolls under it

I have a UITableViewController and when the user taps an "edit" button, I display a toolbar at the bottom of the screen. I create a shadow on top of the toolbar. It looks great (until I changed the color to make it more obvious shat's going wrong). When I scroll the table up, as soon as the bottom of the table comes out from behind the toolbar, the toolbar colors all become transparent or do something that looks transparent.
Here is a picture of the screen when the table has data that flows under the toolbar:
Here is a picture of the screen as I drag the table up and the last item is only partly under the toolbar:
Finally, when I drag the table as fr up as I can and the last item is completely above the toolbar, I get this:
It is obvious that the toolbar background is changing opacity as the table is scrolling. I need to disable this. I have tried various combinations of checking and unchecking the "under bottom bars" and "under opaque bars" in the storyboard. I have tried adding an empty footer and not adding an empty footer to the table. Here is the code that creates the toolbar. Note that I'm using a table view controller within a tab bar controller and hiding the tab bar when the user edits the table:
public func setEditingWithTabController( _ editing: Bool, animated: Bool, tabController: UITabBarController ) {
if navigationController == nil || navigationController!.toolbar == nil {
return
}
navigationController!.setToolbarHidden( !editing, animated: true )
var items = [UIBarButtonItem]()
let flexible = UIBarButtonItem( barButtonSystemItem: .flexibleSpace, target: self, action: nil )
deleteButton = UIBarButtonItem(title: Strings.Delete.localized, style: .plain, target: self, action: #selector(didPressDelete))
deleteAllButton = UIBarButtonItem(title: "Delete All", style: .plain, target: self, action: #selector(didPressDeleteAll))
items.append( deleteAllButton! )
items.append( flexible )
items.append( deleteButton! )
tabController.setToolbarItems( items, animated: false ) // toolbar gets its items form the current view controller
let bar = navigationController!.toolbar!
bar.backgroundColor = AppSettings.appBackgroundColor.isDark ? AppSettings.appBackgroundColor.lighten( amount: 0.05 ) : AppSettings.appBackgroundColor.darken( amount: 0.05 )
bar.barTintColor = AppSettings.appBackgroundColor.isDark ? AppSettings.appBackgroundColor.lighten( amount: 0.05 ) : AppSettings.appBackgroundColor.darken( amount: 0.05 )
bar.layer.shadowColor = UIColor.red.cgColor //AppSettings.appBackgroundColor.isDark ? UIColor.lightGray.cgColor : UIColor.lightGray.cgColor
bar.layer.shadowOpacity = AppSettings.appBackgroundColor.isDark ? 0 : 0.5
bar.layer.shadowOffset = CGSize.zero
bar.layer.shadowRadius = AppSettings.appBackgroundColor.isDark ? 0 : 20
bar.layer.borderColor = UIColor.clear.cgColor
bar.layer.borderWidth = 0
bar.clipsToBounds = false
bar.isTranslucent = false
bar.isOpaque = true
tableView.setEditing( editing, animated: true )
if editing {
refreshControl?.removeFromSuperview()
tableView.backgroundView = nil
} else {
refreshControl = UIRefreshControl()
refreshControl!.addTarget( self, action: #selector( refreshData(_:) ), for: .valueChanged )
tableView.backgroundView = refreshControl
}
}
This same thing happened before I added any of the shadow layer code but was much less obvious with the background simply changing from white to light gray when I scrolled the table.
The function above gets called when the user taps the "edit" button in the app header. Obviously I don't need to configure the toolbar every time this happens and especially when hiding it - I'll worry about fixing all of that later. I need to figure out why I can't get a clean unchanging toolbar. heck, I can't even seem to get rid of the gray line at the top of the toolbar even though I'm setting the border size to zero. This thing has a mind of its own!
[CORRECTION]...
I was not setting a background color. Now when I set a background color, I get the translucency only under the toolbar in the safe area inset like this:
In iOS 15, UIKit has extended the usage of the scrollEdgeAppearance, which by default produces a transparent background, to all navigation bars. The background is controlled by when your scroll view scrolls content behind the navigation bar. Your screenshots indicate that you are scrolled to the top, and so the navigation bar has selected its scrollEdgeAppearance over the standardAppearance that it would use when scrolled, and on previous versions of iOS.
To restore the old look, you must adopt the new UINavigationBar appearance APIs, UINavigationBarAppearance. Remove your existing customizations and do something like this:
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = <your tint color>
navigationBar.standardAppearance = appearance;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance
In the general case, it is the last line navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance, which resolves the issue by having the UINavigationBar use the same appearance for both its standard and edge states. Also note that this will cause the scroll view to underlap the navigation bar – we recommend against setting UINavigationBar.isTranslucent = true.
You can also use the appearance proxy with the code above, but substituting navigationBar.appearance().scrollEdgeAppearance = appearance for the last line (as you are constructing your own appearance object – the idea is to just make sure both scrollEdge and standard appearances are the same).
Credit: https://developer.apple.com/forums/thread/682420
Same can be achieved for Tabbar
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = <your tint color>
self.tabBarController?.tabBar.standardAppearance = appearance;
self.tabBarController?.tabBar.scrollEdgeAppearance = self.tabBarController?.tabBar.standardAppearance

How to change titleTextAttributes of UIBarButtonItem after it's pressed?

I have a navigation bar with several UIBarButtons that I initially display with an alpha of 0.5, and would like to display with an alpha of 1 after pressed. I am storing these attributes in normalAttributes and highlightedAttributes.
I set up the buttons in the following manner:
colorButton = UIBarButtonItem(title: "Colors", style: .plain, target: self, action: #selector(showColors))
colorButton.setTitleTextAttributes(normalAttributes, for: .normal)
colorButton.setTitleTextAttributes(highlightedAttributes, for: .selected)
This leads to the button briefly switching to the highlightedAttributes, which is expected. However, within the button's action showColors I then perform the following:
textButton.setTitleTextAttributes(highlightedAttributes, for:[])
I have also tried using .normal instead of []. Neither method seems to have any sort of effect on the button. Any help with this would be really appreciated.
The easiest way to accomplish this I can think of is using a custom view. Meaning, create a separate UIButton and make a reference to it in your class (e.g., let yourButton = UIButton()). Initialize your bar button item with UIBarButtonItem(customView: yourButton) and then use it however you want to.
Just note that you'll need to add your action/target pair on yourButton, not on the bar button item. Then in your action handler, showColors in your case, you can change the appearance of yourButton.
You can either toggle alpha directly or if it's just text we're talking about, you could do:
yourButton.setTitleColor(yourColor, for: .normal)
and
yourButton.setTitleColor(yourColorHalfAlpha, for: .selected).
Then in your showColors, just call yourButton.isSelected = !yourButton.isSelected to toggle the appearance.
A UIButton contains a UILabel as the titleLabel property. Just set its attributes the usual way instead of setting them via the button’s pass-through functions.

Swift 4 iOS 11 navigation bar back button is pushed by a title view with long text

For a long title on iOS 11, the back button arrow and text are not showing.
I searched for a solution and the closest I got was navigation bar rightbaritem image-button bug iOS 11
It looks like this
When it should look like this for long titles also
My problem though is that I don't have an explicit button added, instead the titleview pushes the "< Back" default leftBarButtonItem that I create:
navigationItem.backBarButtonItem = UIBarButtonItem(title: NSLocalizedString("Back", comment: ""), style: .plain, target: nil, action: nil)
How can I add constraints to that (UIBarButtonItem)?
I ended up lowering the compression resistance of the titleviews text, so the bar button items have higher priorities and everything fell in place.

Swift - Custom SearchController and SearchBar

I am trying to recreate the search field as seen in the Yahoo Finance app. I followed an online tutorial for customizing the UISearchBar and UISearchController, however I still have some problems. If any of you could open up my project and see where Im going wrong / where I need to add these lines with even one of these that would be really great.
My attempted solution project can be found here: https://github.com/jordanw421/yahoofinance
1) How to get the search bar active (with text to the left, and typing indicator blinking) as soon as view presents itself? In the link below, you can see what I am talking about, when the button is pressed the search view is loaded and the search bar is instantly active.
https://youtu.be/tRtXm-m1hX0
I tried using:
customSearchController.definesPresentationContext = true
customSearchController.isActive = true
customSearchController.searchBar.becomeFirstResponder()
but that didn't work. Should I be setting these in the initial view controller with prepareForSegue?
2) How to set the keyboard appearance (to dark), and to add a keyboard toolbar with a button?
I was able to get this working for a non-custom search bar, but for some reason these don't work now:
customSearchController.searchBar.keyboardAppearance = .dark
and
func addKeyboardButton() {
let keyboardToolbar = UIToolbar()
keyboardToolbar.sizeToFit()
keyboardToolbar.isTranslucent = false
keyboardToolbar.barTintColor = UIColor.blue
let addButton = UIButton(type: .custom)
addButton.frame = CGRect(x: keyboardToolbar.frame.size.width / 2, y: keyboardToolbar.frame.size.height / 2, width: 50, height: 30)
addButton.addTarget(self, action: #selector(clickMe), for: .touchUpInside)
let item = UIBarButtonItem(customView: addButton)
keyboardToolbar.items = [item]
customSearchController.searchBar.inputAccessoryView = keyboardToolbar
}
and calling,
addKeyboardButton()
in the search bar configure function.
3) How to prevent the search bar / table view header from scrolling, but still allow the tableView to scroll?
If you look at my attempted solution you can see that for some reason the tableview header scrolls with the table view. When I use a non-custom search bar the header remains static.
I know there are a lot of questions here, but I've been stuck on this for awhile and could really use some help. Thank you.

UIButton with template image receiving touch events only for non-transparent pixels

I have an iOS app written in Swift (2.1). I'm using a little workaround which I've found to make smaller margins between UIBarButtonItem's in NavigationBar. Here's my code:
let modeImage = UIImage(named: modeFilename)!.imageWithRenderingMode(.AlwaysTemplate)
modeButton = UIButton(frame: CGRectMake(0, 0, 22, 22))
modeButton.setBackgroundImage(modeImage, forState: .Normal)
modeButton.addTarget(self, action: Selector("modeClicked:"), forControlEvents:.TouchUpInside)
modeButton.transform = CGAffineTransformMakeTranslation(10, 0)
let modeButtonContainer = UIView(frame: modeButton.frame)
modeButtonContainer.addSubview(modeButton)
modeButtonItem = UIBarButtonItem(customView: modeButtonContainer)
Button works, but I have a square-like simple image and touch is only working on non-transparent pixels (or near them maybe). It's hard to hit it on simulator not to mention real device. It's a real pain. I've found solution to use Tap Gesture Recognizer on modeButtonContainer, but then button is not hovering so it's not a best solution.
Using setImage instead of setBackgroundImage doesn't change anything. Same goes for creating button with type UIButtonType.Custom.
Help!
Figured it out! My theory was wrong. It's not because of transparent pixels. Problem causes this line:
modeButton.transform = CGAffineTransformMakeTranslation(10, 0)
This caused button to be offsetted by 10 points instead being at center of its container. Button seemed looking good, but when I've set background to modeButtonContainer I realized button work only on containers area and doesn't work outside it.
So I needed to remove this line and instead use add this as first item in rightBarButtonItems:
let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
negativeSpacer.width = -10

Resources