Incorrect positioning of background image - swift - ios

I'm using an image in the background of the application. This image is displayed correctly in one clip, while the other clip is positioned incorrectly. In the correct picture(fig .1), the background image is positioned up to Tabbar. As you can see in the wrong picture(fig .2), the background is not positioned up to Tabbar and the logo is left behind Tabbar. The codes are in the same state, but the picture is incorrectly positioned in Fig .2.
MainTableViewController Class
class MainTableViewController: UITableViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
appThemeSetBySettingsPreference()
}
func appThemeSetBySettingsPreference() {
UIGraphicsBeginImageContext(view.frame.size)
UIImage(named: "...png")?.draw(in: view.bounds)
if let image = UIGraphicsGetImageFromCurrentImageContext(){
UIGraphicsEndImageContext()
view.backgroundColor = UIColor(patternImage: image)
}
}
}
DeviceViewController Class
class DeviceViewController: UITableViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
appThemeSetBySettingsPreference()
}
func appThemeSetBySettingsPreference() {
UIGraphicsBeginImageContext(view.frame.size)
UIImage(named: "...png")?.draw(in: view.bounds)
if let image = UIGraphicsGetImageFromCurrentImageContext(){
UIGraphicsEndImageContext()
view.backgroundColor = UIColor(patternImage: image)
}
}
}
EDIT
let image = UIImageView(image: UIImage(contentsOfFile:"...."));
let tabBarHeight = tabBarController?.tabBar.frame.size.height
let topBarHeight = UIApplication.shared.statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height ?? 0.0)
image.frame = CGRect(x:0 , y: topBarHeight, width: self.view.frame.size.width , height: self.view.frame.size.height - topBarHeight - tabBarHeight!)

With the iPhone X, the height of the top bar (navigation bar + status bar) is changed. So you can get exact height of the top bar (both navigation bars + status bar):
Swift 4:
let topBarHeight = UIApplication.shared.statusBarFrame.size.height +(self.navigationController?.navigationBar.frame.height ?? 0.0)
Swift 3:
let topBarHeight = UIApplication.sharedApplication().statusBarFrame.size.height + (self.navigationController?.navigationBar.frame.height ?? 0.0)
Objective-C:
CGFloat topbarHeight = ([UIApplication sharedApplication].statusBarFrame.size.height + (self.navigationController.navigationBar.frame.size.height ?: 0.0));
And the height of the tab bar can be obtained as follows
let tabBarHeight = self.tabBarController?.tabBar.frame.height ?? 49.0
Having these values ​​you can adapt your image to when starting your controller in your method viewDidLoad() of your class, for example
self.image.frame = CGRect(x:0 , y: topBarHeight, width: self.view.frame.size.width , height: self.view.frame.size.height - topBarHeight - tabBarHeight)

Related

Bottom part of tab bar does not get properly colored

I want to custom color my tab bar element in my custom UITabController sub-class and it works fine when I'm doing it with:
tabBar.barTintColor = .blue (With any system or custom color)
But when I'm trying to add a gradient using my custom UIImage extension
extension UIImage {
static func gradientImageWithBounds(bounds: CGRect, colors: [CGColor]) -> UIImage {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
gradientLayer.colors = colors
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
gradientLayer.masksToBounds = true
UIGraphicsBeginImageContext(gradientLayer.bounds.size)
gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
tabBar.barTintColor = UIColor(patternImage: UIImage.gradientImageWithBounds(bounds: tabBar.bounds, colors: [Colors.tabBarTopGradient, Colors.tabBarBottomGradient]))
I having trouble with gradient not getting properly applied to the bottom part of the tab bar around the phone's safe area. What am I missing here? It looks like that:
Please try setting the gradient tint in viewWillLayoutSubviews(). Hope that helps!
I think you create the gradient based on tab bar height, what you need is to add the additional height to the tab bar height
override func viewDidLoad() {
super.viewDidLoad()
var frame = tabBar.bounds
let safeAreaHeight = safeAreaInsets.bottom
frame.size.height = frame.size.height + safeAreaHeight
tabBar.barTintColor = UIColor(patternImage: UIImage.gradientImageWithBounds(bounds: frame, colors: [UIColor.red.cgColor, UIColor.blue.cgColor]))
}
public var safeAreaInsets: UIEdgeInsets {
guard let window: UIWindow = UIApplication.shared.windows.first else {
return .zero
}
if #available(iOS 11.0, *),
UIWindow.instancesRespond(to: #selector(getter: window.safeAreaInsets)) {
return window.safeAreaInsets
}
return .zero
}

How to show an image behind a navigation bar?

Any ideas how to show an image behind a navigation bar and also show the "full" navigation bar on scrolling down?
Thanks in advance!
navigationController?.hidesBarsOnSwipe = true
Simply you can do like this. I hope It will work.
Your Reference Image can be achieved by using the below code.
Here 180 is the header size of the TableView.With This condition scrollOffset > 180 you can change the UIColor of the NavigationBar elements.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let scrollOffset = scrollView.contentOffset.y
UIView.animate(withDuration: 0.1) {
self.navigationView.alpha = scrollOffset > 180 ? 1 : 0
}
}
In your Header of the TableView, you should assign the Desired Image as HeaderView.
You can add image in the title view of the navigation item in viewDidLoad() of the view controller
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let image = UIImage(named: "YOURIMAGE")
navigationItem.titleView = UIImageView(image: image)
}
And here is an example how you can do it with CGRect.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 38, height: 38))
imageView.contentMode = .ScaleAspectFit
let image = UIImage(named: "YOURIMAGE")
imageView.image = image
navigationItem.titleView = imageView
}

Change background color of UITabBarItem in Swift [duplicate]

This question already has answers here:
UITabBar change background color of one UITabBarItem on iOS7
(6 answers)
Closed 5 years ago.
I just want to change the background colour of one of the tab bat items. I found many links but didn't get any help from that.
Requirement:
And, this is the way I setup my tab bar items
let myTabBarItem3 = (self.tabBar.items?[2])! as UITabBarItem
myTabBarItem3.image = UIImage(named: "ic_center")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
myTabBarItem3.selectedImage = UIImage(named: "ic_center")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
What I want is the black colour background for centre tab bar item.
Any idea?
And yes it is not a duplicate, Because the previous answered are not accurate and to add extra subview is never a good option, So expecting some good solution from friends
If you want to change the background colour of only centre tabBarItem you can follow below code.
NOTE: All the below code is used in a custom class which extends UITabBarController as:
class tabbarVCViewController: UITabBarController, UITabBarControllerDelegate {
// MARK: - ViewController Override Methods.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupInitilView()
}
// MARK: - setup Initial View Methode.
private func setupInitilView() {
delegate = self
// Sets the default color of the icon of the selected UITabBarItem and Title
UITabBar.appearance().tintColor = UIColor.white
// Sets the default color of the background of the UITabBar
UITabBar.appearance().barTintColor = UIColor.white
// Sets the background color of the selected UITabBarItem (using and plain colored UIImage with the width = 1/5 of the tabBar (if you have 5 items) and the height of the tabBar)
//UITabBar.appearance().selectionIndicatorImage = UIImage().makeImageWithColorAndSize(color: UIColor.black, size: CGSize.init(width: tabBar.frame.width/4, height: tabBar.frame.height))
// Uses the original colors for your images, so they aren't not rendered as grey automatically.
for item in self.tabBar.items! {
if let image = item.image {
//item.image = image.withRenderingMode(.alwaysTemplate)
item.image = image.withRenderingMode(.alwaysOriginal) //Use default image colour as grey colour and your centre image default colour as white colour as your requirement.
}
}
//Change the backgound colour of specific tabBarItem.
let itemIndex:CGFloat = 2.0
let bgColor = UIColor.black
let itemWidth = tabBar.frame.width / CGFloat(tabBar.items!.count)
let bgView = UIView(frame: CGRect.init(x: itemWidth * itemIndex, y: 0, width: itemWidth, height: tabBar.frame.height))
bgView.backgroundColor = bgColor
tabBar.insertSubview(bgView, at: 0)
}
// MARK: - UITabbarController Override Methods .
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
}
// MARK: - UITabBarControllerDelegate Methods
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
return true
}
}
Use tabBarItem images default colour as grey according to your UI and centre tabBarItem image default colour as white colour in Asset.
And you will want to extend the UIImage class to make the plain colored image with the size you need:
extension UIImage {
func makeImageWithColorAndSize(color: UIColor, size: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(CGRect.init(x: 0, y: 0, width: size.width, height: size.height))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
You can add a subview to the parent tabBar
Then you can set a background color on the subview.
Calculating the offset and width of your tabBarItem and inserting the subView under it.
let itemIndex = 2
let bgColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1.0)
let itemWidth = tabBar.frame.width / CGFloat(tabBar.items!.count)
let bgView = UIView(frame: CGRectMake(itemWidth * itemIndex, 0, itemWidth, tabBar.frame.height))
bgView.backgroundColor = bgColor
tabBar.insertSubview(bgView, atIndex: 0)
Try this :
UITabBar.appearance().tintColor = UIColor.pink
UITabBar.appearance().barTintColor = UIColor.white
if #available(iOS 10.0, *) {
UITabBar.appearance().unselectedItemTintColor = UIColor.white
} else {
// Fallback on earlier versions
}
let x = Double(UIScreen.main.bounds.width / 5.0)
let y = Double(tabBarController!.tabBar.frame.size.height)
let indicatorBackground: UIImage? = self.image(from: UIColor.black, for: CGSize(width: x, height: y))
UITabBar.appearance().selectionIndicatorImage = indicatorBackground
Helper Methods
func image(from color: UIColor, for size: CGSize) -> UIImage {
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
autoreleasepool {
UIGraphicsBeginImageContext(rect.size)
}
let context: CGContext? = UIGraphicsGetCurrentContext()
context?.setFillColor(color.cgColor)
context?.fill(rect)
let image: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
You can use imageView to achieve this affect , try this approach
let myImageView: UIImageView = {
let imageView = UIImageView()
return imageView
}()
// Now add this imageView as subview and apply constraints
tabbar.addSubview(myImageView)
myImageView.translatesAutoresizingMaskIntoConstraints = false
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[v0(28)]", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": myImageView]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[v0(28)]", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": myImageView]))
tabbar.myImageView.image = UIImage(named: "ic_center")?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
tabbar.myImageView.tintColor = UIColor.black

Swift 3 - full width of UITabBarItem for selectionIndicatorImage

i have a UITabBar with three tabs. Now I want to assign or lets say to fill the complete width of one tab to the related selectionIndicatorImage cause currently I got a border if a tab is selected. Like the tab on the left side shows in the following screenshot:
I made a subclass of UITabBar with a new property:
var activeItemBackground:UIColor = UIColor.white {
didSet {
let numberOfItems = CGFloat((items!.count))
let tabBarItemSize = CGSize(width: frame.width / numberOfItems,
height: frame.height)
selectionIndicatorImage = UIImage.imageWithColor(color: activeItemBackground,
size: tabBarItemSize).resizableImage(withCapInsets: .zero)
frame.size.width = frame.width + 4
frame.origin.x = -2
}
}
And the UIImage-Extension in order to have backgroundColor and an image:
extension UIImage
{
class func imageWithColor(color: UIColor, size: CGSize) -> UIImage
{
let rect: CGRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
I read much stuff about this problem but unfortunately I can't get it to work. Is something missing in my code?
I think you're taking a couple extra steps...
You are calculating the exact size of the tab bar item, and creating an image of that size, so you shouldn't need the .resizableImage part.
And, since you are setting to exact size, you also shouldn't need to resize the tab bar frame.
This appears to work fine in my testing (using your .imageWithColor func):
class MyTabBar: UITabBar {
var activeItemBackground:UIColor = UIColor.white {
didSet {
let numberOfItems = CGFloat((items!.count))
let tabBarItemSize = CGSize(width: frame.width / numberOfItems,
height: frame.height)
selectionIndicatorImage = UIImage.imageWithColor(color: activeItemBackground,
size: tabBarItemSize)
}
}
}
Then in viewDidLoad of the first VC:
if let tb = self.tabBarController?.tabBar as? MyTabBar {
tb.activeItemBackground = UIColor.red
}

how to make UITabBar selection indicator image fill the whole space? [duplicate]

This question already has answers here:
Set background color of active tab bar item in Swift
(3 answers)
IOS 8 Tab Bar Item Background Colour
(5 answers)
Closed 10 days ago.
I have a UITabBarController where I use this code to set selection indicator image:
let selectedBG = UIImage(named:"tabbarbgtest.png")?.resizableImageWithCapInsets(UIEdgeInsetsMake(0, 0, 0, 0))
UITabBar.appearance().selectionIndicatorImage = selectedBG
But the image does not fill the whole space - see image below:
The image is just a red square with a solution on 82x49px, but with a wider image it still does not fill the whole space. Hope you guys can help - thanks.
As of 2017, the other answers didn't work for me. After a couple of days searching for another solution, I found mine - by subclassing the UITabBarController.
It works for multiple devices even with rotation.
Notes:
Make your images' rendering mode as Original.
Assign this class below to your UITabBarController in your Storyboard or as your base class if you're doing your screen programmatically.
//
// BaseTabBarController.swift
// MyApp
//
// Created by DRC on 1/27/17.
// Copyright © 2017 PrettyITGirl. All rights reserved.
//
import UIKit
class BaseTabBarController: UITabBarController {
let numberOfTabs: CGFloat = 4
let tabBarHeight: CGFloat = 60
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
updateSelectionIndicatorImage()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
updateSelectionIndicatorImage()
}
func updateSelectionIndicatorImage() {
let width = tabBar.bounds.width
var selectionImage = UIImage(named:"myimage.png")
let tabSize = CGSize(width: width/numberOfTabs, height: tabBarHeight)
UIGraphicsBeginImageContext(tabSize)
selectionImage?.draw(in: CGRect(x: 0, y: 0, width: tabSize.width, height: tabSize.height))
selectionImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
tabBar.selectionIndicatorImage = selectionImage
}
}
To support iPhone X(below code works for all versions), write your code in viewDidLayoutSubviews().
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let tabWidth = (tabBar.frame.width/CGFloat(tabBar.items!.count))
let tabHeight = tabBar.frame.height
self.tabBar.selectionIndicatorImage = imageWithColor(color: UIColor.white, size: CGSize(width: tabWidth, height: tabHeight)).resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
}
Source: https://github.com/Ramotion/animated-tab-bar/issues/191
This relatively simple solution in objective c worked for me for iPhone X, wouldn't be hard to convert to swift:
CGFloat bottomPadding = 0;
if (#available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.keyWindow;
bottomPadding = window.safeAreaInsets.bottom;
}
[UITabBar.appearance setSelectionIndicatorImage:[UIImage imageWithColor:[UIColor lightGrayColor]
andBounds:CGRectMake(0, 0, self.tabBar.frame.size.width/5, self.tabBar.frame.size.height + bottomPadding)]];
This is an adaptation on Glenn's solution above...
import UIKit
class BaseTabBarController: UITabBarController {
var tabBarBounds: CGRect? {
didSet {
guard tabBarBounds != oldValue else { return }
updateSelectionIndicatorColor(UIColor.green)
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tabBarBounds = tabBar.bounds
}
func updateSelectionIndicatorColor(_ tintColor: UIColor) {
guard let tabBarItems = self.tabBar.items else { return }
let tabWidth = tabBar.bounds.width
let tabHeight = tabBar.bounds.height
let tabSize = CGSize(width: tabWidth / CGFloat(tabBarItems.count), height: tabHeight)
var selectionImage = UIImage(color: tintColor, size: tabSize)
UIGraphicsBeginImageContext(tabSize)
selectionImage?.draw(in: CGRect(x: 0, y: 0, width: tabSize.width, height: tabSize.height))
selectionImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
tabBar.selectionIndicatorImage = selectionImage
}
}
public extension UIImage {
public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
color.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let cgImage = image?.cgImage else { return nil }
self.init(cgImage: cgImage)
}
}
you should take a look at this to make the tabbarbgtest.png resizable, then assign the image to selectionIndicatorImage, you can even do this in the storyboard editor.

Resources