iOS 15 Navigation Bar issue - swift

I have a custom NavigationBar in my project, but the only issue I encounter is that once I begin scrolling, the NavigationBar still shows the content behind it.
func customNavigationBar() {
let coloredAppearance = UINavigationBarAppearance()
coloredAppearance.configureWithTransparentBackground()
coloredAppearance.backgroundColor = UIColor(red: 41/255, green: 59/255, blue: 77/255, alpha: 0)
coloredAppearance.shadowColor = .clear
coloredAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
coloredAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
UINavigationBar.appearance().standardAppearance = coloredAppearance
UINavigationBar.appearance().compactAppearance = coloredAppearance
UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
UINavigationBar.appearance().tintColor = .white
}

Change alpha from 0 to 1 on your backgroundColor property
func customNavigationBar() {
let coloredAppearance = UINavigationBarAppearance()
coloredAppearance.configureWithTransparentBackground()
coloredAppearance.backgroundColor = UIColor(
red: 41/255,
green: 59/255,
blue: 77/255,
alpha: 1) //alpha: 0 is Transparent and alpha: 1 is colored
coloredAppearance.shadowColor = .clear
coloredAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
coloredAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
UINavigationBar.appearance().standardAppearance = coloredAppearance
UINavigationBar.appearance().compactAppearance = coloredAppearance
UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
UINavigationBar.appearance().tintColor = .white
}

Related

Picker in SwiftUI 2 .onChange() does not change UINavigationBar.appearance()

So this is a weird one...before SwiftUI 2 launched, I set the UINavigationBar.appearance() in the init() of the view as follows:
init(selectedStyle: Binding<Int>) {
_selectedStyle = selectedStyle
if self.selectedStyle == 1 {
UINavigationBar.appearance().backgroundColor = UIColor.init(displayP3Red: 7/255, green: 7/255, blue: 7/255, alpha: 1)
UISegmentedControl.appearance().backgroundColor = .black
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black], for: UIControl.State.selected)
UISegmentedControl.appearance().selectedSegmentTintColor = .white
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], for: UIControl.State.normal)
} else {
UINavigationBar.appearance().backgroundColor = .white
UISegmentedControl.appearance().backgroundColor = .white
UISegmentedControl.appearance().selectedSegmentTintColor = .white
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black], for: UIControl.State.selected)
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black], for: UIControl.State.normal)
}
}
In SwiftUI 1, the view would initialize again so the new look for the navbar would update correctly. because the init() function would run again. I tried to put the same code inside of an onChange() that's attached to the Picker but for some reason it doesn't work:
Picker(selection: $selectedStyle, label: Text("")) {
ForEach(0 ..< 3) {
Text([$0])
}
}
.pickerStyle(SegmentedPickerStyle())
.onChange(of: selectedStyle, perform: { change in
if self.selectedStyle == 1 {
UINavigationBar.appearance().backgroundColor = UIColor.init(displayP3Red: 7/255, green: 7/255, blue: 7/255, alpha: 1)
UISegmentedControl.appearance().backgroundColor = .black
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black], for: UIControl.State.selected)
UISegmentedControl.appearance().selectedSegmentTintColor = .white
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], for: UIControl.State.normal)
} else {
UINavigationBar.appearance().backgroundColor = .white
UISegmentedControl.appearance().backgroundColor = .white
UISegmentedControl.appearance().selectedSegmentTintColor = .white
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black], for: UIControl.State.selected)
UISegmentedControl.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.black], for: UIControl.State.normal)
}
})
The appearance have effect on UI elements creates after corresponding appearance is set. So you need to recreate all dependent UI.
The possible approach can be as follows - assuming you have NavigationView in root of ContentView, you can recreate it (and so all subviews), by
var body: some View {
NavigationView {
// .. content here
}.id(selectedStyle) // << here !!
}

Global changes UINavigationBar background using appearance proxy not working

I'm trying to change some properties of all UINavigationBars in my app using UINavigationBarAppearance. I'm calling the following function in application(_:didFinishLaunchingWithOptions:) in AppDelegate.swift:
func customizeAppearance() {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithDefaultBackground()
navBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
navBarAppearance.backgroundColor = UIColor.black
UITabBar.appearance().backgroundColor = UIColor.black
let tintColor = UIColor(red: 255/255.0, green: 238/255.0, blue: 136/255.0, alpha: 1.0)
UITabBar.appearance().tintColor = tintColor
}
I expect this to change the background color and color of the title text, but when I run the app, only the text color changes (this is also true for the UITabBar). Any suggestions?
You should use this UINavigationBarAppearance in your UINavigationControllers. If you use global appearance for UINavigationController you should use UINavigationBar.appearance() instead of UINavigationBarAppearance().

Text field four-sided border with animation

I would like to highlight text field four-side border when user clicked inside and reverting back when user's editing end. To achieve this I have following code snippet inside editingDidBegin function of my text field.
func pulseBorderColor() {
let pulseAnimation = CABasicAnimation(keyPath: "borderColor")
pulseAnimation.duration = 0.35
pulseAnimation.fromValue = UIColor.green.cgColor
pulseAnimation.toValue = UIColor(red: 252/255, green: 180/255, blue: 29/255, alpha: 1.0).cgColor
pulseAnimation.fillMode = kCAFillModeForwards
pulseAnimation.isRemovedOnCompletion = false
pulseAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
nationalIdentityTextField.layer.sublayers![0].add(pulseAnimation,forKey: nil)
}
And to revert back my text field color I have following code inside text field editingDidEnd function
func reversePulseBorderColor() {
let pulseAnimation = CABasicAnimation(keyPath: "borderColor")
pulseAnimation.duration = 0.35
pulseAnimation.fromValue = UIColor(red: 252/255, green: 180/255, blue: 29/255, alpha: 1.0).cgColor
pulseAnimation.toValue = UIColor.green.cgColor
pulseAnimation.fillMode = kCAFillModeForwards
pulseAnimation.isRemovedOnCompletion = false
pulseAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
nationalIdentityTextField.layer.sublayers![0].add(pulseAnimation,forKey: nil)
}
However, it could't achieve what I want. What could be the reason and how can I fix it?
I think you should set keyPath to the layer of the textfield in question rather than in the CABasicAnimation
and also you need to set borderWidth to atleast 1 for the color to be visible.
And here is what I tried to modify the code above and had it working
func pulseBorderColor() {
let pulseAnimation = CABasicAnimation(keyPath: nil)
pulseAnimation.duration = 0.35
pulseAnimation.fromValue = UIColor.green.cgColor
pulseAnimation.toValue = UIColor(red: 252/255, green: 180/255, blue: 29/255, alpha: 1.0).cgColor
pulseAnimation.fillMode = CAMediaTimingFillMode.forwards
pulseAnimation.isRemovedOnCompletion = false
pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
txtInput.layer.add(pulseAnimation, forKey: "borderColor")
}
func reversePulseBorderColor() {
let pulseAnimation = CABasicAnimation(keyPath: nil)
pulseAnimation.duration = 0.35
pulseAnimation.fromValue = UIColor(red: 252/255, green: 180/255, blue: 29/255, alpha: 1.0).cgColor
pulseAnimation.toValue = UIColor.green.cgColor
pulseAnimation.fillMode = CAMediaTimingFillMode.forwards
pulseAnimation.isRemovedOnCompletion = false
pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
txtInput.layer.add(pulseAnimation, forKey: "borderColor")
}
to set borderWidth you can do that by setting it in the code like this
txtInput.layer.borderWidth = 1
or in the User Defined Runtime Attributes in the identity inspector.
Hope this helps.

Navigation Controller. Background color

For one controller I have settings:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
and
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
var offset = scrollView.contentOffset.y / 150
if offset > 1 {
offset = 1
self.navigationController?.navigationBar.backgroundColor = UIColor(red: 82/255, green: 76/255, blue: 70/255, alpha: offset)
UIApplication.shared.statusBarView?.backgroundColor = UIColor(red: 82/255, green: 76/255, blue: 70/255, alpha: offset)
self.navigationItem.title = name
} else {
self.navigationController?.navigationBar.backgroundColor = UIColor(red: 82/255, green: 76/255, blue: 70/255, alpha: offset)
UIApplication.shared.statusBarView?.backgroundColor = UIColor(red: 82/255, green: 76/255, blue: 70/255, alpha: offset)
self.navigationItem.title = ""
}
}
The main problem is that when i press back button, settings save. In the end i have white NavigationController. How can I make the settings not taken from the last controller?
func makeSearchController() {
searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.tintColor = .white
searchController.searchBar.placeholder = "Блюдо или продукт ..."
}
You can reset the navigation controller's color in viewWillDisappear, like this:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.navigationBar.backgroundColor = UIColor(red: 221/255, green: 221/255, blue: 225/255, alpha: offset) //gray color
UIApplication.shared.statusBarView?.backgroundColor = UIColor(red: 221/255, green: 221/255, blue: 225/255, alpha: offset) //gray color
}

CAGradientLayerHides my UILabel text

I am trying to add gradient background to my labels (which are connected from UserInterface) , but it hides label's text.
This is my code so far:
//MARK: Grdient label func
func gradientBackground(label:UILabel){
let four = UIColor(red: 240/255, green: 240/255, blue: 240/255, alpha: 1).CGColor
let three = UIColor.whiteColor().CGColor
let two = UIColor.whiteColor().CGColor
let one = UIColor(red: 240/255, green: 240/255, blue: 240/255, alpha: 1).CGColor
let gradient = CAGradientLayer()
gradient.locations = [0.0,0.2,0.8,1.0]
gradient.colors = [one,two,three,four]
gradient.startPoint = CGPointMake(0.0, 0.5)
gradient.endPoint = CGPointMake(1.0, 0.5)
gradient.frame = CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, label.bounds.height)
let backView = UIView()
backView.frame = CGRectMake(0, 0, label.bounds.width, label.bounds.height)
backView.backgroundColor = UIColor.clearColor()
backView.layer.insertSublayer(gradient, atIndex: 0)
label.insertSubview(backView, atIndex: 0)
label.backgroundColor = UIColor.clearColor()
label.textColor = UIColor.blackColor()
label.tintColor = UIColor.blackColor()
}
Then I use the function like this:
override func viewDidLoad() {
super.viewDidLoad()
//MARK: Gradient background
gradientBackground(firstLabel)
}
My question is, what is wrong?
Thank you.
check if it is your label "firstLabel" visible
check if your func draw img under the text