How to set background image, but not behind statusbar in Swift iOS - ios

What I've heard there are no real way) to set a background image for a view in swift (tex self.view.background image. After googling around I found this:
var imageView = UIImageView(frame: self.view.frame) // set as you want
var image = UIImage(named: "fade bg3")!
imageView.image = image
self.view.addSubview(imageView)
self.view.sendSubviewToBack(imageView)
It worked but the statusbar (with the clock, battery status and network ex) has that background too. Can I prevent this?
This was the solution
UIImageView(frame: CGRectMake(self.view.frame.origin.x, 20, self.view.frame.size.width, self.view.frame.size.height))

Just Hide your Status bar for those screens.

You really should implement prefersStatusBarHidden on your view controller(s):
override func prefersStatusBarHidden() -> Bool {
return true
}

Related

Swift 5 custom navigation bar cover title and buttons

After seeking a lot and trying many solutions, nope fixed my problem.
In my app I customized the UINavigationController in order to have blur effect:
import UIKit
class CustomNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
visualEffectView.frame = (self.navigationBar.bounds.insetBy(dx: 0, dy: -40).offsetBy(dx: 0, dy: -40))
self.navigationBar.isTranslucent = true
self.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationBar.addSubview(visualEffectView)
self.navigationBar.sendSubviewToBack(visualEffectView)
}
}
Then in Main.storyboard I selected the customized class for the navigation controller item.
The blur effect works properly, the status icons are correctly visible, but not the standard navigation bar items: left button, title and right button.
For a moment they appears but soon after the customized navigation bar covers them.
I'm using Xcode 12.4 and I'm running the app on iPhone Xr.
How can I show the navigation bar elements again?
Thanks a lot in advance.
Translucent navigation bars in iOS already blur the content behind the bar, so you shouldn't need to add a UIVisualEffectView nor set a backgroundImage.
If you modify your code to just:
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationBar.isTranslucent = true
}
does this not achieve the visual effect you're looking for?
If not, please try the following adjustment to your methodology:
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationBar.isTranslucent = true
// create a UIImageView
let backgroundImage: UIImageView = UIImageView()
backgroundImage.autoresizingMask = [.flexibleWidth, .flexibleHeight]
backgroundImage.image = UIImage()
// add a blur effect to the ImageView
let visualEffectView: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
visualEffectView.frame = (self.navigationBar.bounds.insetBy(dx: 0, dy: -40).offsetBy(dx: 0, dy: -40))
backgroundImage.addSubview (visualEffectView)
// and set that as your backgroundImage on the navigationBar
self.navigationBar.setBackgroundImage(backgroundImage.image, for: .default)
}
this adds the blur effect to the backgroundImage. This seems to work for me, but the visual effect is no different than just using my first suggestion, likely because backgroundImage.image == nil.
This is certainly an improved approach in that it doesn't add unexpected subviews into the UINavigationBar view hierarchy, and I observed both methods did not affect the visibility of the bar controls.

Make NavigationBar's titleView larger than itself

I want to place an image in the middle of a navigation bar that is bigger then the bar itself. So far I tried to use a UIView with a UIImageView inside and it works quite well as you can see here:
However as soon as I push another controller and pop back my ImageView gets cropped to the size of the NavigationBar again.
Any ideas on how to prevent the cropping?
My code so far for iOS 11:
override func viewDidLoad() {
super.viewDidLoad()
let logo = UIImage(named: "Logo")
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
let imageView = UIImageView(image: logo)
imageView.frame = CGRect(x: 0, y: 0, width: titleView.frame.width, height: titleView.frame.height)
titleView.addSubview(imageView)
imageView.contentMode = .scaleAspectFit
imageView.image = logo
navigationItem.titleView = titleView
}
Edit: Currently there is a temporary solution which uses an observer to overwrite the clipsToBounds property of the view that causes the trouble: Link (shout out to #trungduc for that)
I found why you got this issue. It's because of a private view which has name _UINavigationBarContentView. It's a subview of UINavigationBar. navigationItem.titleView is contained in this view.
At first time, when you change navigationItem.titleView. _UINavigationBarContentView.clipsToBounds is false .But after you push another controller and pop back, _UINavigationBarContentView.clipsToBounds is true. That's why titleView is cropped.
So i have a temporary solution. Each time when viewController appears, find this view and change _UINavigationBarContentView.clipsToBounds to false and layout titleView.
override func viewDidAppear(_ animated: Bool) {
for view : UIView in (navigationController?.navigationBar.subviews)! {
view.clipsToBounds = false;
}
navigationItem.titleView?.layoutIfNeeded()
}
override func viewWillAppear(_ animated: Bool) {
for view : UIView in (navigationController?.navigationBar.subviews)! {
view.clipsToBounds = false;
}
navigationItem.titleView?.layoutIfNeeded()
}
I tried and it works. But i think you shouldn't do something whit it because it's private view. Maybe Apple don't want us do anything with it.
Hope somehow my suggestion can help you. Good luck ;)
SOLUTION
Adding observer for _UINavigationBarContentView.clipsToBounds, each time when it changes to false, set to true and update layout of titleView
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let logo = UIImage(named: "Logo")
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
let imageView = UIImageView(image: logo)
imageView.frame = CGRect(x: 0, y: 0, width: titleView.frame.width, height: titleView.frame.height)
titleView.addSubview(imageView)
imageView.contentMode = .scaleAspectFit
imageView.image = logo
navigationItem.titleView = titleView
navigationController?.navigationBar.subviews[2].addObserver(self, forKeyPath: "clipsToBounds", options: [.old, .new], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if (navigationController?.navigationBar.subviews[2].isEqual(object))! {
DispatchQueue.main.async {
self.navigationController?.navigationBar.subviews[2].clipsToBounds = false
self.navigationItem.titleView?.layoutIfNeeded()
}
}
}
deinit {
navigationController?.navigationBar.subviews[2].removeObserver(self, forKeyPath: "clipsToBounds")
}
For more detail and easier, you can check my demo here https://github.com/trungducc/stackoverflow/tree/big-title-navigation-bar
You could try to put the code in the viewWillAppear method. This way you will add the image to the bar everytime the view appears. However you should then remove the inageview within the viewDidDissappear method. If you need it in several views you could subclass the UIViewController and use this one.
The UINavigationBar has UIBarMetrics if you want a custom height but it's not fully interactive.
There's a bunch of code suggested by apple to actually develop nice things like iMessage app.

Swift 3 - Background image issue for my UIViewController in landscape mode

First, this was done programmatically and not in Storyboards.
I am using a background image for my UIViewController. It looks fine in portrait mode but because my image is not wide enough for landscape mode, the image becomes doubled (the same image is shown twice, side by side) when the device is tilted to landscape mode. Is there a way to switch to a different background image if the device is rotated to landscape mode in order to avoid this issue?
Please note: I am trying to do this without having to create an entirely new UIViewController for landscape mode.
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(patternImage: UIImage(named: "backgroundimage.png")!)
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.view.backgroundColor = UIColor.clear
view.addSubview(inputsContainerView)
view.addSubview(loginRegisterButton)
view.addSubview(profileImageView)
view.addSubview(loginRegisterSegmentedControl)
setupInputsContainerView()
setupLoginRegisterButton()
setupProfileImageView()
setupLoginRegisterSegmentedControl()
}
Use UIImageView to set a background image instead of using UIColor(patternImage:) method. See the below code snippet
var backgroundImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
backgroundImageView = UIImageView(frame: CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.width, height: self.view.frame.height))
backgroundImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(backgroundImageView)
}
I have created a backgroundImageView and set the image to that view. In order to handle portrait and landscape mode, autoresizingMask parameter is also set

Fixed background in a TableView?

Fixed Background image in a TableView ?
Hey guys !
My first question as a Swift nOOb !
I'm trying to set up a fixed image as a background for my Table View. So far, the best option has been to include this in my ViewDidLoad :
let uluru = UIImage(named: "Uluru")
self.view.backgroundColor = UIColor(patternImage: uluru!)
Not so great, right?
Especially because when you're scrolling, the image is tiled. Meaning, it's repeating itself. Does anyone has a solution via the IB or directly into the code to make it fixed ? Something like in CSS ?
I also tried the superview way :
override func viewDidAppear(animated: Bool) {
let uluru = UIImage(named: "Uluru")
let uluruView = UIImageView(image: uluru)
self.view.superview!.insertSubview(uluruView, belowSubview:self.view)
}
But no success at all!
And last but not least :
override func viewDidLoad() {
super.viewDidLoad()
let backgroundImage = UIImageView(frame: UIScreen.mainScreen().bounds)
backgroundImage.image = UIImage(named: "Uluru")
self.view.insertSubview(backgroundImage, atIndex: 0)
}
Thank you all!
Do not use the backgroundColor property for this, and do not add any subviews. The table view is all ready for you to do what you want to do. Like this:
Create an image view (UIImageView) whose image is the desired image.
Make that image view the table view's background view (its backgroundView property).

Black background on transparent UITabBar

I am trying to make a blurred background the UITabBar for my UITabViewController, and the idea is to have it be blurred and transparent so that the views underneath can be seen scrolling by.
Unfortunately I cannot for the life of me get the tab bar to be transparent. No matter what I do, there is always some black background to the tab bar that prevents the underlying view controllers from showing through.
If I change the alpha of the UITabBar to something low I can see that the tableview is indeed behind it, however you can see that the UITabBar has some sort of background to it that is preventing the tableview from fully showing through (and I don't want to bar button items to be invisible, just the tab bar background).
How can this be?
In the custom tab bar's view did load I have:
self.tabBar.translucent = true
self.tabBar.alpha = 0.3
self.tabBar.backgroundColor = UIColor.clearColor().colorWithAlphaComponent(0.0)
self.tabBar.layer.backgroundColor = UIColor.clearColor().colorWithAlphaComponent(0.0).CGColor
self.tabBar.backgroundImage = nil
self.tabBar.shadowImage = nil
and in the AppDelegate I have:
UITabBar.appearance().barTintColor = UIColor.clearColor()
UITabBar.appearance().tintColor = kColorAccent
UITabBar.appearance().translucent = true
UITabBar.appearance().translucent = true
UITabBar.appearance().backgroundColor = UIColor.clearColor()
UITabBar.appearance().backgroundImage = nil
UITabBar.appearance().layer.backgroundColor = UIColor.clearColor().CGColor
UITabBar.appearance().shadowImage = nil
...yeah It's excessive but I want to try everything.
Any ideas on what to do?
Make a UITabBar transparent
Assign a clear image to its backgroundImage. You can use a 1x1 clear.png, or create one programmatically:
self.backgroundImage = UIImage.imageWithColor(UIColor.clearColor())
This will make the UITabBar transparent:
Add a blur effect
Insert a UIVisualEffectView as the rearmost subview.
let frost = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
frost.frame = self.bounds
self.insertSubview(frost, atIndex: 0)
This will insert a UIBlurEffect (frost):
Example
Set the Custom Class for the UITabBar of the Tab Bar Controller to FrostyTabBar.
You have a few options to supply a clearColor image. You can create a clear.png image with an alpha of 0. A programmatic elegant solution is described here.
If using a clear.png, assign it to the Background Image in the Attribute Inspector:
In Interface Builder, pick Style: Default & Translucent.
Once you take control of the background blur with a UIVisualEffectView, you can in turn supply any UIVisualEffect you so desire.
The entire FrostyTabBar class looks like this:
import UIKit
class FrostyTabBar: UITabBar {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let frost = UIVisualEffectView(effect: UIBlurEffect(style: .light))
frost.frame = bounds
frost.autoresizingMask = .flexibleWidth
insertSubview(frost, at: 0)
}
}
► Find this solution on GitHub and additional details including a 1x1 clear.png on Swift Recipes.
I found a prefect solution, you only need to subclass UITabBar and then do the following actions to clean that annoying views
class MainTabBar: UITabBar {
var cleanDone = false
override func layoutSubviews() {
super.layoutSubviews()
self.deleteUnusedViews()
}
func deleteUnusedViews() {
if !self.cleanDone {
var removeCount = 0
for (_, eachView) in (self.subviews.enumerate()) {
if NSStringFromClass(eachView.classForCoder).rangeOfString("_UITabBarBackgroundView") != nil {
eachView.removeFromSuperview()
removeCount += 1
}
if NSStringFromClass(eachView.classForCoder).rangeOfString("UIImageView") != nil {
eachView.removeFromSuperview()
removeCount += 1
}
if removeCount == 2 {
self.cleanDone = true
break
}
}
}
}
}
the only solution that worked for me was this:
UITabBar.appearance().shadowImage = UIImage()
UITabBar.appearance().backgroundImage = UIImage()
and set: (you can do this in storyboard as well)
UITabBar.appearance().barTintColor = UIColor.clear
but what i have to set in storyboard is:
tabbar : translucent -> true

Resources