Experts,
I am using following code to hide the tool and nav bars before capturing the screen view. However the image still shows both bars...what I'am I doing wrong?
func generateMeme() ->UIImage {
// Hide toolbar and navbar
self.navigationController?.navigationBarHidden = true
self.navigationController?.toolbarHidden = true
// Render view to an image
UIGraphicsBeginImageContext(self.view.frame.size)
self.view.drawViewHierarchyInRect(self.view.frame,afterScreenUpdates:true)
let memedImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Show toolbar and navbar
self.navigationController?.navigationBarHidden = true
self.navigationController?.toolbarHidden = true
return memedImage
}
Thanks
I'm not doing a screenshot, but I had a similar need - I have a viewController with a UIToolbar at the bottom that I wanted to hide sometimes. I created an outlet to it; and used
#IBOutlet weak var toolBar: UIToolbar!
// later in the code where you don't want it visible anymore
toolBar.isHidden = true
but then there was still space allocated for the toolbar at the bottom of the window; and if the item in the scrollView it was next to was large enough it was really obvious that there was still something there blocking space.
I solved this by selecting the toolbar, and using Embed -> Stack View. Make sure and adjust the constraints of the stackview, setting each top, bottom, left and right to 0. now the same line of code will hide the toolbar, and because it's in a UIStackView, it no longer takes up any space.
You should be able to do the same; hide the toolbar, then snap the image.
Swift 5.1
Hiding the toolbar will be
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.setToolbarHidden(true, animated: true
}
I was able to solve the issue by using reference outlet and then using the hidden property. Below is the code:
// Reference outlet for Tool Bar
#IBOutlet weak var toolBar: UIToolbar!
//Reference outlet for Navigation Bar
#IBOutlet weak var navBar: UINavigationBar!
//Generate meme
func generateMeme() ->UIImage {
// Hide toolbar and navbar
self.toolBar.hidden = true
self.navBar.hidden = true
// Render view to an image
UIGraphicsBeginImageContext(view.frame.size)
view.layer.renderInContext(UIGraphicsGetCurrentContext())
let memedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//Show tool and nav bars
self.toolBar.hidden = false
self.navBar.hidden = false
return memedImage
}
Just use this(below) line at specific place in your code after that
your toolBar will be removed permanently:
self.tabBarController?.tabBar.isHidden = true
func getScreenShot() -> UIImage {
UIGraphicsBeginImageContext(view.frame.size)
view.layer.renderInContext(UIGraphicsGetCurrentContext())
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
return image
}
This should hide the navigationbar and toolbar. You can find the image in the Photos.
I had been exactly in the same problem and I tried your solution but the wrong was that , I suppose you were trying to address the default navigation controller built in toolbar while you need to address your own toolbar that you created in the story board. I solved the problem as follow
create an outlet from my toolbar to the view controller
#IBOutlet weak var toolbarView: UIToolbar!
make it hidden
self.navigationController?.isNavigationBarHidden = true
self.toolbarView.isHidden = true
Related
I'm using UIStackView and it contains 3 UIView instances, which has fixed height
I'm trying to hide these subviews by clicking button
first and second view show/hide well with proper animation
but last view doesn't animate
class ViewController: UIViewController {
private var flag: Bool = true
#IBOutlet weak var targetView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttonDidTapped(_ sender: Any) {
flag = !flag
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
self.targetView.isHidden = !self.flag
}
}
}
The issue is the way stack views change their frames when hiding an arranged subview.
Easiest way to see what's happening:
set your Green view to Alpha: 0.5
toggle .isHidden on the Blue view
You'll see that the 50% translucent Green view "slides up over" the Blue view... the Blue view does not "shrink in height" during the animation.
To solve your specific issue, set Clips To Bounds to true on your stack view. Now, when you toggle .isHidden on your Green view, the animation will look correct.
That will not change the "slide over" appearance if you have translucent views, but that's a different issue.
As a side note, you can simplify your code and get rid of the flag like this:
UIView.animate(withDuration: 0.5) {
// not needed
//self.view.layoutIfNeeded()
self.targetView.isHidden.toggle()
}
Try change your code from:
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
self.targetView.isHidden = !self.flag
}
to:
self.targetView.isHidden = !self.flag
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
Looks like you animate before change.
I've been struggling for a while with setting up a circular profile picture as a bar button item. The picture comes from a URL using SDWebImage. When I run the app the item appears as a square and all the other right bar button items shift left. Also ran into the same issues when trying to set the object as a UIButton. Does anybody know how I could set a circular mask on the object, and/or why the other bar button items shift left?
#IBOutlet weak var myAvatarButton: UIBarButtonItem! {
didSet {
guard let userImageURL = CurrentUser.shared.imageURL else {
return
}
let avatarImage = UIImageView()
avatarImage.sd_setImage(with: userImageURL, placeholderImage: #imageLiteral(resourceName: "noProfilePhoto"), options: [.refreshCached, .retryFailed, .highPriority]) { [weak self] (image, error, cacheType, imageURL) in
self?.myAvatarButton.image = image?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
}
}
}
In viewDidLoad add myAvatarButton.clipsToBounds = true might work.
But the better approach would be using customView in your UIBarButtonItem.
try this :
...
let avatarImage = UIImageView()
avatarImage.layer.clipsToBounds = true
avatarImage.layer.cornerRadius = avatarImage.frame.width / 2
...
It should set cornerRadius to the exact value to have your view circular.
Since I was getting the image programmatically from a URL this was a little tricky. Turns out the easiest way was to embed a UIImageView inside a View which can be inserted via storyboard into the navigation bar. From there, I created an IBOutlet and changed the corner radius. Also the other bar buttons were no longer shifted over after adjusting the image view's width.
I cant create saperate custom popview.. so I have tried like below mentioned one of the answer
here is storyboard view hierarchy
popBG view background colour is black with alpha = 0.3
this is code:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var popViewtop: UIView!
#IBOutlet weak var testTable: UITableView!
#IBOutlet weak var popView: UIView!
#IBOutlet weak var popBG: UIView!
override func viewDidLoad() {
super.viewDidLoad()
popViewtop.isHidden = true
}
#IBAction func testBtn(_ sender: Any) {
popViewtop.isHidden = false
}
#IBAction func btnPop(_ sender: Any) {
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "NewZoomAddressViewController") as! NewZoomAddressViewController;
popViewtop.isHidden = true
self.navigationController?.pushViewController(viewController, animated: true);
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
now the tableview and button are not showing transperently.. only popbg and popview coming.. did i miss anything..
Actually i need like this: total backgroundview in some darkcolour and popupview heighlighted in white colour
if giving alpha value to view,
view's subView's alpha value changes, including popupView
if giving background color to view, including popupView
view's subView's alpha value does not change, including popupView
popupView is a subView of view,view's alpha value affects its subviews's alpha.
view.addSubview(popupView)
Your current structure:
RootView->Subviews //Changing RootView alpha effects Subviews.
The solution is that the popupView is not a subview of view , which you show color changing with
Need a container view to separate from popupView
// backgroundColorChangeContainerView add other views ( tableView ... )
view.addSubview(backgroundColorChangeContainerView)
view.addSubview(popupView)
Make your Popup view full screen ..which have background and have subview as popUp over that background ...so you dont need to change anything once you show or hide popup and its easy to implement... Full screen UIView having popUp UIView over it
You should have a view called it MainPopUpView ... in this view you will add two UIViews ...
Background View ... with black color with alpha 0.3
PopUpUI View ... which shows actual popup
-> backGround UIView full screen (with alpha 0.3)
MainPopUpView
-> popUpView short & centre and shows actual content
So MainPopUpView have two views ...
here is the hierarchy
other way to achieve like your final image.. custom pop controller avoids this situation
put your popupView in a custom viewController, then
#IBAction func addAddressBtn(_ sender: Any) {
present(PopupViewController(nibName: "PopupViewController", bundle: nil), animated: true) {}
}
I have Implemented top items a view with UICollectionview and UIPagecontroller to get android like pagetabs.
For each menu there is a container ViewController but in one of them need UITabBarController.
Why UITabBarController is going down.
I have tried moving menuVIew(Contacts,Recents,etc) up but still did not work.
For the top view, use UISegmentedControl, and make background color, same as border color.
For the tab bar, you mean that it is covered by home indicator?
Turn on Use Safe Area Layout Guides, for this UITabController, and you should be good to go.
let tabBar = UITabBar()
override func viewDidLoad() {
super.viewDidLoad()
addTabbar()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
addHeightConstraintToTabbar()
}
func addTabbar() -> Void {
self.view.addSubview(tabBar)
tabBar.translatesAutoresizingMaskIntoConstraints = false
tabBar.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
tabBar.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
tabBar.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
let item1 = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.bookmarks, tag: 1)
let item2 = UITabBarItem(tabBarSystemItem: UITabBarSystemItem.contacts, tag: 2)
tabBar.items = [item1, item2]
self.view.bringSubview(toFront: tabBar)
}
func addHeightConstraintToTabbar() -> Void {
let heightConstant:CGFloat = self.view.safeAreaInsets.bottom + 49.0
tabBar.heightAnchor.constraint(equalToConstant: heightConstant).isActive = true
}
Result:
I have faced this issue before for iPhone X. I found a weird solution of this as below:
Change the bottom constraint from TabBar to Safe Area not the Super view and change the constraint value to 1 as shown in the below image.
This works on both The normal devices and devices with notch display. Check out the screenshots :
Hope this helps you.
I am updating my app to use iOS 7 and I'm having a problem with a table view. My tab bar is translucent. The problem is when I scroll to the bottom of my table view, part of the last cell is still behind the tab bar. I'd like to have a bit of space between the last cell and the tab bar. I could fix this by using an opaque tab bar instead, but I want to keep it translucent.
Try setting
self.edgesForExtendedLayout = UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars = NO;
self.automaticallyAdjustsScrollViewInsets = NO;
Inside the tableview controller
Swift 4.x
let adjustForTabbarInsets: UIEdgeInsets = UIEdgeInsetsMake(0, 0, self.tabBarController!.tabBar.frame.height, 0)
self.yourTableView.contentInset = adjustForTabbarInsets
self.yourTableView.scrollIndicatorInsets = adjustForTabbarInsets
Check the screen shot
Check the under top Bar and Un-checke under Bottom Bar
SWIFT 3
put this inside viewDidLoad of your tableViewController:
self.edgesForExtendedLayout = UIRectEdge()
self.extendedLayoutIncludesOpaqueBars = false
self.automaticallyAdjustsScrollViewInsets = false
Swift 3.0
This is what worked for me. In your Custom ViewController:
override func viewDidLoad() {
super.viewDidLoad()
let adjustForTabbarInsets: UIEdgeInsets = UIEdgeInsetsMake(self.tabBarController!.tabBar.frame.height, 0, 0, 0);
//Where tableview is the IBOutlet for your storyboard tableview.
self.tableView.contentInset = adjustForTabbarInsets;
self.tableView.scrollIndicatorInsets = adjustForTabbarInsets;
}
Not to sure I like the solution but it works for me.
With iOS 11 I have no issue, I simply use the following in viewDidLoad():
self.collectionView.bottomAnchor.constraint(self.view.safeAreaLayoutGuide.bottomAnchor).isActive = true
However on iOS 10 I need to hack my way like this:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let tabBarHeight: CGFloat = (self.parent?.tabBarController?.tabBar.frame.size.height)!
if #available(iOS 11.0, *) {
} else {
self.collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -tabBarHeight).isActive = true
}
}
This is working for me
override func viewDidLoad() {
self.edgesForExtendedLayout = UIRectEdge()
self.extendedLayoutIncludesOpaqueBars = false
}
If any view shows behind a UITabBar you can grab the bottomLayoutGuide and make adjustments at runtime. What I do is have a BaseViewController that all my view controllers inherit from. Then if the tab bar is visible we adjust the view like so:
import UIKit
class BaseVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
//Ensures that views are not underneath the tab bar
if tabBarController?.tabBar.hidden == false {
var viewBounds = self.view.bounds;
var bottomBarOffset = self.bottomLayoutGuide.length;
self.view.frame = CGRectMake(0, 0, viewBounds.width, viewBounds.height - bottomBarOffset)
}
}
}
Since I don't use storyboards (where you can click a checkbox in IB to fix this problem), this has been the best solution I have found.
It is really hard to resolve the issue without detail information or actual codes. I have similar issue of tabview behind UItabBar in my project. The solutions offered here do not work in my case. After exploring my codes, I found a solution for my case.
Here is brief explanation of my case. I have a UItabBar in main view with two tab buttons. In one tab view, there is table view. If user taps on a row, a detail view is presented by using navigation controller. In the detail view, the tab bar is hidden, and a toolbar is showing at the bottom.
In order to bring tab bar back and hide the toolbar when the main view is brought back, I have to explicitly show tab bar and hide toolbar in the event of viewWillAppear:
class myMainViewController: UITableViewController {
private var tabBarHidden: Bool? = {
didSet {
self.tabBarController?.tabBar.isHidden = tabBarIsHidden ?? true
}
}
private var toolBarIsHidden: Bool? {
didSet {
let hidden = toolBarIsHidden ?? true
self.navigationController?.toolbar.isHidden = hidden
self.navigationController?.setToolbarHidden(hidden, animated: true)
}
}
...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarIsHidden = false
self.toolBarIsHidden = true
}
...
}
I finally realize that the visibility of bar at the bottom is set in the event of viewWillAppear. At that time, the tableView or scroll view's content insets are set already based on no bar at the bottom. That's why my tableView is behind the bottom bar.
The solution I found is to reset content insets in the event of viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
// In the event of viewWillAppear, visibilities of tool bar and tab bar are set or changed,
// The following codes resets scroll view's content insets for tableview
let topInset = self.navigationController!.navigationBar.frame.origin.y +
self.navigationController!.navigationBar.frame.height
let adjustForTabbarInsets: UIEdgeInsets = UIEdgeInsetsMake(
topInset, 0,
self.tabBarController!.tabBar.frame.height, 0)
self.tableView.contentInset = adjustForTabbarInsets
self.tableView.scrollIndicatorInsets = adjustForTabbarInsets
}
The best approch would be to Embed TabBarController to your ViewController (Editor -> Embed In -> TabBar Controller)and set the bottom of the tableview to be bottom of safe area of viewcontroller. The other ways wont be as perfect as this one.
You need to adjust the height of the table view. Just leave 49px at the bottom, as the tabbar height is 49 px. Adjust the height of table view so that it leaves 49px space below it.