mashers
mashers

Reputation: 1099

UITableviewController messes with contentInset of editable UIWebView

I've got a UITableViewController with several sections, dynamically created. One of the rows in each section contains a UIWebView as its accessoryView. The UIWebView is prepopulated with HTML to allow the text within it to be edited. When the UIWebView is tapped, the tableView scrolls so that the row containing the UIWebView is above the keyboard; the keyboard appears and the UIWebView becomes the first responder. This works fine if the UIWebView is at the top of the tableView so the table does not need to be scrolled. If however a lower down row is tapped so that the table has to be scrolled, then the contentInset of the UIWebView's scrollView gets changed. Specifically, the bottom value of the contentInset is added to, making the UIWebView long and thin instead of rectangular.

I have uploaded screenshots to show this:

Before selecting UIWebView: Before selecting UIWebView

After selecting UIWebView: After selecting UIWebView

After the UIWebView resigns first responder status and the keyboard is dismissed, it returns to normal.

I know it is the contentInset property which is being adjusted because I have added an observer of the webView's scrollView using the keyValue "contentInset" and I can observe it changing, and even then log it and confirm that it has changed.

Upvotes: 1

Views: 501

Answers (1)

mashers
mashers

Reputation: 1099

It turns out the problem wasn't the contentInset, it was the contentOffset of the UIWebView's built in UIScrollView. Here's how I fixed it:

@interface SomeViewController ()
@property BOOL monitorContentOffsetChanges;
@end

@implementation SomeViewController

- (void)webViewCreationMethod {
    UIWebView *myWebView = [[UIWebView alloc] init];
    //Setup webView

    //Observe any changes to the scrollView's contentOffset property
    [[webView scrollView] addObserver:self forKeyPath:@"contentOffset" options:0 context:NULL];
    [self setMonitorContentOffsetChanges:YES];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
//The webView's contentOffset was changed
  if (object == [[self webView] scrollView] && [keyPath isEqualToString:@"contentOffset"] && [self monitorContentOffsetChanges]) {
         //Stop responding to changes in the contentOffset to prevent recursive calling of this method
        [self setMonitorContentOffsetChanges:NO];
        //Force the contentOffset back to zero
        [[[self webView] scrollView] setContentOffset:CGPointZero animated:NO];
        //Start monitoring changes to the contentOffset again in case of future changes
        [self setMonitorContentOffsetChanges:YES];
    }
}

@end

This solution is required because UIWebView's scrollView property is read only, so you can't subclass UIScrollView and override setContentOffset to take no action and force this into the UIWebView.

The only thing I'm not sure of now is whether this solution is App Store safe.

Upvotes: 1

Related Questions