I have an app that uses a UIViewController to display articles in a UIWebView, some of which have images. I have it set up so that when an image is clicked it calls
- (void)displayImage:(NSInteger)i {
ImageViewController * imageVC = [[ImageViewController alloc] initWithImageId:i];
[self.navigationController pushViewController:imageVC animated:YES];
[imageVC release];
}
This loads another UIViewController.
All of my views responds perfectly fine to rotations. The ImageViewController maintains the proportions of the image and my ArticleViewController fills the screen with text. However, whenever I rotate the screen to landscape mode while viewing my ImageViewController and press the back button. The previous UIViewController autoresizes incorrectly, increasing the font size of the text rather than putting more words on a line.
EDIT:
This is an article view controller:
This is the ImageViewController that comes up when you click the image:
Now if we change the orientation here...
And hit the back button, the article content has been inappropriately resized to fit the window.
This can be corrected by turning the iPhone twice. This is what the article should look like in landscape.
The problem has something to do with the UIWebView not autoresizing appropriately when it isn't currently visible. What can I do to fix this?
You need to do this in Interface Builder.
Click on your UIWebView and press Apple-3 to pull up the "Size Inspector".
Under "Autosizing", make sure the two arrows inside the box are selected. This will make sure the view size is always maximized to its container.
You can change it on server side by adding different css styles depending on device orientation:
for example:
/* Landscape */
#media screen and (min-width: 321px)
{
body{
width: 320px;
}
}
/* Landscape */
#media screen and (min-width: 321px)
{
body{
width: 480px;
}
}
or you could change viewport from client side:
In case your page has got viewport meta tag:
<meta name="viewport" id="view" content="width=320px, minimum-scale=1.0, maximum-scale=1.0">
then in your code you can change this viewport every time orientation changes:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == UIDeviceOrientationLandscapeLeft)
[uiwebview stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"document.getElementById(\"view\").setAttribute('content', 'width=480');"]];
}
....
and change it again when orientation is portrait
For future reference. You can do this programmatically with this.
[webView setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)];
Related
I need to use the area around (and behind) the notch while application is in full screen mode and display my app "fully full-screen" and use that area to display elements, as if there is no notch there.
I understand that is where the menu bar appears, but I am okay with either disabling menu bar in full screen OR making it act like older macs when it would appear over the application after we move cursor higher in that area.
I've tried (to no avail):
Playing with Safe Area
Hiding Title Bar from inspection menu in Xcode
Removing the Menu completely
Adding UISupportsTrueScreenSizeOnMac = true to plist
P.S. I've already done hours of searching on Google and SO, as well as Apple's documentation but haven't found any indication of how to achieve this.
I do not think you can use fullscreen mode to do this, because there is no public API for overriding your window's fullscreen frame to include the unsafe areas around the sensor housing (the ‘notch’).
You should be able to manually achieve this by looking at the NSScreen representing the built-in display. Set your window's frame to the screen's frame (not the screen's visibleFrame). The screen's auxiliaryTopLeftArea and auxiliaryTopRightArea describe the areas to the left and right of the notch. From those, you can deduce the area obscured by the notch.
This is how I managed to achieve this (simplified just for reference):
Hide application's "Title Bar"
Set your window's frame to full width and height on load (again, simplified)
override func windowDidLoad() {
window!.setFrame(CGRect(x: 0, y: 0, width: NSScreen.main!.frame.width, height: NSScreen.main!.frame.height), display: true)
}
Set LSUIPresentationMode in your plist
<key>LSUIPresentationMode</key>
<integer>3</integer> // Change this to 4 if you want to allow menu bar and dock to appear when user moves cursor top/bottom edges (they are initially hidden)
Note:
Without using LSUIPresentationMode or even hiding title bar, the following code would launch the app in fullscreen and for ~1 second it would fill the area around notch as well, but then it would revert back to the area below notch.
Just thought I should also mention this, so there might be ways to achieve this while using native fullscreen
window!.toggleFullScreen(self)
window!.setFrame(CGRect(x: 0, y: 0, width: 1728, height: 1117), display: true)
This is not a solution. But maybe helpful.
I tried swizzling -[_NSFullScreenContentController reservesSpaceForMenuBarInFullScreen] with retuning value NO.
#import <Cocoa/Cocoa.h>
#import <objc/message.h>
void swizzle(Class class, SEL cmd, IMP custom, IMP _Nullable * _Nullable original) {
Method originalMethod = class_getInstanceMethod(class, cmd);
IMP originalImp = method_getImplementation(originalMethod);
*original = originalImp;
class_replaceMethod(class, cmd, custom, nil);
}
BOOL (*original_NSFullScreenContentController_reservesSpaceForMenuBarInFullScreen)(id, SEL);
BOOL custom_NSFullScreenContentController_reservesSpaceForMenuBarInFullScreen(id self, SEL cmd) {
return NO;
}
#implementation NSWindow (Swizzle)
+ (void)load {
swizzle(NSClassFromString(#"_NSFullScreenContentController"), NSSelectorFromString(#"reservesSpaceForMenuBarInFullScreen"), (IMP)&custom_NSFullScreenContentController_reservesSpaceForMenuBarInFullScreen, (IMP *)&original_NSFullScreenContentController_reservesSpaceForMenuBarInFullScreen);
}
#end
Here's the results.
Before
After
With swizzling -[_NSFullScreenContentController reservesSpaceForMenuBarInFullScreen] frame of window will be fit to screen. But I cannot find how to remove a black bar.
I have a child view controller that needs to be always shown in landscape mode regardless of which mode the parent view is in. I'm adding it onto the parent's view stack with
[[self navigationController] pushViewController:controller animated:NO];
I am trying to force the view to rotate and be displayed as if the device is held in Landscape orientation even though it's still held in Portrait orientation.
The only problem is that no matter what size and coordinates I set the view frame to, I see a 20 pixel gap on the right side of the screen where the StatusBar used to be during Portrait Mode.
What can I adjust to ensure that this gap is gone?
Here's how I'm doing the transformation (as recommended by this SO article)
- (void)changeOrientationToLandscape
{
UIApplication *myApp = [UIApplication sharedApplication];
CGAffineTransform landscapeTransform = CGAffineTransformMakeRotation( degreesToRadian(90) );
landscapeTransform = CGAffineTransformTranslate(landscapeTransform, +90.0, +90.0 );
[self.view setTransform:landscapeTransform];
// Change the status bar orientation so it's shown as if we're in landscape
myApp.statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
// Manually force view frame - this doesn't seem to fix the 20 pixel gap
self.view.frame = CGRectMake(0, 0, 480, 320);
}
The only time I see the view taking up the entire screen and without the 20 pixel gap is if I hide the status bar all together, something I cannot do for this app.
Here's how the screen looks (it's held in Portrait orientation with the home button on the bottom). Notice how the status bar ends doesn't have the same purple background - I was hoping I could shift the view over so the white gap is no longer present.
I also printed out the view and navigationController's view frames and they both report
x and y location at 0,0. The navigation view frame's reported dimension is 320x480 while view's frame is 480x320.
What about disabling the status bar when child is pushed and enabling when it's "popped"?
You can hide status bar for your child view controller only.
If you're pushing your child view controller via self.navigationController, simply override shouldAutorotateToInterfaceOrientation in child view controller and put this ...
return UIInterfaceOrientationIsLandscape( interfaceOrientation );
... to body of this method to make it landscape only.
Here is an interesting problem. On the iPhone, I have a view set up that has a toolbar on the bottom of the screen. I am currently trying to make this a universal app so that it runs on iPad as well. I would like the toolbar to be at the top of the iPad screen, so in the viewDidLoad method of the specific viewController I have the following code.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
//move the toolbar to the top of the page and move the webview down by the height of the toolbar
CGRect toolBarFrame = self.aToolBar.frame;
CGRect webFrame = self.aWebView.frame;
webFrame.origin.y = toolBarFrame.size.height;
[self.aWebView setFrame:webFrame];
toolBarFrame.origin.y = 0;
[self.aToolBar setFrame:toolBarFrame];
[Utils errorString:[NSString stringWithFormat:#"origen: x=%f y=%f", self.aToolBar.frame.origin.x, self.aToolBar.frame.origin.y]];
[Utils errorString:[NSString stringWithFormat:#"origen: x=%f y=%f", self.aWebView.frame.origin.x, self.aWebView.frame.origin.y]];
}
The problem I am having is that the webView moves down fine, but the toolbar only moves up to about what seems to be the height of a iPhone screen. The call to errorString tells me that the webView's origin is at 0,44 (where it should be) and that the toolbar's origin is at 0,0, but it is actually somewhere in the middle of the screen!
Anybody have a clue what is going on here?
I'd say this is because the frame is being set to the top of an iPhone frame (so 320px from the bottom), and then afterwards the view is being resized to fit the iPad screen. However UIToolbar by default is set to stick to the bottom of the window (fixed bottom margin, and flexible top margin) so it's staying 320px from the bottom.
To fix this try:
[self.aToolbar setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];
before setting the toolbar's frame (if it doesn't work before setting the frame, try putting it after)
My aim was to get the application functioning in both landscape and portrait mode, and all I could figure out to do it was this code below. The app was working fine in portrait, but when switched to landscape, the text wouldn't expand (to the right) to fill up the additional space. I made sure my springs/struts where set, and that the parents had "allowResizing" selected in IB.
Here's what I've done instead:
- (void) willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:
(NSTimeInterval)duration {
UIInterfaceOrientation toInterfaceOrientation = self.interfaceOrientation;
if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
self.myView.frame = CGRectMake(0.0, 0.0, 320.0, 480.0);
}
else {
self.myView.frame = CGRectMake(0.0, 0.0, 480.0, 256.0);
}
}
Note that it looks just fine in portrait mode (toolbar appears):
Portrait http://mr-sk.com/img/land.png
But the toolbar is gone in landscape mode:
Landscape http://mr-sk.com/img/por.png
Any ideas?
If you use Interface Builder - you get this same result if you don't specify constraints in the object inspector to pin the toolbar to both edges and the bottom (click on the little red lines to specify constraints).
You can also do the same in code - you need to lookup how to do this (but its easier in IB)
There are a few reasons why it could be messing up... maybe your UIToolbar has the wrong parent. Maybe a layoutSubviews is being run and moving it somewhere strange. Or something else.
I recommend you implement a didRotateFromInterfaceOrientation: on your view controller and read the frame of the UIToolbar after the rotation to see where it has gone. This will be the best way to discover the exact problem.
I'm using a UIWebView with text in it. When the iPhone is rotated to landscape, text doesn't fill the now wider UIWebView width. I'm using P (paragraph) tags, which should not affect content filling landscape's width. The line breaks that are visible in portrait remain the same in landscape. In Interface Builder, I haven't changed anything. In the IB Inspector, Web View Size has all solid bars under AutoSizing, which means it should fill to the landscape width right?
Here is a tweak though not a good thing to do, and something should be handled by apple itself
As you've noticed that things workfine when WebView is initialized in portrait and then you turn it to landscape. So.. what you can do is always initialize your webview with portrait bounds, add a selector which calls back after 2~3 seconds and sets the frame of webView according to your requirement.
Now as the contents started loading when the frame size of your webview were according to portrait (say 320,460) so converting your webview to landscape will automatically adjust your web view if you have this line in your code
[webViewObjet_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
Below is the snippet of code
- (id) initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
webViewObjet_ = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
.....
}
}
- (void) webViewDidStartLoad:(UIWebView *)webView
{
.....
[self performSelector:#selector(chuss) withObject:nil afterDelay:3];
// call the function chuss after 3 second
}
- (void) chuss
{
webViewObjet_.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
[webViewObjet setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
}
Now tried around with the same problem, finally did it after looking detailed at "WhichWayIsUp"-Sample from Apple.
To keep it short:
1) Disable in the View Inspector the |--| and <-->
2) `switch the View Mode from the Webview to "Aspect Fill"
Et voila ;)
Keep the vibes,
Maniac
I have the same problem. Reloading does not work, the only thing that seems to help a bit is to add the following line to the code:
self.view.autoresizingMask =
UIViewAutoresizingFlexibleWidth;
(I place it in the willAnimateFirstHalfOfRotationToInterfaceOrientation function)
It still keeps a small white margin at the right, but its far better than the default. Note: you should apply this on the self.view and not on the UIWebView instance, that won't work.
Waiting for a solution from Apple..
Pieter
This will sound strange, but it works:
If the UIWebView is inside a UINavigationController, it will all work just fine. I had the same problem, so I just wrapped it up in a UINavigationController and the problem was gone.
For some reason, UINavigationController makes rotations work like a charm.