问题
How can I detect UIWebView reaching the top or bottom? Because I need to trigger an action when I reach the bottom.
So is that doable?
回答1:
First of all, you should not put your UIWebView inside a UIScrollView as mentionned in the UIWebView documentation.
Important: You should not embed UIWebView or UITableView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.
Instead, you can access the UIScrollView through the UIWebView properties. Your view controller can implement the UIScrollViewDelegate.
@interface MyViewController : UIViewController<UIScrollViewDelegate>
@end
Then you can hook to the UIScrollView:
- (void)viewDidLoad
{
[super viewDidLoad];
// Set self as scroll view protocol
webView.scrollView.delegate = self;
}
Then finally detect the top and bottom being reached:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if(scrollView.contentOffset.y
>=
(scrollView.contentSize.height - scrollView.frame.size.height)){
NSLog(@"BOTTOM REACHED");
}
if(scrollView.contentOffset.y <= 0.0){
NSLog(@"TOP REACHED");
}
}
Voila, you can detect when top and bottom are reached.
回答2:
If you're targeting iOS 5, UIWebView has a read-only scrollView property that allows you to access the underlying UIScrollView.
From there, you can hook into the scrollView's scrollViewDidScroll: delegate method to receive information on scroll events.
回答3:
You can give this a shot -
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if(scrollView == yourWebView)
{
int percentScrolled = abs((int)ceil((scrollView.contentOffset.y/scrollView.contentSize.height)*100));
if(percentScrolled > 100 || percentScrolled < 0)
percentScrolled = 0;
if(percentScrolled > 90)
{
//scroll percent is 90. do your thing here.
}
}
return;
}
What is being done here is everytime user scrolls webView, calculate the % scrolled & when the % scrolled is coming to end (say anything > 90%) do whatever you planned to do.
回答4:
You could put UIWebView inside a UIScrollView (that has bouncing disabled, so the bounce behavior of the views does not conflict in any way) and then when UIWebView scrolls to bottom, the UIScrollView above will take over scrolling and you can listen to its scrolling events.
Scratch that.
Seems that it's not that simple after all.
You can find the UIScrollView among UIWebView's subviews and tap into its scroll delegate methods.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(@"We scrolled! Offset now is %f, %f", scrollView.contentOffset.x, scrollView.contentOffset.y);
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIWebView *view = (UIWebView *)self.view;
for (UIView * subview in view.subviews) {
if ([subview isKindOfClass:[UIScrollView class]]) {
UIScrollView *webScrollView = (UIScrollView *)subview;
webScrollView.delegate = self;
break;
}
}
[view loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://stackoverflow.com"]]];
}
As the UIWebView loads the web content, its UIScrollView should change its contentSize property. You can use that to determine whether you're at the bottom or at the top already or not.
回答5:
You could use KVO to detect any change in the contentOffset property of your UIWebView instance.
Warning : Be careful because this property is changing very often when scrolling, and the events in the example below will pop really frequently. Don't implement or call high cost function at each contentOffset change !
Here is a code example for doing it in a UIView subclass containing a UIWebView :
@IBOutlet weak var webView: UIWebView!
override func awakeFromNib() {
super.awakeFromNib()
webView.delegate = self
webView.scrollView.addObserver(self, forKeyPath: "contentOffset", options: [.New, .Old], context: nil)
}
deinit {
webView.scrollView.removeObserver(self, forKeyPath: "contentOffset", context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
guard let kp = keyPath else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
return
}
if kp == "contentOffset" {
self.scrollViewDidScroll(webView.scrollView)
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentSize.height - scrollView.contentOffset.y - scrollView.frame.size.height < 100 {
print("this is the end")
} else if scrollView.contentOffset.y < 100 {
print("this is the beginning")
}
}
As documented by Apple in UIWebview documentation, you should avoid placing your UIWebview instance in a UIScrollView to detect the end/beginning of scrolling.
回答6:
If you are using Wkwebview:
I am bit late, I implemented delegate of wkwebview to check scrollview reaches on top or bottom.I used to read javascript code through evaluateJavaScript function. Before use set scrollview delegate of your webview and implement scrollViewDidEndDragging delegate function of UIScrollViewDelegate
extension BaseWebViewController: UIScrollViewDelegate {
func scrollViewDidEndDragging(_ scrollView: UIScrollView,
willDecelerate decelerate: Bool) {
webView.evaluateJavaScript("document.readyState", completionHandler: { (complete, error) in
if complete != nil {
self.webView.evaluateJavaScript("document.body.scrollHeight", completionHandler: { (height, error) in
let bodyScrollHeight = height as! CGFloat
var bodyoffsetheight: CGFloat = 0
var htmloffsetheight: CGFloat = 0
var htmlclientheight: CGFloat = 0
var htmlscrollheight: CGFloat = 0
var wininnerheight: CGFloat = 0
var winpageoffset: CGFloat = 0
var winheight: CGFloat = 0
//body.offsetHeight
self.webView.evaluateJavaScript("document.body.offsetHeight", completionHandler: { (offsetHeight, error) in
bodyoffsetheight = offsetHeight as! CGFloat
self.webView.evaluateJavaScript("document.documentElement.offsetHeight", completionHandler: { (offsetHeight, error) in
htmloffsetheight = offsetHeight as! CGFloat
self.webView.evaluateJavaScript("document.documentElement.clientHeight", completionHandler: { (clientHeight, error) in
htmlclientheight = clientHeight as! CGFloat
self.webView.evaluateJavaScript("document.documentElement.scrollHeight", completionHandler: { (scrollHeight, error) in
htmlscrollheight = scrollHeight as! CGFloat
self.webView.evaluateJavaScript("window.innerHeight", completionHandler: { (winHeight, error) in
if error != nil {
wininnerheight = -1
} else {
wininnerheight = winHeight as! CGFloat
}
self.webView.evaluateJavaScript("window.pageYOffset", completionHandler: { (winpageOffset, error) in
winpageoffset = winpageOffset as! CGFloat
let docHeight = max(bodyScrollHeight, bodyoffsetheight, htmlclientheight, htmlscrollheight,htmloffsetheight)
winheight = wininnerheight >= 0 ? wininnerheight : htmloffsetheight
let winBottom = winheight + winpageoffset
if (winBottom >= docHeight) {
print("end scrolling")
} else if winpageoffset == 0 {
print("top of webview")
}
})
})
})
})
})
})
})
}
})
}
}
来源:https://stackoverflow.com/questions/9535303/ios-detect-uiwebview-reaching-the-top-or-bottom