I am trying to set different colors for different navigation bar large title states. For base large title state(when it's large and not scrolled) bar should have grayColor(i am setting barTint color), but when the user scrolls content and bar is attached to top(goes to UIBarPosition.topAttached) it should have white color, so I am setting background image for .topAttached state, and because of that image my barTint color is ignored.
I've tried to set background image for all possible nav bar UIBarPosition's and UIBarMetrics, and for topAttached state image work's well, but for large state it never appeared. Example:
bar.setBackgroundImage(.pixel(color: UIColor.red), for: .any, barMetrics: .default)
bar.setBackgroundImage(.pixel(color: UIColor.green), for: .topAttached, barMetrics: .default)
bar.setBackgroundImage(.pixel(color: UIColor.blue), for: .bottom, barMetrics: .default)
bar.setBackgroundImage(.pixel(color: UIColor.purple), for: .top, barMetrics: .default)
Is there any way to make different colors for different large title states in iOS 11-12?
Finally found solution, works for iOS 11-12:
let observer = navBar.observe(\.frame, changeHandler: { (bar, frame) in
if navBar.frame.height <= 44 {
navBar.barTintColor = UIColor.lightGray
navBar.shadowImage = imageForShadow
}
else {
navBar.barTintColor = UIColor.white
navBar.shadowImage = UIImage()
}
})
Related
After update to iOS 15, I implemented UITabBar configuration this way:
let backgroundColor = UIColor.grey
let selectedItemTextColor = UIColor.blue
let unselectedItemTextColor = UIColor.black
if #available(iOS 15, *) {
let tabBarAppearance = UITabBarAppearance()
tabBarAppearance.backgroundColor = backgroundColor
tabBarAppearance.stackedLayoutAppearance.selected.titleTextAttributes = [.foregroundColor: selectedItemTextColor]
tabBarAppearance.stackedLayoutAppearance.normal.titleTextAttributes = [.foregroundColor: unselectedItemTextColor]
tabBar.standardAppearance = tabBarAppearance
tabBar.scrollEdgeAppearance = tabBarAppearance
} else {
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor: selectedItemTextColor], for: .selected)
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor: unselectedItemTextColor], for: .normal)
tabBar.barTintColor = backgroundColor
}
This works fine for iOS 15 and older versions.
But in my project I need to set selected/unselected text color for one of tab bar items, different from other items. Set it in runtime.
There are 5 tab bar items. In some moment, I need this behavior: four of them should have blue/black text color (for selected/unselected states) and one should have red/green color.
Until iOS 15, I used this code to set colors of needed item in every moment of time:
let indexOfItemToChange = 4
tabBar.items[indexOfItemToChange].setTitleTextAttributes([.foregroundColor: UIColor.red], for: .selected)
tabBar.items[indexOfItemToChange].setTitleTextAttributes([.foregroundColor: UIColor.green], for: .normal)
After update update to iOS 15 it makes no effect. I have tried to set it like this:
let indexOfItemToChange = 4
tabBar.items[indexOfItemToChange].standardAppearance?.stackedLayoutAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.green]
tabBar.items[indexOfItemToChange].standardAppearance?.stackedLayoutAppearance.selected.titleTextAttributes = [.foregroundColor: UIColor.red]
But it makes no effect too. Even if before setting of tab bar item colors I set UITabBar appearances for each tab bar item:
tabBar.items.forEach {
$0.standardAppearance = standardAppearance
$0.scrollEdgeAppearance = scrollEdgeAppearance
}
Some one faced this issue? Any advice?
PS. In my project there are no xibs and storyboards. So I need to solve my problem only programmatically.
On the right, the first time and on the left, all the other times
Hello Guys,
I’m new so I hope that’s the way things goes around here !
Like y’all know, iOS 13 introduced UI changes. We have an app in production and I recently woke up (maybe a little too late haha) and as I compiled and launch it on a freshly updated iOS 13 device, that’s when I became aware there was some work to do !
I handled the dark mode by not enabling it, I handled my modals but there is one thing I can’t seem to make like iOS 12 and it’s my Navigation Bar UI.
We use a custom back button image and after fighting during several hours, I finally succeeded but it’s ok everytime except the first time. I will always have the default icon the first time, and then when I come back to the same controller, it’s okay.
Here is a photo (at the beginning of the question) so you can understand and also my code !
I know it’s possible to use Appearance for specific VC with « whenContained » but I can’t seem to figure it out cause it’s all in navigation controller and I don’t know how to differentiate them.
fileprivate func navigationBarWithBackgroundColor(_ backgroundColor: UIColor, TintColor tintColor: UIColor, displayBackButtonIfNeeded: Bool, BackImage imageName:String, displayShadowBar: Bool = false) {
let backButtonImage = UIImage(named: imageName)
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = backgroundColor
appearance.titleTextAttributes = [.foregroundColor: tintColor]
appearance.setBackIndicatorImage(backButtonImage, transitionMaskImage: backButtonImage)
appearance.shadowImage = displayShadowBar ? UIImage(named:"") : UIImage()
let back = UIBarButtonItemAppearance()
// hide back button text
back.normal.titleTextAttributes = [.foregroundColor: UIColor.clear]
appearance.backButtonAppearance = back
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
} else {
if displayBackButtonIfNeeded {
self.navigationController?.navigationBar.backIndicatorImage = backButtonImage
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = backButtonImage
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItem.Style.plain, target: nil, action: nil)
} else {
self.navigationItem.setHidesBackButton(true, animated: false)
}
self.navigationController?.navigationBar.barTintColor = backgroundColor
self.navigationController?.navigationBar.tintColor = tintColor
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named:""), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = displayShadowBar ? UIImage(named:"") : UIImage()
}
}
I’m basically become crazy here and I assume I’m missing something very obvious so if you guys have any hints or clues except apple documentation, feel free to share :)
Thanks in advance !
In iOS 13 you can set up back button image and transition mask image only by the function
func setBackIndicatorImage(UIImage?, transitionMaskImage: UIImage?)
And here is an example
standartAppearence.setBackIndicatorImage(#imageLiteral(resourceName: "backButton"), transitionMaskImage: #imageLiteral(resourceName: "backButton"))
In short, how can I change the color of the black button items (while maintaining control over their size)?
Longer version: I am programmatically adding a number of custom UIBarButtonItems to a UIToolbar. I'm using the solution found here so that I can control the size of the items.
While this fixes the UIBarButtonItem size issue, it does not respect tintColor like a typical UIBarButtonItem would. So I get something like this:
The large white item is the color I want, but not the size. This item was simply added in IB with the tintColor set to default.
The small black items are the size I want, and were added with the following code (N.B. the lines marked with // Not producing intented result):
for e in (self.profile?.expressions)! {
let button = UIButton()
button.setImage(UIImage(named: "emojiph"), for: .normal)
button.addTarget(self, action: #selector(onEmojiInsert), for: .touchUpInside)
let barItem = UIBarButtonItem(customView: button)
barItem.tag = e.family_expression_id
let wConstraint = barItem.customView?.widthAnchor.constraint(equalToConstant: 32)
wConstraint?.isActive = true
let hConstraint = barItem.customView?.heightAnchor.constraint(equalToConstant: 32)
hConstraint?.isActive = true
// Not producing intented result
button.tintColor = UIColor.white
// Not producing intented result
barItem.customView?.tintColor = UIColor.white
// Not producing intented result
barItem.tintColor = UIColor.white
self.emojibar.items?.append(barItem)
// Add flexible spacers
if (e.family_expression_id < (self.profile?.expressions.count)!) {
self.emojibar.items?.append(UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil))
}
}
A workaround would be to provide the white image assets, but I'd prefer to find a more elegant solution if it exists.
To make the button change the color of the presented image to match the tint color then you need to initiate the button as a system type
let button = UIButton(type: .system)
In my app, I have a button with a text title next to a button that's an image. I want the color scheme of both buttons to match. I create the button with the image like this:
let button1 = UIButton()
button1.setImage(
UIImage(named: "button1")?.withRenderingMode(.alwaysTemplate), for: .normal)
button1.tintColor = UIColor.green
This creates the effect that I want on both buttons, i.e. the button is green, then when it's highlighted it gets tinted to a darker, black-ish green. I tried creating the text button the same way:
let button2 = UIButton()
button2.setTitle("button2", for: .normal)
button2.tintColor = UIColor.green
But, in this case, setting the tint color doesn't change the color of the button's title/text (it remains white even when highlighted). My solution to this is as follows:
let button2 = UIButton()
button2.setTitle("button2", for: .normal)
button2.setTitleColor(UIColor.green, for: .normal)
button2.setTitleColor(UIColor(red: 0x23 / 255.0,
green: 0x34 / 255.0,
blue: 0x16 / 255.0,
alpha: 1.0), for: .highlighted)
Essentially, I've estimated the color that the image gets tinted to when it's highligted and set the text color to match. This works fine, but it bothers me that I only have an approximation; ideally, I would want the system to tint the text color for me when the button is highlighted in the same way that it tints the image. I get that this is a really small problem and that fixing it probably won't noticeably improve the app, but I'd still like to know if there's a way to tint a button with a text title "automatically" (as opposed to hardcoding the tint).
Tint color is property of UIView, which doesn't have a state. State is property of UIControl(Button's parent class). Means that you cannot change the tint on the bases of button's state. You can only change properties mentioned seen in this screen shot on the basis of button's state by default.
Also the
darker, black-ish green
color your getting that the default behaviour of button to change background color to show highlighted state
Solution : CustomButton
Create a custom UIButton
class MyButton : UIButton {
override var isHighlighted: Bool{
didSet {
tintColor = isHighlighted ? UIColor.green : UIColor.red
// do additional work here according to your need
}
}
override var isSelected: Bool {
didSet {
// do changes according to you need
}
}
}
You can also set the properties mentioned in above image programmatically.
button.setTitleColor(UIColor.green, for: .normal)
button.setTitleColor(UIColor.red, for: .highlighted)
button.setBackgroundImage(yourBackgroundImage, for: .normal)
let button2 = UIButton()
button2.addTarget(self, action: #selector(self.pressed), for: [.touchDown])
button2.addTarget(self, action: #selector(self.released), for: [.touchDragExit, .touchUpInside, .touchUpOutside, .touchCancel])
func pressed() {
// set colour
}
func released() {
// set colour
}
I'm trying to implement a segmented control but it seems so simple in the layout. I want to customize it:
lose the borders for instance
have a custom indicator
What would be the way to do it? I know in Android how to customise an TabLayout but here I'm lost to be honest.
I'm quite late to the party, but here's what I'd do:
Set the background color to .clear
segmentedControlInstance.backgroundColor = UIColor(red:0.13, green:0.16, blue:0.29, alpha:1.0)
Set the background tint color to .clear
segmentedControlInstance.tintColor = .clear
I noticed the selected segment's title is bold. Set the text attributes for the two states (.normal & .selected)
segmentedControlInstance.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.white, NSAttributedStringKey.font: UIFont.systemFont(ofSize: 16)], for: .normal)
segmentedControlInstance.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.white, NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 16)], for: .selected)
Finally, set the two background images. Caution, I have no idea what to set for the barMetrics parameter:
segmentedControlInstance.setBackgroundImage(UIImage(name: "selectedSegment", for: .selected, barMetrics: ?)
segmentedControlInstance.setBackgroundImage(UIImage(name: "normalSegment", for: .normal, barMetrics: ?)
I'll let you play around with the barMetrics parameters.
If what I need to customize wasn't on this list, UISegmentedControl Docs, I'd build my own.
In your image, I'd use two buttons, a view for the indicator, and some logic to respond to user interactions.