How to disabled uiwebview auto scroll to top when finished load - ios

I added same subviews in the UIWebView's scrollview.When the webview get contentSize the scrollview will scroll to top.Now I'know the event happend before finished(some images may still loading) but after get the text content.What should i do?
This is the code,and to see the bug you need slow down the request(use edge)!! Before load finished scroll the view,then wait.When the request finished you will see the view scroll to top .
class WebViewController: UIViewController {
var mw = UIScreen.mainScreen().bounds.width
var mh = UIScreen.mainScreen().bounds.height
override func viewDidLoad() {
super.viewDidLoad()
var web = UIWebView(frame: CGRect(x: 0, y: 0, width: mw, height: mh))
var scrollview = web.scrollView
var tmp = UIView(frame: CGRect(x: 0, y: 0, width: mw, height: 300))
tmp.backgroundColor = UIColor.redColor()
scrollview.addSubview(tmp)
(scrollview.subviews.first as UIView).frame.origin.y = 300
let requestURL = NSURL(string: "http://stackoverflow.com/questions/27008545/how-to-disabled-uiwebview-auto-scroll-to-top-when-finished-load")
let request = NSURLRequest(URL: requestURL!)
web.loadRequest(request)
self.view.addSubview(web)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

first you need to set the setContentSize: to the actual content size, not the frame size. That is if your content is e.g. 800px high, you should setContentSize:CGSizeMake(width, 800). using this you can set a UIScrollView that it should scroll to show 800px high content. If you set a UIScrollView's content size equal to its frame, no scrolling is performed and no scroll indicators appear .

Related

How iOS's coordinate system works? [duplicate]

This question already has an answer here:
Why iOS coordinate system is difficult to understand?? only me?
(1 answer)
Closed 5 years ago.
nice to meet you. I am studying "Coordinate System" of UIView of iOS.
Frame is easy to understand, but Bounds isn't.
For example, Frame works as expected when you change origin.
Bounds does not change its position even if we change origin.
import UIKit
class ViewController: UIViewController {
var childView : UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let rect = CGRect(x: 20, y: 30, width: 200, height: 200)
childView = UIView(frame: rect)
childView.backgroundColor = UIColor.red
self.view.addSubview(childView)
}
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 5, animations: {
self.childView.bounds = CGRect(x: 100, y: 150, width: 200, height: 200)
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
"Why do we need Bounds?" I thought.
And I searched hard on the internet. So, there are some facts I found out.
----First----
Bounds literally means borderline. iOS can draw a picture only within that boundary line. As you can see in the figure above, the UIButton also has Bounds, and when it exceeds the Bounds, the picture is cut and drawn.
---- Second ----
Size of Bounds and Size of Frame are the same.
It's not important, but I tried to test it out.
---- Thirds ----
bounds.origin is also useful in View Hierarchy. But it works differently from Frame.
Frame is easy to understand.
The ViewController's RootView will be 700 from top to button.
import UIKit
class ViewController: UIViewController {
var childView : UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let rect = CGRect(x: 100, y: 100, width: 200, height: 200)
childView = UIView(frame: rect)
childView.backgroundColor = UIColor.red
self.view.addSubview(childView)
self.view.backgroundColor = UIColor.cyan
}
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 10, animations: {
self.view.frame = CGRect(x: 0, y: 700, width: self.view.frame.size.width, height: self.view.frame.size.height)
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
If you look at the Coordinate System in iOS, you can see that Frame should work like that.
However, Bounds does not move itself, but only the Subview below it. I do not understand this part.
import UIKit
class ViewController: UIViewController {
var childView : UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let rect = CGRect(x: 100, y: 100, width: 200, height: 200)
childView = UIView(frame: rect)
childView.backgroundColor = UIColor.red
self.view.addSubview(childView)
self.view.backgroundColor = UIColor.cyan
}
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 10, animations: {
self.view.bounds = CGRect(x: 0, y: 700, width: self.view.frame.size.width, height: self.view.frame.size.height)
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
So, I searched it in google.
Eventually, I found a mathematical formula for "SubView" to reposition when SuperView.origin.bounds was changed.
( 출처 : article )
CompositedPosition.x = View.frame.origin.x - Superview.bounds.origin.x;
CompositedPosition.y = View.frame.origin.y - Superview.bounds.origin.y;
By the way, why did Apple use these formulas? Basically, based on the "Coordinate System" we think,
CompositedPosition.x = View.frame.origin.x + Superview.bounds.origin.x;
CompositedPosition.y = View.frame.origin.y + Superview.bounds.origin.y;
Is not this formula more intuitive?
So, My Question are these.
When I increase SuperView.bounds.origin.y by 700 in its original state, why does SubView move up not moving down ???
Should I just accept the formula and memorize it?
---------------------------------------------------------------
----------------------------Edit--1----------------------------
Now I Got the concept of bounds by studying UIScrollView!
CompositedPosition.x = View.frame.origin.x - Superview.bounds.origin.x;
CompositedPosition.y = View.frame.origin.y - Superview.bounds.origin.y;
This is right.
This is a picture what I understand.
yes, I agree this picture looks dizzy sorry!
If I scroll UP the scrollview, and bounds.origin.y will increase and offset.y will increase and the subviews attached in scrollview's frame.origin.y will not change but, iOS calculate where the subviews to draw(CompositedPosition) by using that formula so! It looks like that the subviews goes UP!.
In brief, bounds change -> iOS calculate by using that formula -> draw!
First, please post in English or another supported language.
Second I think I might have understand what you are going for and here is the general simple answer.
First there is a coordinate system for everything, but each view also has its own coordinated system. Each subview of a view is defined inside of the superviews coordinate system.
I would try and say more but I am purely going of the pictures. And also even in the post was in English, I have trouble believing this post is a minimal example of the presented problem

Unable to change contentSize of UIScrollview in WKWebView

I'm trying to add a little bit of extra height to the content of a UIScrollView that is within a WKWebView after it loads by adjusting the contentSize property.
I can modify this property, but it somehow keeps changing back to its original size by the time the next layout/display refresh hits.
To test this even further, I attempted to change contentSize in scrollViewDidScroll. Whenever you scroll to the bottom, you can see for a fraction of a second that it's trying add the extra space and keeps reverting back.
I can't reproduce this issue with UIWebView. It works just fine there. Perhaps some changes were added to WKWebView recently? I'm using Xcode 8 and testing on iOS 9/10.
Given my ineptitude with Dropbox I felt badly so put the attached together to try and help you out. If you change the contentInset property of the WKWebView's scrollView rather than contentSize, this seems to work quite well. I agree with you that while you might be able temporarily to change the content size of the scrollView, it reverts quickly; moreover, there are no delegate methods either for UIScrollView or WKWebView that I can find that you might override to counteract this.
The following sample code has a web page and some buttons that allow you to increase or decrease the top and bottom contentInset and animating you to the appropriate point on the scrollView.
import UIKit
import WebKit
class ViewController: UIViewController {
var webView : WKWebView!
var upButton : UIButton!
var downButton : UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let webFrame = CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: self.view.frame.width - 200, height: self.view.frame.height - 200))
webView = WKWebView(frame: webFrame)
webView.load(URLRequest(url: URL(string: <PUT RELEVANT URL STRING (NB - THAT YOU ARE SURE IS VALID) HERE>)!))
webView.backgroundColor = UIColor.red
webView.scrollView.contentMode = .scaleToFill
self.view.addSubview(webView)
func getButton(_ label: String) -> UIButton {
let b : UIButton = UIButton()
b.setTitle(label, for: .normal)
b.setTitleColor(UIColor.black, for: .normal)
b.layer.borderColor = UIColor.black.cgColor
b.layer.borderWidth = 1.0
return b
}
let upButton = getButton("Up")
let downButton = getButton("Down")
upButton.frame = CGRect(origin: CGPoint(x: 25, y: 25), size: CGSize(width: 50, height: 50))
downButton.frame = CGRect(origin: CGPoint(x: 25, y: 100), size: CGSize(width: 50, height: 50))
upButton.addTarget(self, action: #selector(increaseContentInset), for: .touchUpInside)
downButton.addTarget(self, action: #selector(decreaseContentInset), for: .touchUpInside)
self.view.addSubview(webView)
self.view.addSubview(upButton)
self.view.addSubview(downButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func increaseContentInset() -> Void {
guard let _ = webView else { return }
webView.scrollView.contentInset = UIEdgeInsetsMake(webView.scrollView.contentInset.top + 100, 0, webView.scrollView.contentInset.bottom + 100, 0)
webView.scrollView.setContentOffset(CGPoint(x: webView.scrollView.contentInset.left, y: -1 * webView.scrollView.contentInset.top), animated: true)
}
func decreaseContentInset() -> Void {
guard let _ = webView else { return }
webView.scrollView.contentInset = UIEdgeInsetsMake(webView.scrollView.contentInset.top - 100, 0, webView.scrollView.contentInset.bottom - 100, 0)
webView.scrollView.setContentOffset(CGPoint(x: webView.scrollView.contentInset.left, y: -1 * webView.scrollView.contentInset.top), animated: true)
}
}
I hope that helps. If you need an answer based specifically on setting the content size then let me know, but I think this is the best option.

UIWebView sizeToFit() Smaller

It appears that using sizeToFit() on a UIWebView does not change the size to be smaller, only larger. This is some set-up code:
var scrollView: UIScrollView!
var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
scrollView = UIScrollView()
scrollView.frame = CGRect(x: 50.0, y: 50.0, width: 800.0, height: 1200.0)
webView = UIWebView()
webView.frame = CGRect(x: 50.0, y: 50.0, width: 800.0, height: 1.0)
webView.scrollView.scrollEnabled = false
webView.delegate = self
webView.scalesPageToFit = false
webView.loadHTMLString("Test", baseURL: nil)
self.view.addSubview(scrollView)
scrollView.addSubview(webView)
}
This is my test code. It changes the size of the content to be VERY LARGE after 3 seconds, then VERY SMALL after another 3 seconds:
dispatch_after_delay_main(3) {
self.webView.loadHTMLString("Test Test Test Test ", baseURL: nil)
// Much longer string abbreviated here
dispatch_after_delay_main(3, block: {
self.webView.loadHTMLString("Test", baseURL: nil)
})
}
This is called after the HTML is loaded. The goal is to change the size of the webView based on the size of its content. Note: I've done this with both .sizeToFit() and sizeThatFits() with the same size result.
func webViewDidFinishLoad(webView: UIWebView) {
webView.frame.size.height = 0.0 // Just in case
webView.sizeToFit()
}
I've omitted the print statements at the end of webViewDidFinishLoad(webView: UIWebView) but they output the size growing, but not decreasing. In other words, it will grow, but then once "Test" is loaded, it does not decrease in size.
(800.0, 1.0) // "Test" (before sizeToFit() called)
(800.0, 1976.0) // "Test Test .... Test "
(800.0, 1976.0) // "Test"
do you need the webview embedded on a scrollView? I think not.
Try to change your HTML string to "<div id='main-html'>Your text</div>" and then on the webViewDidFinishLoad delegate function you will do these things:
First, you get the content height with:
var result : Float = NSString (webView.stringByEvaluatingJavaScriptFromString("document.getElementById('main-html').offsetHeight").floatValue
Second, change the webview height with the result value.
And tries to change the height of webView.scrollView.contentSize using the same result value.
Finally, use the webView.sizeToFit()
Cheers
EDIT:
As you said, you can use:
func webViewDidFinishLoad(webView: UIWebView) {
webView.frame.size.height = 1.0 // Value needs to be > 0.0 and < of the current height
webView.sizeToFit()
}

Scrollview ContentSize

I am trying to make a scrollview with 3 pictures on a sign up/join page for a small app I trying to make. I was using this code below:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
var signInButton: UIButton!
var joinButton: UIButton!
var pageControl: UIPageControl!
#IBOutlet weak var scrollView: UIScrollView!
var colors:[UIColor] = [UIColor.redColor(), UIColor.blueColor(), UIColor.greenColor(), UIColor.yellowColor()]
var frame = CGRectMake(0, 0, 0, 0)
override func viewDidLoad() {
super.viewDidLoad()
signInButton = UIButton(frame: CGRectMake(1/3.0 * self.view.bounds.size.width, 5/6.0 * self.view.bounds.size.height, 23, 60))
joinButton = UIButton(frame: CGRectMake(2/3.0 * self.view.bounds.size.width, 5/6.0 * self.view.bounds.size.height, 23, 60))
pageControl = UIPageControl(frame: CGRectMake(1/2.0 * self.view.bounds.size.width, 70/100.0 * self.view.bounds.size.height, 23, 60))
self.view.addSubview(signInButton)
self.view.addSubview(joinButton)
self.view.addSubview(pageControl)
signInButton.addTarget(self, action: "signInButtonClicked:", forControlEvents: .TouchUpInside)
joinButton.addTarget(self, action: "joinButtonClicked:", forControlEvents: .TouchUpInside)
pageControl.addTarget(self, action: Selector("changePage:"), forControlEvents: UIControlEvents.ValueChanged)
configurePageControl()
scrollView.delegate = self
for index in 0...3 {
frame.size = scrollView.frame.size
frame.origin.x = scrollView.frame.size.width * CGFloat(index)
scrollView.pagingEnabled = true
let view: UIView = UIView(frame: frame)
view.backgroundColor = colors[index]
scrollView.addSubview(view)
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * 4, self.scrollView.frame.size.height)
}
func configurePageControl() {
self.pageControl.numberOfPages = colors.count
self.pageControl.currentPage = 0
self.pageControl.tintColor = UIColor.redColor()
self.pageControl.pageIndicatorTintColor = UIColor.blackColor()
self.pageControl.currentPageIndicatorTintColor = UIColor.greenColor()
}
I put a scrollview on my view controller (using the size class width: Any and height: Any) and pinned all four sides of the scrollview to the view controller. For some reason each of the views I add to the scrollview are not exactly the same width as the iPhone.
For example when, I tried running it on an iPhone 6 the first view extends past the width of the iPhone. And that happens to the second and third view. I want the first view to be the exact width of the iPhone and the second view to be exactly to the right of the first view and so on. There seems to be some overlapping with the first view going past the width of the iPhone.
Could this be because I am using the size class (width: any and height: any) and I should disable size classes and add a scrollview for each iPhone width?
Can someone help me identify the problem here.
Add:
scrollView.setNeedsLayout()
scrollView.layoutIfNeeded()
at the beginning of the viewDidLoad() method.
Always call these two methods before accessing a view's frame when using Auto Layout, otherwise you'll probably get an incorrect size.
The problem is that when viewDidLoad() is called, your view still has a width of 600 (due to your storyboard view controller size of 600x600).
Your constraints dictate that the scroll view should be the same width as the device, but these constraints are only applied after viewDidLoad() finishes, when Auto Layout's next scheduled pass is calculated.
Adding the code above forces Auto Layout to perform a pass, thus giving you the correct frame sizes for subsequent use in your size calculations.
Put your scroll view in , set your constraint. Then grab a UIView, put it IN the scroll view, set it as equal width, equal height, and center it (use CTRL + drag to the scroll view, you'll get a small pop up menu)
Then put your content in the UIView you just created... Bam ! also I personally rename my UIView to ContentView, just for sake
Here's a screen to help :
Now I myself am still having issue with the height, I usually simply use a fixed height for the content view because if I don't it doesn't scroll....

SFSafariViewController NOT fullscreen / content presented on top

I'm making a very simple app for a demo and am trying to present a webpage using SFSafariViewController (I need to use SF versus WKWebView so to be able to access cookies).
I would really like to present the User with some UI buttons, but I've been unable to pull it off.
I tried this snippet (placed in the completion callback of presentViewController():
let width: CGFloat = 66
let x: CGFloat = self.view.frame.width - width
// It can be any overlay. May be your logo image here inside an imageView.
let overlay = UIView(frame: CGRect(x: x, y: 20, width: width, height: 44))
overlay.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
svc.view.addSubview(overlay)
... outlined in this post. In their case, they're attempting to cover the reload button with a small view. Regardless of the use-case, for me the view immediately disappears when I load SFSafariViewController (I can see it for a moment and it disappears).
I was thinking about presenting the button in an .OverContext modal, but then the User would be unable to interact with the SFSafariViewController, which also doesn't work.
Here's essentially what I'm after (pardon the gross, quick mockup) ... basically, SafariViewController with a view presented over it (see bottom) ... the transparency is just to show that it's being presented over Safari).
Any recommendations are greatly appreciated.
Figured it out ... there's likely some slight race condition going on that was preventing the recommended "draw a rectangle" code from working as desired. What I did:
Subclassed SFSafariWebViewController
In viewDidAppear, implemented a slight delay using NSTimer that draws any additional view elements
This also ended up helping me hide the status bar, which was giving me issues (see mockup).
Here's the relevant code:
import UIKit
import SafariServices
class MySafariVC: SFSafariViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
var frame = self.view.frame
let OffsetY: CGFloat = 44
frame.origin = CGPoint(x: frame.origin.x, y: frame.origin.y - OffsetY)
frame.size = CGSize(width: frame.width, height: frame.height + (1 * OffsetY))
self.view.frame = frame
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "drawNavBar", userInfo: nil, repeats: false)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("i laid out my subviews")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
func drawNavBar() {
let height: CGFloat = 44
let y: CGFloat = self.view.frame.height - height
// It can be any overlay. May be your logo image here inside an imageView.
let overlay = UIView(frame: CGRect(x: 0, y: y, width: self.view.frame.width, height: height))
overlay.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.9)
self.view.addSubview(overlay)
}
}

Resources