how to cover the entire screen with a UIView using swift programatically - ios

I'm trying to put a UIview() to cover the full screen so when i press a button i can put a dark mode theme on it. it works ok the only problem is that it does not cover the nav bar which is something i want to do i have looked up a few things i found this code it works on the tutorial i have seen but does not work now think swift have updated the language making that solution old
if let window = UIApplication.shared.keyWindow {
let blackView = UIView()
blackView.backgroundColor = .black
view.addSubview(blackView)
blackView.frame = window.frame
}

Swift 4.X
You can add extension in your project.
extension UIView {
func addToWindow() {
let window = UIApplication.shared.keyWindow!
self.frame = window.bounds
window.addSubview(self)
}
}
Use:
bgView = UIView(frame: UIScreen.main.bounds)
bgView.backgroundColor = UIColor(white: 0, alpha: 0.4)
bgView.addToWindow()

Related

Change statusbar backgroundColor WITHOUT navigationBar (iOS 13)

I'm looking for a way to change the backgroundcolor of the statusBar. There are similar questions, but they all requires a navigationBar. I found this answer, but it makes no sense. He uses properties who are deprecated.
For iOS 12 and below it was really simple to change the backgroundcolor:
let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
statusBar.backgroundColor = UIColor.black
But for iOS 13 it looks really complicated. Is there no similar way to change it?
You can use following way to change the status bar color. It will work for iOS 13. I hope it will work for you
guard let windowScene = (scene as? UIWindowScene) else { return }
if let statusBarFrame = windowScene.statusBarManager?.statusBarFrame {
let statusBarHeight = statusBarFrame.size.height
let statusBarView = UIView.init(frame: CGRect.init(x: 0, y: -statusBarHeight, width: UIScreen.main.bounds.width, height: statusBarHeight))
statusBarView.backgroundColor = UIColor.yellow
self.navigationController?.navigationBar.addSubview(statusBarView)
}
Here is reference link
How to change the status bar background color and text color on iOS 7?

Add overlay to cover entire screen(including status bar)

I have an overlay (UIImageView) which should have a transparent background and alpha. How can I set the imageview such that it covers the entire screen? Currently, it covers the screen but not the UIStatusBar. I am adding the view in AppDelegate's main window as a subview.
The code:
let overlay1 = UIImageView(image: UIImage(named: "overlay-image"))
overlay1.contentMode = .scaleAspectFit
overlay1.backgroundColor = UIColor.black
overlay1.alpha = 0.87
overlay1.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
overlay1.isUserInteractionEnabled = true
overlay1.layer.zPosition = 1
(UIApplication.shared.delegate as? AppDelegate).window.addSubview(overlay1)
After discussion in comments found that changing the backgroundColor of statusBar is the reason why your code is not working properly.
By printing the superView of statusBar I found that statusBar is not added on UIWindow instead it is on UIStatusBarWindow which is probably above the mainWindow.
Also please don't use force unwrapping it can be cause of crash. At last I put a guard to fetch the statusBar, to check if it responds to backgroundColor property, to fetch its superView and adding the overlay on this superView got it working.
Your check for respondToSelector is also wrong. See below code it works as per your requirement.
guard let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView, statusBar.responds(to: NSSelectorFromString("backgroundColor")), let superView = statusBar.superview else {return}
statusBar.backgroundColor = UIColor.red
let overlay1 = UIImageView(image: UIImage(named: "overlay-image"))
overlay1.contentMode = .scaleAspectFit
overlay1.backgroundColor = UIColor.black
overlay1.alpha = 0.87
overlay1.frame = superView.bounds
overlay1.isUserInteractionEnabled = true
overlay1.layer.zPosition = 1
superView.addSubview(overlay1)
Note: Changing the statusBar color is not recommended. You can set its style to default or light.
Okay I just tried with something and it worked. Just use it in your ViewController like:
// You should be using viewDidAppear(_:)
override func viewDidAppear(_ animated: Bool) {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate, let window = appDelegate.window {
let windowFrame = window.frame
let imageView = UIImageView(frame: windowFrame)
imageView.image = #imageLiteral(resourceName: "TakeOff") // use your image
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = UIColor.green.withAlphaComponent(0.2) // replace green with the color you want
window.addSubview(imageView)
}
}
But, remember one thing. It's not a good idea to add an image view as
an overlay. You should always use a UIView as an overlay and add the
image view as a sub view to that overlay.
Screenshot:

UIView added as subview to the Application Window does not rotate when the device rotates

I had created an extension to the UIView and created an ActivityIndicatorView and added it as the subview to UIApplication Window. Now when the device rotates the UIViewController also rotates and not this ActivityIndicatorView.
internal extension UIView{
func showActivityViewWithText(text: String?) -> UIView{
let window = UIApplication.sharedApplication().delegate?.window!!
let baseLineView = window!.viewForBaselineLayout()
let locView = UIView(frame:window!.frame)
locView.backgroundColor = UIColor.clearColor()
locView.center = window!.center
baseLineView.addSubview(locView)
baseLineView.bringSubviewToFront(locView)
let overlay = UIView(frame: locView.frame)
overlay.backgroundColor = UIColor.blackColor()
overlay.alpha = 0.35
locView.addSubview(overlay)
locView.bringSubviewToFront(overlay)
let hud = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)
hud.hidesWhenStopped = true
hud.center = CGPoint(x: locView.frame.size.width/2,
y: locView.frame.size.height/2)
hud.transform = CGAffineTransformMakeScale(1, 1)
hud.color = UIColor.redColor()
hud.startAnimating()
locView.addSubview(hud)
locView.bringSubviewToFront(hud)
}
May be problem is in missed autoresizing mask? Try to add:
hud.autoresizingMask = [ .flexibleTopMargin, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin ]
In a reason your hud is subview of a locView autoresizingMask is required for locView too I suppose.

Why does my UITableViewFooter jump to the top?

self.tableView.tableFooterView = PromptInviteView.instantiateFromNib()
I've tried putting this in viewWillAppear and viewDidLoad.
Great, everything shows up and displays correctly.
However, if:
I push HOME and open 4-5 other apps, then return back to my app, the footer will "jump" to the top, covering the first row.
If I perform other actions inside the app (navigating back and forth), and then finally going back to his vc, then it will jump to the top also.
When I pull to refresh, all is good again. But if I don't do anything...the footer stays at the top (replacing the top row + is not clickable)
Does anyone know why this behavior is occurring, and how I can solve it?
Update: I realize that "drawRect" in my xib gets called when I open the app after 4-5 other apps. And this is why the problem is happening.
In my drawRect code, I have this:
override func drawRect(rect: CGRect) {
super.drawRect(rect)
inviteLabel.textColor = UIColor(hex: 0x404040)
inviteLabel.text = STRINGS["PromptInviteLabelText"]
inviteLabel.numberOfLines = 0
inviteLabel.sizeToFit()
inviteButton.setTitle(STRINGS["PromptInviteButtonText"], forState: UIControlState.Normal)
inviteButton.backgroundColor = FlatWatermelon()
inviteButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
inviteButton.setTitleColor(UIColor(hex: 0xcccccc), forState: UIControlState.Selected)
inviteButton.layer.cornerRadius = 2.0
inviteButton.clipsToBounds = true
super.layoutSubviews() //this will allow the view's frame to be set.
var padding = CGFloat(20.0)
self.frame = CGRectMake(0, 0, screenWidth, CGRectGetMaxY(inviteButton.frame) + padding )
var topBorder = UIView()
topBorder.frame = CGRectMake(0, 0, screenWidth, 0.5)
topBorder.backgroundColor = UIColor(hex: 0xededed)
self.addSubview(topBorder)
var bottomBorder = UIView()
bottomBorder.frame = CGRectMake(0, self.frame.size.height, screenWidth, 0.5)
bottomBorder.backgroundColor = UIColor(hex: 0xededed)
self.addSubview(bottomBorder)
}
How can I remove my code (especially the layoutSubview part) and put it somewhere else?
Is there another location where I should put the code? Is there a didLayoutSubviews() equivalent?

UITabBar change background color of one UITabBarItem on iOS7

Can I change the background color of a specific UITabBarItem in a UITabBar?
I know how to change all the background of the selected background, using:
[[UITabBar appearance] setBarTintColor:[UIColor redColor]];
[[UITabBar appearance] setTintColor:[UIColor blueColor]];
[[UITabBar appearance] setSelectedImageTintColor:[UIColor yellowColor]];
But can it be done for only one item without subclassing?
Thanks
You can add a subview to the parent tabBar, and set a background color on the subview. You can use the tabBar frame dimensions to calculate the offset and width of your tabBarItem, and then insert the subview underneath.
Example (in Swift):
// Add background color to middle tabBarItem
let itemIndex = 2
let bgColor = UIColor(red: 0.08, green: 0.726, blue: 0.702, 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)
in Swift:
This solution is for apps using Auto Layout . Main difference between other solution is that: tabBar.frame.width is not getting actual device's screen width. So, bgView is appearing wrong place.
You can fix it with this : UIScreen.main.bounds.width
let tabWidth: CGFloat = UIScreen.main.bounds.width / CGFloat(self.tabbar!.items!.count)
let tabIndex: CGFloat = 2
let bgColor: UIColor = .redColor
let bgView = UIView(frame: CGRectMake(tabWidth * tabIndex, 0, tabWidth, 49))
bgView.backgroundColor = bgColor
self.tabbar!.insertSubview(bgView, atIndex: 0)
49 is a default height of UITabbar
Objective C solution:
int itemIndex = 3;
UIColor* bgColor = [UIColor colorWithRed:(245/255.f) green:(192/255.f) blue:(47/255.f) alpha:1];
float itemWidth = self.tabBarController.tabBar.frame.size.width / 5.0f; //5 = tab bar items
UIView* bgView = [[UIView alloc]initWithFrame: CGRectMake(itemWidth*itemIndex, 0,itemWidth, self.tabBarController.tabBar.frame.size.height)];
bgView.backgroundColor = bgColor;
[self.tabBarController.tabBar insertSubview:bgView atIndex:1];
Updated for Swift 4:
let itemIndex: CGFloat = 2.0
let bgColor = UIColor.ownBlue
let itemWidth = tabBar.frame.width / CGFloat(tabBar.items!.count)
let bgView = UIView(frame: CGRect(x: itemWidth * itemIndex, y: 0, width: itemWidth, height: tabBar.frame.height))
bgView.backgroundColor = bgColor
tabBar.insertSubview(bgView, at: 0)
You cannot really do this with the tint color property. See this post about the fact that even the setSelectedImageTintColor does not really seem to be working (it did not last time I checked).
The solution is to change the tintColor on the fly for the item in question. You can do this ad hoc whenever the selected item changes by implementing the UITabBarDelegate method tabBar:didSelectItem: e.g. in the app delegate.
Late to the game, but this is how I did it. I made the tabs look like buttons, with rounded views. The answers above, have issues when the device is rotated, or the app is sent into a split window.
This solution marries the background directly to each tab, using auto-layout, so they naturally follow the tab bar changes.
This is done on the custom subclass of UITabBarController.
First, I set the colors (white for unselected, and black for selected), of the icons in the tab items, then, I iterate the tabs, and insert backgrounds to each, using auto layout to have them cleave to the tabs:
override func viewDidLoad() {
super.viewDidLoad()
let appearance = UITabBarAppearance()
appearance.stackedLayoutAppearance.normal.iconColor = .white
appearance.stackedLayoutAppearance.selected.iconColor = .black
appearance.inlineLayoutAppearance.normal.iconColor = .white
appearance.inlineLayoutAppearance.selected.iconColor = .black
appearance.compactInlineLayoutAppearance.normal.iconColor = .white
appearance.compactInlineLayoutAppearance.selected.iconColor = .black
tabBar.subviews.forEach {
if let item = $0 as? UIControl {
let wrapper = UIView()
wrapper.isUserInteractionEnabled = false
wrapper.clipsToBounds = true
wrapper.backgroundColor = tabBar.tintColor
wrapper.layer.cornerRadius = 8
item.insertSubview(wrapper, at: 0)
wrapper.translatesAutoresizingMaskIntoConstraints = false
wrapper.leadingAnchor.constraint(equalTo: item.leadingAnchor).isActive = true
wrapper.trailingAnchor.constraint(equalTo: item.trailingAnchor).isActive = true
wrapper.topAnchor.constraint(equalTo: item.topAnchor).isActive = true
wrapper.bottomAnchor.constraint(equalTo: item.bottomAnchor).isActive = true
}
}
}
The reason this works, is that the tab bar implements the tab items as an internal subclass of UIControl, which is a UIView.
I can add views underneath the control.
This ends up looking like this:
NB: Turning off user interaction is important, as is inserting at 0.
The drawback is that there's no way to tell which item is the selected one (at the time the background images are created).
ALSO NB: Apple REALLY doesn't want us mucking about in the tab bar, so I could see this method (as well as the ones above), breaking in some future OS upgrade.

Resources