Resize WebView for ipad swift 3 - swift

I have a First View, where when I click on one button, it opens an UIWebView,
I want this webView to take only 3/4 of my view when I look at it from an Ipad, if it's an Iphone I want to get a full screen view.
Here is my code :
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
I try the method init with arbitrary values frame: .init(x: 20, y: 20, width: 20, height: 20)
But it's still taking full screen, for detect if it's an Ipad I use this condition
if (UIScreen.main.traitCollection.userInterfaceIdiom.rawValue == 1)
{
// if here I'm an Ipad I can resize my webview
webView.frame.size.height = view.frame.height - // some number
}

Isn't this exactly what adaptive user interfaces and size classes in Interface Builder is for? Have a look at this WWDC video from 2014.

Related

Identifying Objects in Firebase PreBuilt UI in Swift

FirebaseUI has a nice pre-buit UI for Swift. I'm trying to position an image view above the login buttons on the bottom. In the example below, the imageView is the "Hackathon" logo. Any logo should be able to show in this, if it's called "logo", since this shows the image as aspectFit.
According to the Firebase docs page:
https://firebase.google.com/docs/auth/ios/firebaseui
You can customize the signin screen with this function:
func authPickerViewController(forAuthUI authUI: FUIAuth) -> FUIAuthPickerViewController {
return FUICustomAuthPickerViewController(nibName: "FUICustomAuthPickerViewController",
bundle: Bundle.main,
authUI: authUI)
}
Using this code & poking around with subviews in the debuggers, I've been able to identify and color code views in the image below. Unfortunately, I don't think that the "true" size of these subview frames is set until the view controller presents, so trying to access the frame size inside these functions won't give me dimensions that I can use for creating a new imageView to hold a log. Plus accessing the views with hard-coded index values like I've done below, seems like a pretty bad idea, esp. given that Google has already changed the Pre-Built UI once, adding a scroll view & breaking the code of anyone who set the pre-built UI's background color.
func authPickerViewController(forAuthUI authUI: FUIAuth) -> FUIAuthPickerViewController {
// Create an instance of the FirebaseAuth login view controller
let loginViewController = FUIAuthPickerViewController(authUI: authUI)
// Set background color to white
loginViewController.view.backgroundColor = UIColor.white
loginViewController.view.subviews[0].backgroundColor = UIColor.blue
loginViewController.view.subviews[0].subviews[0].backgroundColor = UIColor.red
loginViewController.view.subviews[0].subviews[0].tag = 999
return loginViewController
}
I did get this to work by adding a tag (999), then in the completion handler when presenting the loginViewController I hunt down tag 999 and call a function to add an imageView with a logo:
present(loginViewController, animated: true) {
if let foundView = loginViewController.view.viewWithTag(999) {
let height = foundView.frame.height
print("FOUND HEIGHT: \(height)")
self.addLogo(loginViewController: loginViewController, height: height)
}
}
func addLogo(loginViewController: UINavigationController, height: CGFloat) {
let logoFrame = CGRect(x: 0 + logoInsets, y: self.view.safeAreaInsets.top + logoInsets, width: loginViewController.view.frame.width - (logoInsets * 2), height: self.view.frame.height - height - (logoInsets * 2))
// Create the UIImageView using the frame created above & add the "logo" image
let logoImageView = UIImageView(frame: logoFrame)
logoImageView.image = UIImage(named: "logo")
logoImageView.contentMode = .scaleAspectFit // Set imageView to Aspect Fit
// loginViewController.view.addSubview(logoImageView) // Add ImageView to the login controller's main view
loginViewController.view.addSubview(logoImageView)
}
But again, this doesn't seem safe. Is there a "safe" way to deconstruct this UI to identify the size of this button box at the bottom of the view controller (this size will vary if there are multiple login methods supported, such as Facebook, Apple, E-mail)? If I can do that in a way that avoids the hard-coding approach, above, then I think I can reliably use the dimensions of this button box to determine how much space is left in the rest of the view controller when adding an appropriately sized ImageView. Thanks!
John
This should address the issue - allowing a logo to be reliably placed above the prebuilt UI login buttons buttons + avoiding hard-coding the index values or subview locations. It should also allow for properly setting background color (also complicated when Firebase added the scroll view + login button subview).
To use: Create a subclass of FUIAuthDelegate to hold a custom view controller for the prebuilt Firebase UI.
The code will show the logo at full screen behind the buttons if there isn't a scroll view or if the class's private constant fullScreenLogo is set to false.
If both of these conditions aren't meant, the logo will show inset taking into account the class's private logoInsets constant and the safeAreaInsets. The scrollView views are set to clear so that a background image can be set, as well via the private let backgroundColor.
Call it in any signIn function you might have, after setting authUI.providers. Call would be something like this:
let loginViewController = CustomLoginScreen(authUI: authUI!)
let loginNavigationController = UINavigationController(rootViewController: loginViewController)
loginNavigationController.modalPresentationStyle = .fullScreen
present(loginNavigationController, animated: true, completion: nil)
And here's one version of the subclass:
class CustomLoginScreen: FUIAuthPickerViewController {
private var fullScreenLogo = false // false if you want logo just above login buttons
private var viewContainsButton = false
private var buttonViewHeight: CGFloat = 0.0
private let logoInsets: CGFloat = 16
private let backgroundColor = UIColor.white
private var scrollView: UIScrollView?
private var viewContainingButton: UIView?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// set color of scrollView and Button view inside scrollView to clear in viewWillAppear to avoid a "color flash" when the pre-built login UI first appears
self.view.backgroundColor = UIColor.white
guard let foundScrollView = returnScrollView() else {
print("😡 Couldn't get a scrollView.")
return
}
scrollView = foundScrollView
scrollView!.backgroundColor = UIColor.clear
guard let foundViewContainingButton = returnButtonView() else {
print("😡 No views in the scrollView contain buttons.")
return
}
viewContainingButton = foundViewContainingButton
viewContainingButton!.backgroundColor = UIColor.clear
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Create the UIImageView at full screen, considering logoInsets + safeAreaInsets
let x = logoInsets
let y = view.safeAreaInsets.top + logoInsets
let width = view.frame.width - (logoInsets * 2)
let height = view.frame.height - (view.safeAreaInsets.top + view.safeAreaInsets.bottom + (logoInsets * 2))
var frame = CGRect(x: x, y: y, width: width, height: height)
let logoImageView = UIImageView(frame: frame)
logoImageView.image = UIImage(named: "logo")
logoImageView.contentMode = .scaleAspectFit // Set imageView to Aspect Fit
logoImageView.alpha = 0.0
// Only proceed with customizing the pre-built UI if you found a scrollView or you don't want a full-screen logo.
guard scrollView != nil && !fullScreenLogo else {
print("No scrollView found.")
UIView.animate(withDuration: 0.25, animations: {logoImageView.alpha = 1.0})
self.view.addSubview(logoImageView)
self.view.sendSubviewToBack(logoImageView) // otherwise logo is on top of buttons
return
}
// update the logoImageView's frame height to subtract the height of the subview containing buttons. This way the buttons won't be on top of the logoImageView
frame = CGRect(x: x, y: y, width: width, height: height - (viewContainingButton?.frame.height ?? 0.0))
logoImageView.frame = frame
self.view.addSubview(logoImageView)
UIView.animate(withDuration: 0.25, animations: {logoImageView.alpha = 1.0})
}
private func returnScrollView() -> UIScrollView? {
var scrollViewToReturn: UIScrollView?
if self.view.subviews.count > 0 {
for subview in self.view.subviews {
if subview is UIScrollView {
scrollViewToReturn = subview as? UIScrollView
}
}
}
return scrollViewToReturn
}
private func returnButtonView() -> UIView? {
var viewContainingButton: UIView?
for view in scrollView!.subviews {
viewHasButton(view)
if viewContainsButton {
viewContainingButton = view
break
}
}
return viewContainingButton
}
private func viewHasButton(_ view: UIView) {
if view is UIButton {
viewContainsButton = true
} else if view.subviews.count > 0 {
view.subviews.forEach({viewHasButton($0)})
}
}
}
Hope this helps any who have been frustrated trying to configure the Firebase pre-built UI in Swift.

Scaling content in WKWebView

I recently started working on WKWebView and have minimum knowledge about it.
I want to know how to scale the content in the WKWebView so that it fits into the given view size without scrolling.
I have tried setting the height of the view to be screen size and load some large html content to the WKWebView and disable scrolling. Then only a part of the content is shown.
Then I searched for the approach to scale the content of the WKWebView so that the entire content is seen without need for scrolling.
Many people have posted questions regarding this but some questions were still unanswered and some other solutions did not work for me.
For the WKWebView try the following three options depending upon your requirement:
webview being the webview in your file
webView.contentMode = .scaleAspectFill
or
webView.contentMode = .scaleAspectFit
or
webView.contentMode = .scaleToFill
Given a webView object of type WKWebView you can do
webView.contentMode = .scaleToFill
This 'contentMode' will work after set webview frame correctly (need to fit to the device).
var webView: WKWebView!
func setupView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: view.bounds.size.height), configuration: webConfiguration)
webView.uiDelegate = self
webView.contentMode = .scaleAspectFit
webView.sizeToFit()
webView.autoresizesSubviews = true
self.view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}

IOS Swift web view control, hiding the header and footer

When using the web view control in IOS 10, how do you hide the header and footer ( the grey boxes)? I am using the UIWebView that I drag to the viewcontrol. The web view has the grey boxes at the time it is placed in the storyboard. I have used the web view with previous versions and didn't see these boxes.
You can try setting the web view programmatically:
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height), configuration: null)
let url = URL(string: "http://www.google.com")
let urlRequest = URLRequest(url: url!)
webView.load(urlRequest)
self.view = webView

UIImageView and UIWebView in UIScrollView

I have added UIImageView with view frame height and width and below that UIWebView has to be loaded. I am not sure how to implement this. I tried to add both in UIScrollView. Image is perfectly displaying but WebView not loaded. Adding UIWebView to UIScrollView is not good practice as its below screen, I need to make it in scroll. I am not using Storyboard, all through programming.
Please suggest what should be the best approach to implement this. Wether to use UIWebView in UIScrollView or if added then why it's not loaded. It comes blank.
func viewDidLoad(){
var image = UIImage(frame: view.bounds)
var webView = UIWebView(frame: CGRect(x: 0, y: self.view.frame.height, width: self.view.frame.width, height: self.view.frame.height))
var scrollView = UIScrollView()
scrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height*2)
webView.delegate = self
webView.loadRequest(URLRequest(url: URL(string: "http://www.google.com")))
scrollView.addSubview(image)
scrollView.addSubView(webView)
self.view.addSubview(scrollView)
}
func webViewDidFinishLoad(_ webView: UIWebView){
}
func webViewDidStartLoad(_ webView: UIWebView){
}
Thanks
Your code is fine.
Please check if you are getting this error:
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
If you are getting this error, then add this in info.plist file:

Keeping video playing within the webView instead of presenting fullscreen?

I know in iOS 10 you can pinch the video player to keep the video playing within the webview. Is there any way to set the webview so that the video player doesn't open in full screen on default?
webView.allowsInlineMediaPlayback = true
is what I believe you are looking for
The following is working for in WKWebView in swift 4.1
The main part of the WKWebView in WKwebviewConfiguration
wkwebView.navigationDelegate = self
wkwebView.allowsBackForwardNavigationGestures = true
self.wkwebView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true
wkwebView = WKWebView(frame: wkwebView.frame, configuration: config)
self.view.addSubview(wkwebView)
self.wkwebView.load(NSURLRequest(url: URL(string: self.getUrl())!) as URLRequest)