I'm trying to get the black circle to go on top of the red Nav Bar but am lost for how to achieve. This is what I have so far:
override func viewDidAppear(_ animated: Bool) {
//Adding the button
let buttonImage = #imageLiteral(resourceName: "button")
var buttonView : UIImageView {
let view = UIImageView(image: buttonImage)
view.translatesAutoresizingMaskIntoConstraints = false
view.frame = CGRect(x: self.view.frame.maxX - 100, y: -100, width: 200, height: 200)
view.backgroundColor = .clear
return view
}
super.view.addSubview(buttonView)
}
Try this one. This should put the image on top of the nav bar.
override func viewDidAppear(_ animated: Bool) {
//Adding the button
navigationController?.navigationBar.addSubview(buttonView)
let navBar = navigationController?.navigationBar
// use this navBar to set your framing and constraints
let buttonImage = #imageLiteral(resourceName: "button")
var buttonView : UIImageView {
let view = UIImageView(image: buttonImage)
view.translatesAutoresizingMaskIntoConstraints = false
view.frame = CGRect(x: self.view.frame.maxX - 100, y: -100, width: 200, height: 200)
view.backgroundColor = .clear
return view
}
}
Related
I'm trying to create a welcome onboarding for the first time users but none of the views are loafing in the simulator, all I'm getting is a red background when the onboardingVC gets presented. Can anyone see the issue as to why the titles, buttons, and images won't appear?
This is the message I'm getting in the console:
Warning: Attempt to present <EMA.WalkthroughVC: 0x7faa2401e5b0> on <EMA.HomeVC: 0x7faa22407e00> whose view is not in the window hierarchy!
FOUND ALL!!
let holderView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = true
view.backgroundColor = .darkGray
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view.backgroundColor = UIColor.red
configure()
}
private func configure() {
let scrollView = UIScrollView(frame: holderView.bounds)
holderView.addSubview(scrollView)
let titles = ["Hi","Welcome","real nigga"]
for x in 0..<3 {
let pageView = UIView(frame: CGRect(x: CGFloat(x) * holderView.frame.size.width, y: 0, width: holderView.frame.size.width, height: holderView.frame.size.height))
scrollView.addSubview(pageView)
let label = UILabel(frame: CGRect(x: 10, y: 10, width: pageView.frame.size.width-20, height: 120))
let imageView = UIImageView(frame: CGRect(x: 10, y: 10+120+10, width: pageView.frame.size.width-20, height: pageView.frame.size.height - 60 - 130 - 15))
let button = UIButton(frame: CGRect(x: 10, y: pageView.frame.size.height - 60, width: pageView.frame.size.width-20, height: 50))
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
pageView.addSubview(label)
label.text = titles[x]
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "BankCard\(x)")
pageView.addSubview(imageView)
button.setTitleColor(.red, for: .normal)
button.backgroundColor = .black
button.setTitle("Continue", for: .normal)
if x == 2 {
button.setTitle("Get Started", for: .normal)
}
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
pageView.addSubview(button)
}
}
#objc func didTapButton(_ button: UIButton) {
}
}
"whose view is not in the window hierarchy"
you didn't add the views that you created to the main view try to add the subviews to the main by using this one
self.view.addSubview(holderView)
also don't forget to add the frame for the holder view like that
UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
view.translatesAutoresizingMaskIntoConstraints = true
and inside the view did load
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.view.addSubview(holderView)
}
I have a UITabBarController and four UIViewControllers associated with it. I created a custom view in the place of the navigation bar in the UITabBarController subclass, so this custom view will be common for all the UIViewControllers. There are two buttons in the custom view when one of the buttons is tapped, I want to add and open the "FilesViewController.xib" as a child view controller to the currently active UIViewController.
Below is what I tried so far and it is not adding the FilesViewController.xib as a child view controller. What I'm doing wrong?
import UIKit
class RootTabBarController: UITabBarController {
var topBarHeight:CGFloat = 87.0
override func viewDidLoad() {
super.viewDidLoad()
let containerView = UIView()
self.view.addSubview(containerView)
containerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: topBarHeight)
containerView.backgroundColor = UIColor.init(red: 113.0/255.0, green: 193.0/255.0, blue: 34.0/255.0, alpha: 1.0)
let filesButton = UIButton()
containerView.addSubview(filesButton)
filesButton.frame = CGRect(x: logoutButton.frame.origin.x-46, y: 40, width: 40, height: 40)
filesButton.setImage(UIImage(named: "folder"), for: .normal)
filesButton.addTarget(self, action: #selector(openFileViewController(_:)), for: .touchUpInside)
}
func configureFilesController() // Old Function
{
let filesController = FilesViewController()
self.addChild(filesController)
self.view.addSubview(filesController.view)
filesController.didMove(toParent: selectedViewController)
let height = view.frame.height
let width = view.frame.width
filesController.view.frame = CGRect(x: 0, y: self.view.frame.maxY, width: width, height: height)
}
func configureFilesController() // New One
{
filesController = FilesViewController.init(nibName: "FilesViewController", bundle: nil)
self.addChild(filesController)
self.view.addSubview(filesController.view)
let height = view.bounds.height
let width = view.bounds.width
filesController.view.frame = CGRect(x: 0, y: height/2, width: width, height: height/2)
filesController.view.layer.cornerRadius = 5.0
filesController.didMove(toParent: self)
}
#objc func openFileViewController(_ sender: UIButton) {
print("Tapped")
configureFilesController()
}
}
import UIKit
class FilesViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
}
override func viewWillAppear(_ animated: Bool) {
prepareBackGroundView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Adding the below line worked like what I was expecting
self.view.frame = CGRect(x: 0, y: self.view.bounds.height, width: self.view.bounds.width, height: self.view.frame.height)
UIView.animate(withDuration: 0.3) { [weak self] in
let frame = self?.view.frame
let yComponent = UIScreen.main.bounds.height - 200
self?.view.frame = CGRect(x: 0, y: yComponent, width: frame!.width, height: frame!.height)
}
}
func prepareBackGroundView(){
let blurEffect = UIBlurEffect.init(style: .dark)
let visualEffect = UIVisualEffectView.init(effect:blurEffect)
let blurView = UIVisualEffectView.init(effect: blurEffect)
blurView.contentView.addSubview(visualEffect)
visualEffect.frame = UIScreen.main.bounds
blurView.frame = UIScreen.main.bounds
view.insertSubview(blurView, at: 0)
}
}
you can find the solution here stackoverflow answer. by using this answer I have created sample program. Here I added two tabs one child controller created in story board and another one created in xib.
my RootTabBarController looks like
import UIKit
class RootTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let child1 = storyBoard.instantiateViewController(identifier: "Child1ViewController")
let child2 = Child2ViewCOntroller.init(nibName: "Child2ViewCOntroller", bundle: nil)
let tabItem1:UITabBarItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 0) // customise TabBar with images and title
let tabItem2:UITabBarItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 1)
child1.tabBarItem = tabItem1
child2.tabBarItem = tabItem2
self.setViewControllers([child1,child2], animated: true)
}
}
I was wondering the best approach to put an image into the navigation bar.
My initial thought was to create a cocoa touch class for UINavigationController and set it up that way, but I can seem to get it to working using the below code:
class NavBarImage: UINavigationController {
override func awakeFromNib() {
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self.setupView()
}
func setupView()
{
let navController = navigationController!
let image = #imageLiteral(resourceName: "BarTabsNavLogoWhite")
let imageView = UIImageView(image: image)
let bannerWidth = navController.navigationBar.frame.size.width
let bannerHeight = navController.navigationBar.frame.size.height
let bannerX = bannerWidth / 2 - image.size.width / 2
let bannerY = bannerHeight / 2 - image.size.height / 2
imageView.frame = CGRect(x: bannerX, y: bannerY, width: bannerWidth,
height: bannerHeight)
imageView.contentMode = .scaleAspectFit
navigationItem.titleView = imageView
}
}
I keep getting an "unexpectedly found nil while unwrapping an optional value" on let navController = navigationController!.
However, this method has also been working for me too. I created a cocoa touch class for UINavigationBar and used this code below:
import UIKit
class NavBarImg: UINavigationBar {
override init(frame: CGRect) {
super.init(frame: frame)
initialise()
}
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)!
initialise()
}
func initialise(){
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 225, height: 40))
imageView.contentMode = .scaleAspectFit
let image = UIImage(named:"BarTabsNavLogoWhite")
imageView.image = image
imageView.frame.origin = CGPoint(x: self.superview?.center.x, y: self.superview?.center.y)
addSubview(imageView)
}
}
The only problem with this is that on different iPhones I cant figure out how to get the image to always be centered on any device using CGPoint.
Then for the last method I found and implemented is done by the code below:
#IBDesignable class test: UINavigationBar { #IBInspectable var imageTitle: UIImage? = nil {
didSet {
guard let imageTitle = imageTitle else {
topItem?.titleView = nil
return
}
let imageView = UIImageView(image: imageTitle)
imageView.frame = CGRect(x: 0, y: 0, width: 40, height: 30)
imageView.contentMode = .scaleAspectFit
topItem?.titleView = imageView
}
}
}
I really like this method because with the IBDesignable function you can see it in the storyboard. However the way I have my viewcontrollers set up with tableviews, after i go past the first view controller, the navigation bar image disappears in all other view controllers when I run the simulator.
Looking for advice to see which method is the best approach and how to possibly solve the problems I am having. Or if anyone has a different method that they have found that works, id love to see how it works!
you can simply add a image or customize the barbutton as follows:
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "icon_right"), for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
button.frame = CGRect(x: 0, y: 0, width: 53, height: 31)
button.imageEdgeInsets = UIEdgeInsetsMake(-1, 32, 1, -32)//move image to the right
let label = UILabel(frame: CGRect(x: 3, y: 5, width: 20, height: 20))
label.font = UIFont(name: "Arial-BoldMT", size: 16)
label.text = "title"
label.textAlignment = .center
label.textColor = .black
label.backgroundColor = .clear
button.addSubview(label)
let barButton = UIBarButtonItem(customView: button)
self.navigationItem.rightBarButtonItem = barButton
I want to set logo of app as background image to UINavigationBar and when user traverse into app it should display logo as well as back button on top of it.
Below is code that I've used :
func setNavigationBar() {
let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height
let screenSize: CGRect = UIScreen.mainScreen().bounds
let objCustomView = CustomView(frame: CGRect(x: 0, y: 0, width: screenSize.width, height: navigationBarHeight))
let objWindow = UIApplication.sharedApplication().keyWindow
objWindow?.addSubview(objCustomView)
self.navigationItem.setHidesBackButton(false, animated:true);
self.navigationItem.backBarButtonItem = UIBarButtonItem(title:"", style:.Plain, target:nil, action:nil)
}
The issue with this is that back button goes behind the image.
How to fix this?
After refering post by #NDoc I'm getting extra space in left. Why so?
Also, the back button should be white with no back text i.e. only < arrow.
Below is code for customView :
class CustomView: UIView {
var imgLogo = UIImageView(frame:CGRectZero)
override init(frame: CGRect) {
super.init(frame: frame)
let screenSize: CGRect = UIScreen.mainScreen().bounds
imgLogo.frame = CGRectMake(0, 0, screenSize.width, 44.0)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
imgLogo.image = UIImage(named:"BoM_Logo")
self.addSubview(imgLogo)
}
}
You can display your logo in leftBarButtonItem and set the leftItemsSupplementBackButton to true to display backButton also like this.
let logoView = UIImageView(frame: CGRect(x: 0, y: 0, width: 60, height: 30))
logoView.image = UIImage(named: "Logo")
let item = UIBarButtonItem(customView: logoView)
self.navigationItem.leftBarButtonItem = item
To show the back button with your logo image set leftItemsSupplementBackButton to true
self.navigationItem.leftItemsSupplementBackButton = true
Edit:
If you want custom arrow then you need to use leftBarButtonItems and pass array of BarButtonItem and no need to set leftItemsSupplementBackButton to true like this.
let logoView = UIImageView(frame: CGRect(x: 0, y: 0, width: 60, height: 30))
logoView.image = UIImage(named: "Logo")
let logoItem = UIBarButtonItem(customView: logoView)
let btnBack = UIButton(frame: CGRect(x: 0, y: 0, width: 25, height: 25))
btnBack.setImage(UIImage(named: "Back_Arrow"), forState: .Normal)
btnBack.addTarget(self, action: #selector(self.buttonAction(_:)), forControlEvents: .TouchUpInside)
let backItem = UIBarButtonItem(customView: btnBack)
self.navigationItem.leftBarButtonItems = [backItem, logoItem]
Note: Don't forgot to add buttonAction action method inside your viewController.
Try this in your appDelegate
let image = UIImage.init(named:"upper-bar.png")
UINavigationBar.appearance().setBackgroundImage(image,forBarMetrics:UIBarMetrics.Default)
for back button try this in the viewDidLoad() of your viewController
let image1 = UIImage(named: "go10.png") as UIImage?
let btnLeft = UIButton(type: .Custom)
btnLeft.frame = CGRectMake(0, 0, 25, 25)
btnLeft.setImage(image1,forState:UIControlState.Normal)
btnLeft.addTarget(self, action:(#selector(NameofyourViewController.backBtn(_:))),forControlEvents:UIControlEvents.TouchUpInside)
let leftBarButton = UIBarButtonItem(customView: btnLeft)
self.navigationItem.leftBarButtonItem = leftBarButton
#IBAction func backBtn(sender: UIButton)
{
self.navigationController?.popViewControllerAnimated(true)
}
I am trying to create a custom titleView for a navigation bar. I am able to set the titleView in the root view controller that is embedded in a navigation controller.
When I push the second view controller onto the stack and try to set the titleView for this view controller it does not work. The titleView quickly appears and disappears. When I go back to the previous view controller this titleView quickly appears and disappears now also.
Does anyone know why this is happening or how to set the titleView correctly without flashing and disappearing?
class FirstViewController: UIViewController {
var titleView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
addTitleView()
}
func addTitleView() {
titleView = UIView(frame: CGRect(x: 0, y: 0, width: 150, height: 44))
let companyLabel = UILabel(frame: CGRect(x: 0, y: 3, width: 150, height: 11))
companyLabel.text = "CPS Dashboard"
companyLabel.textColor = UIColor.grayColor()
companyLabel.textAlignment = .Center
companyLabel.font = UIFont.systemFontOfSize(9)
titleView.addSubview(companyLabel)
let titleLabel = UILabel(frame: CGRect(x: 0, y: 16, width: 150, height: 18))
titleLabel.text = "Dashboard"
titleLabel.textColor = UIColor.blackColor()
titleLabel.textAlignment = .Center
titleLabel.font = UIFont.systemFontOfSize(15)
titleView.addSubview(titleLabel)
navigationItem.titleView = titleView
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Show" {
let controller = segue.destinationViewController as! SecondViewController
controller.titleView = titleView
}
}
}
The second viewcontroller:
class SecondViewController: UIViewController {
var titleView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
if let titleView = titleView {
navigationItem.titleView = titleView
}
}
}
I found a solution. I copied addTitleView() method from FirstViewController into SecondViewController, and called both of them in viewDidLoad(). This worked exactly as I wanted it to. For some reason it was not working to pass the titleView forward as a property and assigning it to navigationItem.titleView.
class FirstViewController: UIViewController {
var titleView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
addTitleView()
}
func addTitleView() {
titleView = UIView(frame: CGRect(x: 0, y: 0, width: 150, height: 44))
let companyLabel = UILabel(frame: CGRect(x: 0, y: 3, width: 150, height: 11))
companyLabel.text = "CPS Dashboard"
companyLabel.textColor = UIColor.grayColor()
companyLabel.textAlignment = .Center
companyLabel.font = UIFont.systemFontOfSize(9)
titleView.addSubview(companyLabel)
let titleLabel = UILabel(frame: CGRect(x: 0, y: 16, width: 150, height: 18))
titleLabel.text = "Dashboard"
titleLabel.textColor = UIColor.blackColor()
titleLabel.textAlignment = .Center
titleLabel.font = UIFont.systemFontOfSize(15)
titleView.addSubview(titleLabel)
navigationItem.titleView = titleView
}
}
The second viewcontroller:
class SecondViewController: UIViewController {
var titleView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
addTitleView()
}
func addTitleView() {
titleView = UIView(frame: CGRect(x: 0, y: 0, width: 150, height: 44))
let companyLabel = UILabel(frame: CGRect(x: 0, y: 3, width: 150, height: 11))
companyLabel.text = "CPS Dashboard"
companyLabel.textColor = UIColor.grayColor()
companyLabel.textAlignment = .Center
companyLabel.font = UIFont.systemFontOfSize(9)
titleView.addSubview(companyLabel)
let titleLabel = UILabel(frame: CGRect(x: 0, y: 16, width: 150, height: 18))
titleLabel.text = "Dashboard"
titleLabel.textColor = UIColor.blackColor()
titleLabel.textAlignment = .Center
titleLabel.font = UIFont.systemFontOfSize(15)
titleView.addSubview(titleLabel)
navigationItem.titleView = titleView
}
}
My solution is simple, and it works:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let tv = navigationItem.titleView {
print("transform", tv.transform)) // is always identity
let bounds = tv.bounds
print("bounds", bounds) // its origin may not be zero.
tv.bounds = CGRect(origin: .zero, size: bounds.size)
print("new bounds", tv.bounds)
}
}
Using Xcode's view debugger, you will find that titleView.bounds.origin is not zero.
How to let it happen again, two steps:
1. UIViewController A and B; A has custom navigationItem.titleView, B hides navigationBar in its viewWillAppear(); when B poped, A.viewWillAppear() setNavigationBar(hidden: false, animated: true)
2. user-driven popViewController is canceled by lifting your hand.
Then you will found, A's navigationBar is blank.
I was having this same issue, but none of the above solutions fixed it for me. My issue was that I was setting translatesAutoresizingMaskIntoConstraints to false. I imagine this caused the appearing/disappearing because it needs to be set to true in order to constrain the view internally to the navigation bar.