swift 3, iOS - UIImageView for background - swift3

I currently have several labels and buttons in a UIView. I am using Storyboards and I want to add an image to the background. I tried it this way:
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(patternImage: UIImage(named:"background.png")!)
But unfortunately, this does not look right in the larger screen sizes. I think that I need to add a UIImageView. When I added a UIImageView, I couldn't figure out how to set it to be in the background so my button and labels could still be seen.

let someImageView: UIImageView = {
let theImageView = UIImageView()
theImageView.image = UIImage(named: "yourImage.png")
return theImageView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(someImageView) //This add it the view controller without constraints
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
someImageView.frame = view.bounds
}

In your storyboard:
1- Add a UIImageView (inside your main view and outside everything else) and set its image to the image you want.
2- setup its constraints properly to fill the screen (give it 0 from all sides).
3- From attribute inspector, set Content Mode property to Aspect Fit.

I solved this problem by going to the panel in Storyboards and moving the UIImageView above the container view that held the labels and buttons. The UIImageView remained inside of the View, but moved to the background (under the buttons and labels).

Related

Swiftui checking if UIHostingController is presented

I have 2 screens with which I am navigating between them. One screen is for clicking a button to navigate to the other screen and the other screen is for presenting some other information.
Screen one
I have the following piece of swift code since screen 2 uses third part library
let host = UIHostingController(rootView: AnyView(vc))
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let application = windowScene?.windows.first
ScanGuideContainer(title: self.viewModel.defaultLocalizer.stringForKey(key: ""), icon: icon,action: {
application?.rootViewController?.present(host, animated: true, completion: {
})
})
.environmentObject(viewModel)
This automatically launches a modal pop which then navigates to Screen2.
Screen 2
This screen has two options either to go back to the modal by pressing the back button or automatically go back once done processing some information which when it does so it returns a new value which then I can use to dismiss the host automatically since its a boolean value.
I can access the second screen viewController via
secondScreen?.viewController
How can i dismiss the modal from first screen when user presses back button of second screen?
What I tried
.onChange(of: self.ViewModel.dismissModal){ newvalue in
if(newvalue) {
host.dismiss(animated: true)
}
}
I set self.ViewModel.dismissModal value from second screen on but it does not work. please help

UIHostingViewController background color showing

I am showing a UIViewController via a SwiftUI view, like so:
#available(iOS 13, *)
struct WelcomeNavView: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<WelcomeNavView>) -> UINavigationController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navVc = storyboard.instantiateViewController(withIdentifier: "welcomeNav") as! UINavigationController
return navVc
}
func updateUIViewController(_ uiViewController: UINavigationController, context: UIViewControllerRepresentableContext<WelcomeNavView>) {
}
}
I then present it from a ViewController like so:
self.viewController?.present(style: .fullScreen) {
WelcomeNavView()
}
However, it does not occupy the entire screen and the UIHostViewController color is showing at the top and bottom:
How can I change the color of the UIHostingViewController's view.. Or expand the View it is holding to occupy the entire screen?
Another simple and quick solution is, you can ignore safe area of your WelcomeNavView() while presenting.
example
iOS 13:
WelcomeNavView().edgesIgnoringSafeArea(.all)
iOS 14 and above:
WelcomeNavView().ignoresSafeArea()
Here is the solution,
I ran into similar problem, wherein I had to set hosting view controller's background clear.
Apparently, rootView (probably our SwiftUI View) of hostingVC and hostingVC.view are different.
so this would allow you to change to background color.
hostingVC.view.backgroundColor = .clear
Of course use any color in place of ".clear".
Just keep in mind to change color of SwiftUI view passed as rootView to hostingVC accordingly, mostly make that clear, so it won't be shown against above set color.
Your_SwiftUI_View.background(Color.clear)

How to create Side Menu on right side in Swift 3.0?

I am a beginner and I wanted to create a side menu on the right side.
So far I have a UIButton on right top side of viewController, what I want is when I click that button I want to show/hide slide menu with say 3 items…
when I click each item it will go to the different view controller. In my project, i am showing slide menu in only one viewController using AMSlideMenu. Thanks in advance.
Anuj just follow the steps-
Create a SideMenuViewController which is sub class of UIViewController , using storyboard how it will look according to the requirement.
Add this SideMenuViewController and its view as a child view controller in parent view controller by UIButton click.
When you done, remove SideMenuViewController from parent View controller and remove its view from parent view.
Repeat 2 and 3 for all view controllers.
Updated code :
Declare in your view controller -
var sideMenuViewController = SideMenuViewController()
var isMenuOpened:Bool = false
In viewDidLoad
sideMenuViewController = storyboard!.instantiateViewController(withIdentifier: "SideMenuViewController") as! SideMenuViewController
sideMenuViewController.view.frame = UIScreen.main.bounds
In your button Clicked event -
func openAndCloseMenu(){
if(isMenuOpened){
isMenuOpened = false
sideMenuViewController.willMove(toParentViewController: nil)
sideMenuViewController.view.removeFromSuperview()
sideMenuViewController.removeFromParentViewController()
}
else{
isMenuOpened = true
self.addChildViewController(sideMenuViewController)
self.view.addSubview(sideMenuViewController.view)
sideMenuViewController.didMove(toParentViewController: self)
}
}
For Animation:
let transition = CATransition()
let withDuration = 0.5
transition.duration = withDuration
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromLeft
sideMenuViewController.view.layer.add(transition, forKey: kCATransition)
There is no built-in control in iOS for side-menu. However, you could use different open source libraries to achieve your goal.
Have a look at the following libraries:
https://github.com/John-Lluch/SWRevealViewController
The detailed tutorial for this library:
http://www.appcoda.com/ios-programming-sidebar-navigation-menu/
http://www.raywenderlich.com/32054/how-to-create-a-slide-out-navigation-like-facebook-and-path

Get the height of the UIScrollView after layout in Swift

I have a situation where I'm using a UIScrollView to help users with smaller phones see the full text inside a window. And I was wanting to show an image icon if they needed to scroll (just so that they know there is more inside the window) but I'm having a problem finding the height of the scrollview using Swift.
This is the hierarchy of my objects
Basically, those 4 labels fit inside a 4.7" iPhone but not the 4" iPhone. I tried setting some logic to check if the UIScrollView content is larger than the window, but it doesn't seem to be working. I keep getting that the height is zero.
I'm using scrollHeight = scrollView.contentSize.height and have tried putting that inside of viewDidLoad(), viewWillAppear(), and viewDidLayoutSubviews() but every time it ends up being 0.
Is contentSize the right thing I should be using to check the height?
TL;DR;
As a general guide, Auto Layout does not finish giving views their size by the time viewDidLoad is called (neither is it correct inside viewDidLayoutSubviews). To make sure all views and their subviews have their correct sizes before querying their bounds or frame, do:
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
print(self.someSubview.frame) // gives correct frame
Explanation
Somewhat counterintuitively, putting your code inside viewDidLayoutSubviews does not mean all sub-views have been given their correct size by Auto Layout. To quote the docs for this method:
However, this method being called does not indicate that the individual layouts of the view's subviews have been adjusted.
What this means is that: inside viewDidLayoutSubviews, only the first hierarchical-level of sub-views will have their correct size (i.e. child views but not "grandchild views").
Here is an example layout I created (the red view is the child, the blue view is the grandchild).
A few important points about this example:
All views are positioned using Auto Layout constraints to their parent view (fixed margins, but not fixed widths), this allows them to grow or shrink depending on the screen size of the simulator I run this on.
I've used an iPhone 7 sized view controller in my storyboard, and ran the example on an iPhone 7 Plus Simulator. This means I can be sure the views will grow somewhat and use this to determine whether or not a view has its original size or its final size.
Note that in Interface Builder, the original width of the child view (red) is 240 points and the original width of the grandchild view (blue) is 200 points.
And here is the code:
class ViewController: UIViewController {
#IBOutlet weak var childView: UIView!
#IBOutlet weak var grandchildView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
print("child ", #function, childView.frame.size.width)
print("grandchild", #function, grandchildView.frame.size.width)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("child ", #function, childView.frame.size.width)
print("grandchild", #function, grandchildView.frame.size.width)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("child ", #function, childView.frame.size.width)
print("grandchild", #function, grandchildView.frame.size.width)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("child ", #function, childView.frame.size.width)
print("grandchild", #function, grandchildView.frame.size.width)
}
}
And here is the output:
child viewDidLoad() 240.0
grandchild viewDidLoad() 200.0
child viewWillAppear 240.0
grandchild viewWillAppear 200.0
child viewDidLayoutSubviews() 271.0 // `child` has it's final width now
grandchild viewDidLayoutSubviews() 200.0 // `grandchild` still has it's original width!
// By now, in MOST cases, all views will have their correct sizes.
child viewDidAppear 271.0
grandchild viewDidAppear 231.0
What you can see from this output is that viewDidLayoutSubviews does not guarantee that anything past the immediate sub-views of the View Controller's principal view have their correct size.
Note: Usually by the time viewDidAppear is called, views have their correct size, but I'd say this is by no means guaranteed.

Navigation Bar showing without been added

There is the Main Storyboard, from there three other storyboards with Navigation Controller, each one connected to a 4 view controllers so they use the back button to go back to their respective storyboard. Each Storyboard has a Storyboard reference to return to the Main Storyboard. Problem: each time the secondaries storyboards return to the main storyboard appears a Navigation Bar with
I used the following code in viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBarHidden = true
}
and also on viewWillAppear:
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = true
}