I am trying to make my Tab Bar in my tab bar controller to have a low opacity background, so it is semi transparent, i am trying to do this programatically, however the background changes to the correct color, but always appears solid, with no transparency.
Here is the code in my TabBarViewController
class TabBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBar.unselectedItemTintColor = UIColor(red: 17.0/255.0, green: 70.0/255.0, blue: 95.0/255.0, alpha: 0.4)
self.tabBar.barTintColor = UIColor(red: 17.0/255.0, green: 70.0/255.0, blue: 95.0/255.0, alpha: 0.5)
// Do any additional setup after loading the view.
}
}
For such a case, you should generate a customized UIImage to the tab bar backgroundimage property.
Let's assume that your desired color for your tab bar -that should be transparent- is black, you could implement in your custom UITabBarController:
class TabBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let transperentBlackColor = UIColor(displayP3Red: 0, green: 0, blue: 0, alpha: 0.5)
let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
transperentBlackColor.setFill()
UIRectFill(rect)
if let image = UIGraphicsGetImageFromCurrentImageContext() {
tabBar.backgroundImage = image
}
UIGraphicsEndImageContext()
}
}
So, as an Output, if we assumed that the background color of your view controller is blue, it should looks like:
As shown, the tab bar is not purely black, it contains transparency (0.5) as expected.
Also, for checking how you could generate a solid-color UIImage, you could check this SO answer : Create UIImage with solid color in Swift.
Just replace barTintColor with backgroundColor.
override func viewDidLoad() {
super.viewDidLoad()
self.tabBar.unselectedItemTintColor = UIColor(red: 17.0/255.0, green: 70.0/255.0, blue: 95.0/255.0, alpha: 0.4)
self.tabBar.backgroundColor = UIColor(red: 17.0/255.0, green: 70.0/255.0, blue: 95.0/255.0, alpha: 0.5)
// Do any additional setup after loading the view.
}
private func setTabbarOpacity() {
let transperentBlackColor = UIColor(displayP3Red: 0, green: 0, blue: 0, alpha: 0.75)
let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
transperentBlackColor.setFill()
UIRectFill(rect)
if let image = UIGraphicsGetImageFromCurrentImageContext() {
tabBar.backgroundImage = image
}
UIGraphicsEndImageContext()
}
Related
I'm setting the image of the navigation bar to a gradient. This works perfectly on all models except for iPhone 12 mini.
I've tried calling this on my main view controller in ViewWillAppear, viewDidAppear, and ViewDidLoad
Here's what it looks like on all other models
func setNavGradiant(){
guard let navigationController = self.navigationController else {print("❇️♊️>>>\(#file) \(#line): guard let failed<<<"); return}
let gradientLayer = CAGradientLayer()
var updatedFrame = navigationController.navigationBar.bounds
updatedFrame.size.height += UIApplication.shared.windows[0].windowScene?.statusBarManager?.statusBarFrame.height ?? 0
gradientLayer.frame = updatedFrame
gradientLayer.colors = [ #colorLiteral(red: 0.4392156899, green: 0.01176470611, blue: 0.1921568662, alpha: 1).cgColor, #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1).cgColor] // start color and end color
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0) // vertical gradient start
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
UIGraphicsBeginImageContext(gradientLayer.bounds.size)
gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.navigationController?.navigationBar.setBackgroundImage(image, for: UIBarMetrics.default)
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(#colorLiteral(red: 0.9579688907, green: 0.9579688907, blue: 0.9579688907, alpha: 1))]
}
You will probably have better results by subclassing UINavigationController:
class MyNavigationController: UINavigationController {
let gradient = CAGradientLayer()
override func viewDidLoad() {
super.viewDidLoad()
gradient.frame = navigationBar.bounds
gradient.colors = [ #colorLiteral(red: 0.4392156899, green: 0.01176470611, blue: 0.1921568662, alpha: 1).cgColor, #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1).cgColor] // start color and end color
gradient.startPoint = CGPoint(x: 0.5, y: 0.0) // vertical gradient start
gradient.endPoint = CGPoint(x: 0.5, y: 1.0)
if let image = getImageFrom(gradientLayer: gradient) {
navigationBar.setBackgroundImage(image, for: UIBarMetrics.default)
}
}
func getImageFrom(gradientLayer:CAGradientLayer) -> UIImage? {
var gradientImage:UIImage?
UIGraphicsBeginImageContext(gradientLayer.frame.size)
if let context = UIGraphicsGetCurrentContext() {
gradientLayer.render(in: context)
gradientImage = UIGraphicsGetImageFromCurrentImageContext()?.resizableImage(withCapInsets: UIEdgeInsets.zero, resizingMode: .stretch)
}
UIGraphicsEndImageContext()
return gradientImage
}
}
Try calling:
DispatchQueue.main.async {
self.setNeedsStatusBarAppearanceUpdate()
}
after your setup is done. Should work without dispatching to main thread, but I had previously caught issues of things called from lifecycle methods not being on the main thread. So another thing to check is to make sure you are running the updates on the main thread.
I need to change the color of the UIBezierPath, but if I set a custom color, then there is simply no color.
UIColor(red: 255/255.0, green: 249/255.0, blue: 244/255.0, alpha: 1.0)
Tried adding colors via extension, but there is no color either.
UIColor.themeColor.setFill()
extension UIColor {
class var themeColor: UIColor {
return UIColor(red: 255/255.0, green: 249/255.0, blue: 244/255.0, alpha: 1.0)
}
}
Standard colors like .blue, .green, .red - work, but I need to understand how to set my own color through rgb
Here is my code
class MyView: UIView {
override func draw(_ rect: CGRect) {
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 303.19, height: 495.93))
path.stroke()
}
}
let views = MyView(frame: CGRect(x: 36.62, y: 77.54, width: 303.19, height: 495.93))
views.backgroundColor = .clear
views.rotate(radians: -45.84)
view.addSubview(views)
Use this if you want to change the color in UIBezierPath
path.fillColor = UIColor(red: 255/255.0, green: 249/255.0, blue: 244/255.0, alpha: 1.0).cgColor
path.fillColor = UIColor.red.cgColor
path.fillColor = UIColor(red: 155/255.0, green: 149/255.0, blue: 234/255.0, alpha: 1.0).cgColor
Works well
I have a UIViewController with a navigation bar on top. I want to replace the title with a segmented control.
class AViewController: UIViewController
{
private var navigationbar = UINavigationBar();
private var segment = UISegmentedControl();
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
buildThebar();
}
func buildThebar()
{
navigationbar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 64));
navigationbar.backgroundColor = UIColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1.0);
segment = UISegmentedControl(items: ["Testy", "Tests"]);
segment.sizeToFit();
segment.tintColor = UIColor(red: 104/255, green: 90/255, blue: 132/255, alpha: 1.0);
let cancel = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelbar(sender:)));
cancel.tintColor = UIColor(red: 104/255, green: 90/255, blue: 132/255, alpha: 1.0);
let title = UINavigationItem(title: "Testing");
title.leftBarButtonItem = cancel;
navigationbar.setItems([title], animated: false);
self.navigationItem.titleView = segment;
// self.navigationItem.leftBarButtonItem = cancel;
self.view.addSubview(navigationbar);
}
Ok found issue.
What you missed is setting titleView to the navigation item you created.
title.titleView = segment
You are adding titleView to navigation item self.navigationItem.titleView = segment; but you need to set it to your navigationItem which you are passing to your navigation bar.
Final code
func buildThebar()
{
navigationbar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 64));
navigationbar.backgroundColor = UIColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1.0);
segment = UISegmentedControl(items: ["Testy", "Tests"]);
segment.sizeToFit();
segment.tintColor = UIColor(red: 104/255, green: 90/255, blue: 132/255, alpha: 1.0);
let cancel = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: nil);
cancel.tintColor = UIColor(red: 104/255, green: 90/255, blue: 132/255, alpha: 1.0);
let title = UINavigationItem(title: "Testing"); //better let title = UINavigationItem()
title.leftBarButtonItem = cancel;
title.titleView = segment
navigationbar.setItems([title], animated: false);
// self.navigationItem.leftBarButtonItem = cancel;
self.view.addSubview(navigationbar);
}
EDIT:
There is another issue with how you are setting navigation bar frame. O/P with your code looks like
I believe thats not what you want! the reason why it looks like that is because your frame starts from y = 0 but in iPhone and iPads portait mode there is a status bar on top which consumes variable amount of space based on various condition (Usually people hardcode or assume it to be 20 but iPhone X the height status bar might vary and even in normal iPhones when you receive a call status bar height changes). Its always better to use auto layout and safe margin to add navigation bar to View.
But if you really wanna hard code frames then you can use
navigationbar = UINavigationBar(frame: CGRect(x: 0, y: 20, width: self.view.bounds.width, height: 44));
O/P looks like
Hope it helps.
let title = UINavigationItem()
title.titleView = segment
title.rightBarButtonItem = cancel
navigationbar.setItems([title], animated: false);
self.view.addSubview(navigationbar);
Just a matter of order of assignment of the objects in operation.
I have a code where, depending on whether a condition is true, an image is flipped and its tintColor changed.
func incoming(incoming: Bool) {
let image = UIImage(named: "MessageBubble")?.imageWithRenderingMode(.AlwaysTemplate)
var shownImage: UIImage
// Check whether it is an incoming or outgoing message
if incoming {
let flippedImage = UIImage(CGImage: image!.CGImage!, scale: image!.scale, orientation: UIImageOrientation.UpMirrored)
shownImage = flippedImage.imageWithRenderingMode(.AlwaysTemplate)
bubbleImageView.tintColor = UIColor(red: 100/255, green: 200/255, blue: 100/255, alpha: 1)
} else {
shownImage = image!
bubbleImageView.tintColor = UIColor(red: 100/255, green: 255/255, blue: 255/255, alpha: 1)
}
bubbleImageView.image = shownImage
}
However, this code does not flip the image but it is correctly applying the tintColor. If the ".imageWithRenderingMode(.AlwaysTemplate)" function is removed, the image is correctly flipped but the tintColor is not applied. (bubbleImageView is a UIImageView).
The code under else block shows up with the correct tintColor.
How can I get both the image flipped and its color changed?
Try to add color for your images with this method:
func coloredImage(image: UIImage, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) -> UIImage! {
let rect = CGRect(origin: CGPointZero, size: image.size)
UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
let context = UIGraphicsGetCurrentContext()
image.drawInRect(rect)
CGContextSetRGBFillColor(context, red, green, blue, alpha)
CGContextSetBlendMode(context, CGBlendMode.SourceAtop)
CGContextFillRect(context, rect)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
So, in your case, you should do:
let processedImage = coloredImage(bubbleImageView, red: 100/255, green: 255/255, blue: 255/255, alpha: 1)
I have done gradient coloring before for changing color of my parent view now I am using same method to change the background color of UITextField but its not working.
This is the method I used for my view:
func setGradientBackgroundOfView()
{
// assigning gradient color to background View
let endingColorOFGradient = UIColor(colorLiteralRed: 133/255, green: 210/255, blue: 230/255, alpha: 1.0).CGColor
let startingColorOfGradient = UIColor(colorLiteralRed: 50/255, green: 189/255, blue: 170/255, alpha: 1.0).CGColor
gradient.startPoint = CGPoint(x: 0.5, y: 0.0)
gradient.endPoint = CGPoint(x: 0.5, y: 1.0)
gradient.colors = [startingColorOfGradient , endingColorOFGradient]
self.view.layer.insertSublayer(gradient, atIndex: 0)
}
And this method for setting layer:
override func viewWillLayoutSubviews() {
gradient.frame = self.view.bounds
}
I am calling my setGradientBackgroundOfView() in viewDidLoad() and it's working perfect but if I change
self.view.layer.insertSublayer(gradient, atIndex: 0)
with
self.textFieldUserName.layer.insertSublayer(gradient, atIndex: 0)
it does not work. What am I missing here?