WkwebView - bottom part of the page is not visible - ios

I am rendering website using WkWebView. The problem I am facing is that as shown in the screenshot, if I scroll to the bottom, part of the page (last 2 rows) is not visible. If I drag scrollbar to the bottom, it shows that part of the page and automatically scrolls upwards and that part becomes no longer visible to the user. Do I need to update my webview constraints or change the height of the webview?
Here is the screenshot
here is the code snapshot
let webConfiguration = WKWebViewConfiguration()
let customFrame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: 0.0, height: self.webViewContainer.frame.size.height))
self.webView = WKWebView (frame: customFrame , configuration: webConfiguration)
webView.translatesAutoresizingMaskIntoConstraints = false
self.webViewContainer.addSubview(webView)
addConstraints(to: webView, with: webViewContainer)
func addConstraints(to webView: UIView, with superView: UIView) {
webView.translatesAutoresizingMaskIntoConstraints = false
let leadingConstraint = NSLayoutConstraint(item: webView, attribute: .leading, relatedBy: .equal, toItem: superView, attribute: .leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: webView, attribute: .trailing, relatedBy: .equal, toItem: superView, attribute: .trailing, multiplier: 1, constant: 0)
let topConstraint = NSLayoutConstraint(item: webView, attribute: .top, relatedBy: .equal, toItem: superView, attribute: .top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: webView, attribute: .bottom, relatedBy: .equal, toItem: superView, attribute: .bottom, multiplier: 1, constant: 0)
superView.addConstraints([leadingConstraint, trailingConstraint, topConstraint, bottomConstraint])
}
Any help will be appreciated.

I have noticed this happening before.
I'd recommend
webView.scrollView.isScrollEnabled = false
Webpage is supposed to find out the viewport area and set its width and height using CSS or JS.
Most UI frameworks have support for this by default
So when you scroll the scrolling happens within the webpage rather scrolling in the native view.

Related

WKWebView - Ignore the right "safe area inset" in landscape view

I am fairly new to iOS development and I'm using a WKWebView to render my website. I am trying to add some constraints but want to ignore the right "safe area inset" in landscape view as marked in the screenshot.
Here is the screenshot.
Here is the code.
let webConfiguration = WKWebViewConfiguration()
let customFrame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: 0.0, height: self.webViewContainer.frame.size.height))
self.webView = WKWebView (frame: customFrame , configuration: webConfiguration)
webView.translatesAutoresizingMaskIntoConstraints = false
self.webViewContainer.addSubview(webView)
addConstraints(to: webView, with: webViewContainer)
func addConstraints(to webView: UIView, with superView: UIView) {
webView.translatesAutoresizingMaskIntoConstraints = false
let leadingConstraint = NSLayoutConstraint(item: webView, attribute: .leading, relatedBy: .equal, toItem: superView, attribute: .leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: webView, attribute: .trailing, relatedBy: .equal, toItem: superView, attribute: .trailing, multiplier: 1, constant: 0)
let topConstraint = NSLayoutConstraint(item: webView, attribute: .top, relatedBy: .equal, toItem: superView, attribute: .top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: webView, attribute: .bottom, relatedBy: .equal, toItem: superView, attribute: .bottom, multiplier: 1, constant: 0)
superView.addConstraints([leadingConstraint, trailingConstraint, topConstraint, bottomConstraint])
}
Any help will be appreciated.
Use size classes and change the constraint like below in the image

Wrong NSLayoutConstraint Causes Black Screen

I want to place header view on top of screen with NSLayoutConstraint (I must use NSLayoutConstraint). When I do it like in below code, view places corruptly in somewhere else and also controllers background color turns black and nothing works. Where am I doing wrong?
I searched below posts for not opening a duplicate post but nothing fixed it:
Programmatically creating constraints bound to view controller margins
Programmatically Add CenterX/CenterY Constraints
EDIT: This controller is inside navigation controller but I'm not sure If It is related.
override func viewDidLoad(){
self.view.backgroundColor = UIColor.white
boxView.backgroundColor = Color.Common.welcomeScreenBackgroundColor.withAlphaComponent(0.5)
boxView.translatesAutoresizingMaskIntoConstraints = false
self.view.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubView(boxView)
}
override func viewDidLayoutSubviews() {
//Header = 20 from left edge of screen
let cn1 = NSLayoutConstraint(item: boxView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1.0, constant: 0)
//Header view trailing end is 20 px from right edge of the screen
let cn2 = NSLayoutConstraint(item: boxView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1.0, constant: 0)
//Header view height = constant 240
let cn3 = NSLayoutConstraint(item: boxView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant:240)
//Header view vertical padding from the top edge of the screen = 20
let cn5 = NSLayoutConstraint(item: boxView, attribute: .top, relatedBy: .equal, toItem: self.topLayoutGuide, attribute: .bottom, multiplier: 1.0, constant: 0)
self.view.addConstraints([cn1,cn2,cn3,cn5])
}
The problem was setting translatesAutoresizingMaskIntoConstraints to false on Superview. So I deleted the;
self.view.translatesAutoresizingMaskIntoConstraints = false
and this solves the problem. I think this causes app creates constraint for superview.

How to set an element center of view programmatically in iOS Swift 3?

I have a view and I want to center it horizontally and vertically in its superview.
I tried this but it's not working:
let horConstraint = NSLayoutConstraint(item: webView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0.0)
view.addConstraints([horConstraint])
I would suggest trying to use Anchors which are more convenient and easy to understand. This code centered my view:
let someView = UIView()
someView.backgroundColor = .red
someView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(someView)
NSLayoutConstraint.activate([
someView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
someView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
someView.heightAnchor.constraint(equalToConstant: 50),
someView.widthAnchor.constraint(equalToConstant: 50)
])
Try this:
Note: Make sure that you are setting this property (before applying constraints) to false for webView
webView.translatesAutoresizingMaskIntoConstraints = false
For x axis
let horConstraint = NSLayoutConstraint(item: webView, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX ,multiplier: 1.0, constant: 0.0)
For y axis
let verConstraint = NSLayoutConstraint(item: webView, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY ,multiplier: 1.0, constant: 0.0)
view.addConstraints([horConstraint, verConstraint])

fb login button not displaying properly in view

I have the following code:
override func viewDidLoad() {
super.viewDidLoad()
let fbLoginButton = FBSDKLoginButton()
fbLoginView.contentMode = UIViewContentMode.scaleAspectFit
fbLoginView.addSubview(fbLoginButton)
fbLoginButton.frame.origin = fbLoginView.frame.origin
fbLoginButton.frame = CGRect(x: fbLoginView.frame.origin.x, y: fbLoginView.frame.origin.y, width: fbLoginView.frame.width, height: fbLoginView.frame.height)
print("INFO width: \(fbLoginView.frame.width) height: \(fbLoginView.frame.height)")
print("INFO width: \(fbLoginButton.frame.width) height: \(fbLoginButton.frame.height)")
// fbLoginButton.delegate = self
}
I am trying to add the facebook login button within a small subview that I have in my main view. For some reason when I print out the width/height of the UIView, and facebook login button I see this:
INFO width: 1000.0 height: 1000.0
INFO width: 1000.0 height: 1000.0
BUT when I run the app on the simulator I see that the view isnt 1000.0 x 1000.0 (it would be overflowing off of the screen but it isn't. It looks like this:
You can se the blue of the button, and that its correctly WITHIN the smaller subview but, the button actually seems to be overflowing larger than the view. What I don't get why the view is the correct size in the simulator, but its saying that its size is so large. I've read posts here which tell me to resize the button to aspect fit, and I've played around with all of the other options but no luck.
I have the smaller uiview set up like this:
In viewDidLoad, the app hasn't yet completed its auto-layout pass so many views are 1000x1000pts.
So in your code when you set the loginButton's size to match the loginView's size, it copies the value of 1000 across.
Later on when your app applies its auto layout constraints, the containing loginView is resized to the correct size, but within it the loginButton has its old, larger size.
The correct solution would be to correctly constrain the loginButton using autolayout - the simplest change would be to add constraints to it within loginView so that it's resized at the same time:
NSLayoutConstraint(item: fbLoginButton, attribute: .Trailing, relatedBy: .Equal, toItem: fbLoginView, attribute: .Trailing, multiplier: 1.0, constant: 0.0).active = true
NSLayoutConstraint(item: fbLoginButton, attribute: .Leading, relatedBy: .Equal, toItem: fbLoginView, attribute: .Leading, multiplier: 1.0, constant: 0.0).active = true
NSLayoutConstraint(item: fbLoginButton, attribute: .Top, relatedBy: .Equal, toItem: fbLoginView, attribute: .Top, multiplier: 1.0, constant: 0.0).active = true
NSLayoutConstraint(item: fbLoginButton, attribute: .Bottom, relatedBy: .Equal, toItem: fbLoginView, attribute: .Bottom, multiplier: 1.0, constant: 0.0).active = true
Or it would probably be cleaner to add the Facebook Button within your storyboard directly (add an empty view and set its class to FBSDKLoginButton).
The problem with frames in viewDidLoad() is that they are not layouted. They do not have their final size yet. You could use viewDidLayoutSubviews() for that.
I would suggest to use NSLayoutConstraints, though. Looking at what you were trying to do with your frame, you can simply create the constraints and add them to your view.
let topConstraint = NSLayoutConstraint(item: fbLoginButton, attribute: .top, relatedBy: .equal, toItem: fbLoginView, attribute: .top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: fbLoginButton, attribute: .bottom, relatedBy: .equal, toItem: fbLoginView, attribute: .bottom, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: fbLoginButton, attribute: .leading, relatedBy: .equal, toItem: fbLoginView, attribute: .leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: fbLoginButton, attribute: .trailing, relatedBy: .equal, toItem: fbLoginView, attribute: .trailing, multiplier: 1, constant: 0)
self.view.addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint])

Adding a UISearchController and position it with constraints programmatically

I want to add a leading, trailing, bottom and width constraint programmatically to a UISearchController. This is my code:
#IBOutlet weak var navigationBar: UIView!
// create search bar
searchBar = UISearchController(searchResultsController: nil)
navigationBar.addSubview(searchBar.searchBar)
searchBar.searchBar.translatesAutoresizingMaskIntoConstraints = false
let leftConstraint = NSLayoutConstraint(item: searchBar.searchBar, attribute: .Leading, relatedBy: .Equal, toItem: navigationBar, attribute: .Leading, multiplier: 1, constant: 0)
let rightConstraint = NSLayoutConstraint(item: searchBar.searchBar, attribute: .Trailing, relatedBy: .Equal, toItem: navigationBar, attribute: .Trailing, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: searchBar.searchBar, attribute: .Bottom, relatedBy: .Equal, toItem: navigationBar, attribute: .Bottom, multiplier: 1, constant: 0)
let heightConstraint = NSLayoutConstraint(item: searchBar.searchBar, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 44)
navigationBar.addConstraints([leftConstraint, rightConstraint, bottomConstraint, widthConstraint])
When running the app, the search bar appears correctly, but when I press on the search bar, it shrinks, and if I press another time the app crashes. Here is the output:
2015-08-12 20:20:37.696 Contacts++[96997:8547485] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7fb22580c7a0 UIView:0x7fb225817b20.leading == UIView:0x7fb223449860.leading>
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.
2015-08-12 20:20:37.697 Contacts++[96997:8547485] *** Assertion failure in -[UIView _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3491.2.5/NSLayoutConstraint_UIKitAdditions.m:590
Why do you need to create an instance of 'UISearchController' and get its searchBar?
why not just make the searchBar from UISearchBar?
// create a searchBar from UISearchBar
let searchBar = UISearchBar(frame: CGRectZero)
// add searchBar to navigationBar
navigationController?.navigationBar.addSubview(searchBar)
// call sizeToFit.. this will set the frame of the searchBar to exactly the same as the size of the allowable frame of the navigationBar
searchBar.sizeToFit()
// now reframe the searchBar to add some margins
var frame = searchBar.frame
frame.origin.x = 20
frame.size.width -= 40
searchBar.frame = frame // set new frame with margins
note: you won't need any of those constraint to achieve this.
But if you really prefer the constraint, here's the constraint code without a crash.
let searchBar = UISearchBar(frame: CGRectZero)
navigationController?.navigationBar.addSubview(searchBar)
searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)
let leftConstraint = NSLayoutConstraint(item: searchBar, attribute: .Leading, relatedBy: .Equal, toItem: navigationController?.navigationBar, attribute: .Leading, multiplier: 1, constant: 20) // add margin
let bottomConstraint = NSLayoutConstraint(item: searchBar, attribute: .Bottom, relatedBy: .Equal, toItem: navigationController?.navigationBar, attribute: .Bottom, multiplier: 1, constant: 1)
let topConstraint = NSLayoutConstraint(item: searchBar, attribute: .Top, relatedBy: .Equal, toItem: navigationController?.navigationBar, attribute: .Top, multiplier: 1, constant: 1)
let widthConstraint = NSLayoutConstraint(item: searchBar, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: self.view.frame.size.width - 40) // - margins from both sides
navigationController?.navigationBar.addConstraints([leftConstraint, bottomConstraint, topConstraint, widthConstraint])
Do you really want to set the width of the navigatinBar to 44 points? Width is horizontal. You already have a width constraint by adding trailing and leading constraints.

Resources