UIScrollView won't scroll on iOS 7 after popping the view controller - uiwebview

My app's home screen has a UIScrollView that contains a UIWebView and a UIButton. The scroll view's content size is set accordingly after loading the web view.
The user can return to the home screen at anytime by simply pressing an icon in a tab bar. This action clears all of the view controllers out of the navigation controller and adds the home screen's controller to the navigation controller. The home screen is redisplayed correctly and the scroll view works just fine.
The problem I'm encountering is when the user presses a "back" button to return the to home screen, which pops the current view controller. The page redisplays fine, but you can't scroll anymore.
I've stepped through the code numerous times and the scroll view's content size is being set to the same value no matter which way you return to the home screen.
It's important to note that the scrollview only stops working under iOS 7. It works as expected under iOS 6.
The web page is loaded in viewWillAppear:
-(void)viewWillAppear:(BOOL)animated
{
NSString *fullURL = #"http://somewhere.com/app-homepage/index.html";
NSURL *url = [NSURL URLWithString:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:requestObj];
[self.scrollView setContentOffset:CGPointZero];
}
The scroll view is dynamically resized in webViewDidFinishLoad:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
webView.scrollView.scrollEnabled = NO;
CGRect frame = webView.frame;
frame.size.height = 1;
webView.frame = frame;
CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
self.webViewHeightConstraint.constant = frame.size.height;
self.featuredCelebritiesButtonTopVerticalSpaceConstraint.constant = frame.size.height + 8;
CGSize svContentSize = self.scrollView.contentSize;
svContentSize.height = frame.size.height + 65;
self.scrollView.contentSize = svContentSize;
webView.frame = frame;
[self.activity stopAnimating];
}

Related

iOS 9 UINavigation bar content is not centred after rotation in iOS 9?

I noticed a bug in iOS 9, or may be I am not using something correctly.
In the following code in an empty project targeted for iPhone :
UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Show" style:UIBarButtonItemStylePlain target:self action:#selector(test:)];
self.navigationItem.rightBarButtonItem = anotherButton;
self.navBar.items = #[self.navigationItem];
I added a custom button to a navigation bar property. I noticed that after rotation from portrait to landscape, the button moves down and it is not centered correctly in the navigation bar.
Portrait Screen
Landscape Screen
This code works fine if I compile for iOS 8.4 for example, but not on iOS 9.
Has anyone encountered this?
Thanks!
I've seen something similar on the iPad. When I start the app in portrait, then rotate to landscape, the View Controller its navigationItem.titleView doesn't align correctly anymore. I simply reset it after rotation as follows in Swift:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animateAlongsideTransition(nil) { (coordinator) -> Void in
self.navigationItem.titleView = someView
}
}
Swift 3:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: nil) { (coordinator) -> Void in
self.navigationItem.titleView = self.someView
}
}
I have managed to fix the problem with custom navigation bar class with and overridden method:
-(void) layoutSubviews
{
[super layoutSubviews];
for (UIView *view in self.subviews)
{
if ([view isKindOfClass:[UIView class]] ||
[view isKindOfClass:[UIButton class]] ||
[view isKindOfClass:[UISearchBar class]] ||
[view isKindOfClass:[UILabel class]])
{
CGRect frame = view.frame;
frame.origin.y = (self.frame.size.height - frame.size.height) / 2.f;
view.frame = frame;
}
}
}
Other type of view classes can be added in the if statement. Its not the cleanest solution, but it will do for now.

How can I add a menu option to the NSTextAttachment popup menu is UITextView?

I want to add another menu option to the default image attachment menu options (Copy Image, Save to Camera Roll). Note that these options are shown when you long press on an image embedded in the UITextView if the textView is not in editing mode.
I have tried adding a custom menu to the uimenucontroller and using -(void)canPerformAction to enable or disable the option, however this seems to add the menu item to the uitextView's edit menu and has no affect on the attachments popup menu.
-(void)canPerformAction never seems to get called when long pressing on the image attachment.
Well according to Apple there is no public API for doing this, however as it turns out its relatively straight forward to replace the default menu with one that looks and behaves the same.
In the viewController that contains the UITextView add the following or similar and set it up as the textView's delegate.
- (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange {
// save in ivar so we can access once action sheet option is selected
_attachment = textAttachment;
[self attachmentActionSheet:(UITextView *)textView range:characterRange];
return NO;
}
- (void)attachmentActionSheet:(UITextView *)textView range:(NSRange)range {
// get the rect for the selected attachment (if its a big image with top not visible the action sheet
// will be positioned above the top limit of the UITextView
// Need to add code to adjust for this.
CGRect attachmentRect = [self frameOfTextRange:range inTextView:textView];
_attachmentMenuSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Copy Image", #"Save to Camera Roll", #"Open in Viewer", nil];
// Show the sheet
[_attachmentMenuSheet showFromRect:attachmentRect inView:textView animated:YES];
}
- (CGRect)frameOfTextRange:(NSRange)range inTextView:(UITextView *)textView {
CGRect rect = [textView.layoutManager boundingRectForGlyphRange:range inTextContainer:textView.textContainer];
// Now convert to textView coordinates
CGRect rectRange = [textView convertRect:rect fromView:textView.textInputView];
// Now convert to contentView coordinates
CGRect rectRangeSuper = [self.contentView convertRect:rectRange fromView:textView];
// Get the textView frame
CGRect rectView = textView.frame;
// Find the intersection of the two (in the same coordinate space)
CGRect rectIntersect = CGRectIntersection(rectRangeSuper, rectView);
// If no intersection then that's weird !!
if (CGRectIsNull(rectIntersect)) {
return rectRange;
}
// Now convert the intersection rect back to textView coordinates
CGRect rectRangeInt = [textView convertRect:rectIntersect fromView:self.contentView];
return rectRangeInt;
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (actionSheet == _attachmentMenuSheet) {
switch (buttonIndex) {
case 0:
[self copyImageToPasteBoard:[_attachment image]];
break;
case 1:
[self saveToCameraRoll:[_attachment image]];
break;
case 2:
[self browseImage:[_attachment image]];
break;
default:
break;
}
}
}
- (void)saveToCameraRoll:(UIImage*)image {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
- (void)copyImageToPasteBoard:(UIImage*)image {
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
NSData *data = UIImagePNGRepresentation(image);
[pasteboard setData:data forPasteboardType:#"public.png"];
}
-(void)browseImage:(UIImage*)image
{
OSImageViewController *_imageViewerController = [[OSImageViewController alloc] init];
UIImage *img = [[UIImage alloc] initWithData:UIImagePNGRepresentation(image)];
_imageViewerController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
_imageViewerController.modalPresentationStyle = UIModalPresentationFullScreen;
_imageViewerController.delegate = self;
[self presentViewController:_imageViewerController animated:YES completion:^(void){
[_imageViewerController setImage:img];
}];
}

Issue in showing my UIWebview in IOS 7 properly

In my app i have a UIWebview in which all the activity is taking place.
The app works perfect on ios6 but with iOS 7 my UIwebview content is colliding with the status bar.
Is there a way i can set the view for my UIWindow to show this properly.
if([[[UIDevice currentDevice] systemVersion] integerValue] >= 7) {
if (self.window.rootViewController.view.frame.origin.y <=0) {
screenBounds = CGRectMake(0, 20, self.window.bounds.size.width, self.window.bounds.size.height-20);
}
}
self.window.rootViewController = self.viewController;
Thanks,
Try:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
in the viewDidLoad method of your view controller.

displaying Wiki mobile page in UIWebView within UIPopoverController

I try to open wiki mobile version webpage by a UIWebView within a UIPopoverController. the problem is, not matter how I set my contentSizeForViewInPopover, or just UIWebView frame, or simply set UIWebView.scalesPageToFit = YES. the Wiki mobile version page content size seem to larger than my UIWebView. But if I use it on iPhone, there's no such problem. here's my code for popover controller:
//create a UIWebView UIViewController first
WikiViewController *addView = [[WikiViewController alloc] init];
addView.contentSizeForViewInPopover = CGSizeMake(320.0, 480.0f);
//then create my UIPopoverController
popover = [[UIPopoverController alloc] initWithContentViewController:addView];
popover.delegate = self;
[addView release];
//then get the popover rect
CGPoint pointforPop = [self.mapView convertCoordinate:selectAnnotationCord
toPointToView:self.mapView];
CGRect askRect = CGRectMake((int)pointforPop.x, (int)pointforPop.y+10, 1.0, 1.0);
[popover presentPopoverFromRect:askRect
inView:self.mapView
permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];
[self.mapView deselectAnnotation:annotation animated:YES];
and this is my code on creating UIWebView:
- (void)viewDidLoad
{
wikiWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 480.0f)];
wikiWebView.scalesPageToFit = YES;
//or No, doesn't matter, it all get larger than this
wikiWebView.delegate = self;
self.view = wikiWebView;
}
all code seem to be typical...
I wonder if anyone can shed me some light, thank you so much.
This is an enhanced version of auco answer, where if the viewport meta tag is not present it will be added:
- (void)webViewDidFinishLoad:(UIWebView*)webView
{
int webviewWidth = (NSUInteger)webView.frame.size.width;
if (!webView.loading) {
NSString *jsCmd = [NSString stringWithFormat:#"try {var viewport = document.querySelector('meta[name=viewport]');if (viewport != null) {viewport.setAttribute('content','width=%ipx, initial-scale=1.0, user-scalable=1');} else {var viewPortTag=document.createElement('meta');viewPortTag.id='viewport';viewPortTag.name = 'viewport';viewPortTag.content = 'width=%ipx, initial-scale=1.0, user-scalable=1';document.getElementsByTagName('head')[0].appendChild(viewPortTag);}} catch (e) {/*alert(e);*/}", webviewWidth, webviewWidth];
[webView stringByEvaluatingJavaScriptFromString:jsCmd];
}
}
Here is the Javascript pretty formatted code we are injecting in the WebView with a width of 320px
try {
var viewport = document.querySelector('meta[name=viewport]');
if (viewport != null) {
viewport.setAttribute('content',
'width=320px, initial-scale=1.0, user-scalable=1');
} else {
var viewPortTag = document.createElement('meta');
viewPortTag.id = 'viewport';
viewPortTag.name = 'viewport';
viewPortTag.content = 'width=320px,initial-scale=1.0, user-scalable=1';
document.getElementsByTagName('head')[0].appendChild(viewPortTag);
}
} catch (e) {
/*alert(e);*/
}
you can remove the try/catch if you want.
oh, i found in another QA that sometimes if html got a line "width=device-width", and you load a webview from popover controller, this popover controller will automatically send out device-width, not the view width you specified, and make your view ugly and funky. in that post it is a jQuery issue, and it solved with a jQuery way. In my problem, it is just a html issue in wiki mobile version. so I try another way, but similar.
I simple add a code in webViewdidload delegate method, first get URL html into a NSString, then use NSString instance method to search for "device-width" in loaded html, and replace it with my view width to make it a new NSString, then load this page with this new NSString. that's it.
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
if (!alreadyReload)
{
NSString *webHTML = [NSString stringWithContentsOfURL:webView.request.URL encoding:NSUTF8StringEncoding error:NULL];
NSRange range = [webHTML rangeOfString:#"device-width"];
if ((range.location!=NSNotFound)&&(range.length != 0))
{
webHTML = [webHTML stringByReplacingOccurrencesOfString:#"device-width" withString:#"whatever width you need" options:0 range:range];
[webView loadHTMLString:webHTML baseURL:wikiWebView.request.URL];
alreadyReload = YES;
}
}
}
something like this.
by the way, since I only use this on wiki mobile version, the html is simple and this kind of compare and replace is pretty easy. if you wanna use it in a more general case, you might use other way.
It would be much more efficient to manipulate the device-width via JavaScript rather than altering the html after it has fully loaded and then reloading the full page with modified html again.
This should work (and also consider if it's even necessary to change the viewport width):
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
if(aWebView.frame.size.width < aWebView.window.frame.size.width) {
// width=device-width results in a wrong viewport dimension for webpages displayed in a popover
NSString *jsCmd = #"var viewport = document.querySelector('meta[name=viewport]');";
jsCmd = [jsCmd stringByAppendingFormat:#"viewport.setAttribute('content', 'width=%i, initial-scale=1.0, user-scalable=1');", (NSUInteger)aWebView.frame.size.width];
[aWebView stringByEvaluatingJavaScriptFromString:jsCmd];
}
// stop network indicator
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

Custom navigation bar height and view

I want to have a naviagtion bar that is at least the double height.
In didFinishLaunchingWithOptions in my appdelegate.m file, I've added
CGRect frame = CGRectMake(0.0f, 0.0f, 320.0f, 100.f);
[self.navigationController.navigationBar setFrame:frame];
But when I run the app the top part of the table view is behind the bottom of the navigation bar.
How do I resize the table view so it`s not behind the navigation bar?
Thank's
// Sven
If you want to resize your navigation bar in all application viewConttrollers, you can override sizeThatFits:(CGRect) rect method in UINavigationBar category
#implementation UINavigationBar (bigSize)
- (CGSize)sizeThatFits:(CGSize)size {
CGSize newSize = CGSizeMake(320,100);
return newSize;
}
#end

Resources