I've got an app that uses a UIWebView. Currently I create the web view using a storyboard but I want to create it programatically.
This needs to work across all devices and iOS 5 - 7.
Currently (using the storyboard) in iOS 6 it looks like this:
But in iOS 7 you don't get that white bar at the top:
How can I create the UIWebView programatically so that it fills available window space (i.e. doesn't go over tab bar or status bar) across all devices?
Thanks
//EDIT
Here's my storyboard for the UIWebView
//Edit 2
As per a suggestion I am doing this but it overlaps the status bar and tab bar. Is there any way to take them into account?
float width = [UIScreen mainScreen].bounds.size.width;
float height = [UIScreen mainScreen].bounds.size.height;
try to set your webview's frame programmatically like this
float width = [UIScreen mainScreen].bounds.size.width;
NSLog(#"width: %f", width);
float height = [UIScreen mainScreen].bounds.size.height;
NSLog(#"height: %f", height);
so your webview's frame should be
objWeb.frame = CGRectMake(0,0,width,height);
Okay, self.view will be resized at somewhere between viewDidLoad and viewWillAppear.
So, if you wanted to adjust the size, you should do it in viewWillApear.
But, my suggestion is use AutoResizeMask, or |[webView]| for auto layout.
AutoReszie
add your webView to self.view as subView, set the frame to self.view.boudse, and then
webView.autoResizeMask = UIViewAutoResizeMaskFliexbleHeight|UIViewAutoResizeMaskFliexbleWidth;
let me know if you need autoLayout version.
This is what worked for me based on others answers
-(void)createWebView
{
float width = self.view.bounds.size.width;
float height = self.view.bounds.size.height;
UIWebView *wv = [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, width, height)];
wv.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
wv.scalesPageToFit = YES;
wv.delegate = self;
[self.view addSubview:wv];
}
Related
I am using storyboards. I am unable to resize webview according to the screen size in my storyboard.
I want header to be of same size for both resolution but change the height of webview according to screen resolution.
I can't use Autolayout because I want to deploy my app for ios5 and above.
Please help.
you can set Your Webview frame according to UIScreen like Bellow where you alloc your `webview
CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
webFrame.origin.y -= 20.0; // statusbar 20 px cut from y of frame
webView = [[UIWebView alloc] initWithFrame:webFrame];
webView.scalesPageToFit = YES;
webView.autoresizesSubviews = YES;
webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
[webView setBackgroundColor:[UIColor clearColor]];
In your .m file under viewDidLoad add this code.
webview.frame = CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height);
Add a referencing outlet of your web view to webView and then that should set the webView height to your view height.
Explanation: The view will get longer when you deploy to a 4 inch simulator causing the webView to change to the view's size.
I am trying to get a webpage to fit to the iPhone screen using Xcode, but at the bottom of the screen I put a textbox to allow a user to enter in a username. This means that the webview box is a little bit smaller than using the full screen. I know how to make webpage fit to the full screen, but how do you fit it in a frame smaller than the full iPhone screen?
Start with a UIView in IB that is the full size of the screen and then put your web view and text fields inside it. You should then be able to resize the web view.
Init with frame:
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(x, y, width, height)];
Try this:
CGFloat x = 0;
CGFloat y = 0;
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height - 30;
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(x, y, width, height)];
[self.view addSubview:webView]; // Add the webview to the main view
This will make the height of the webView 30 points less than the main view you are adding it to.
Using a UIScrollView with a view containing som textviews and button. In viewDidLoad setting:
_myscrolview.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
I looks fine in poratraite but in landscape I am unable to scroll to the top for typing in textViews?
Tried setting in "didRotateFromInterfaceOrientation"
_myscrolview.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
With or without "didRotateFromInterfaceOrientation"... it only scrolls a bit, but unable to get to the top?
Thanks
Regards
Christian
Your _myscrolview.frame is changed due to the device rotation.
_myscrolview.frame = self.view.bounds;
And every subview inside _myscrolview probably needs to be re-oriented as well, Their width and height may need to be set to the landscape width.
After sub views inside _myscrolview is resized, you can then calculate the contentSize by:
CGRect contentRect = CGRectZero;
for (UIView *oneView in _myscrolview.subviews) {
contentRect = CGRectUnion(contentRect, oneView.frame);
}
_myscrolview.contentSize = contentRect.size;
I'm writing an app that uses UITabBar for parts of the navigation. I'm also using UIScrollView for presenting more information than what the screen can typically handle. Because of this, I'm needing to set the scroll view to take into account the height of the UITabBar so that all of the information is displayed.
Is there a way to calculate the height of the UITabBar?
If the view controller has an ancestor that is a tab bar controller, you can retrieve the height from that tab bar.
CGFloat tabBarHeight = self.tabBarController.tabBar.frame.size.height;
It is 320 x 49.
If you want to test, open Interface Builder, add a UITabBar, go into the ruler, you will see it
UITabBar is inherited from UIVIew so you can use the frame.size.height to get the height
In Swift:
let height = self.tabBarController?.tabBar.frame.height ?? 49.0
Relying on the actual height of the tab-bar, and using the magic number as a fallback.
Swift 3+
let tabBarHeight = tabBarController?.tabBar.frame.size.height
print(tabBarHeight ?? "not defined")
It should print 49.0 (Type CGFloat)
I was looking to do something similar with centering a label in the VISIBLE portion of a ViewController's view. This ViewController belonged to a UITabBarController.
Here's the code I used to center my label:
UILabel *roomLabel = [[UILabel alloc] init];
CGRect frame = [[self view] bounds];
float tabBarHeight = [[[super tabBarController] tabBar] frame].size.height;
frame.size.height -= tabBarHeight;
[roomLabel setFrame:frame];
[[self view] addSubview:roomLabel];
[roomLabel release];
Notice that I used [[self view] bounds] not [[self view] frame] because the latter includes the 20 pixel top bar as the Y offset (which throws off the vertical centering).
Hope this helps someone!
By the way: I'm using iOS 4.3 and XCode 4 and the "hard-code" value for the TabBar's height is still 49 for me!
I know this isn't ideal, but I really didn't want to have a magic number constant anywhere. What I did was create a throwaway UITabBarController, and get the height from there.
I did this also because [UITabBar initWithFrame:] works as desired, but doing a [bar setFrame:] doesn't. I needed the frame to be correct at creation.
UITabBarController *dtbc = [[[UITabBarController alloc] init] autorelease];
CGRect tabRect = [[[self navigationController] view] frame];
tabRect.origin.y = tabRect.size.height - [[dtbc tabBar] frame].size.height;
tabRect.size.height = [[dtbc tabBar] frame].size.height;
tabBar_ = [[UITabBar alloc] initWithFrame:tabRect];
What I like about this is that it will correctly place the tab bar at the bottom of the parent regardless of the parents size.
This should work in most cases on any instance of UIViewController:
bottomLayoutGuide.length
In swift 4 and 5. self.tabBarController?.getHeight()
extension UITabBarController{
func getHeight()->CGFloat{
return self.tabBar.frame.size.height
}
func getWidth()->CGFloat{
return self.tabBar.frame.size.width
}
}
Others can also try to get the height using the intrinsicContentSize property of the tab bar.
let tabBarHeight = self.tabBarController.tabBar.intrinsicContentSize.height
This is how I got it to work in swift 4.1
let tabBarHeight = CGFloat((self.tabBarController?.tabBar.frame.size.height)!)
Swift 5
if let tabBarController = tabBarController {
let tabBarSafeAreaHeight = tabBarController.tabBar.frame.size.height -
tabBarController.tabBar.safeAreaInsets.bottom
}
This calculates the height of the UITabBar taking into account the safeAreaInsets (UIEdgeInsets)
At the time of writing this equals 49 on iPhone portrait
let screenHeight = UIApplication.shared.statusBarFrame.height +
self.navigationController!.navigationBar.frame.height + (tabBarController?.tabBar.frame.size.height)!
This works perfectly, based it of a few ppls answer here
SWIFT 5 UPDATE :
AS this thread is old, I am posting here the update from another thread: https://stackoverflow.com/a/25550871/14559220. To sum things up,
in portrait and regular landscape, the height is still 49 points. In
compact landscape, the height is now 32 points.
On iPhone X, the height is 83 points in portrait and 53 points in
landscape.
UIScrollView in paging mode assumes the pages are located right next to each other, with no gap. However if you open a photo in the Photos app and swipe through photos, you can see that it has some gap between pages. I want these gaps too.
I'm looking for existing solutions if any, or for some more bizarre ideas about implementing the page gaps besides the one I have explained below. Or maybe there's some obvious easy way I am missing?
To be clear: I want the gap to only be visible while scrolling, so I cannot simply inset the page content.
My plan is to try moving the page content from inside scrollViewDidScroll callback, so that (assuming you're scrolling to the right) initially the target page is slightly offset to the right of its page boundaries, and by the time you arrive at the target page it's back at its proper location, and the source page is slightly offset to the left of its boundaries. (Or maybe instead of moving things continuously, I'll be better off shifting the offsets, say, exactly halfway between pages.)
I'm the author of the ScrollingMadness article+example that I've been referring some people to here. I've implemented progammatic zooming, and got in-photo zooming+scrolling working together with inter-photo paging. So I know how to play with UIScrollView, and am looking for the advanced stuff.
Please don't point me at TTScrollView. I've already pointed many people to it myself, but I consider it's feel too far from the native UIScrollView behaviour, and do not want to use it in my projects.
Note that this answer is quite old. The basic concept still works but
you should not be hard coding view sizes in iOS7 and 8. Even if you ignore
that advice, you should not use 480 or 330.
Have you tried making the frame of the UIScrollView slightly larger than the screen (assuming that you want to display your images fullscreen and then arranging your subviews on the same slightly-larger-than-the-screen boundaries.
#define kViewFrameWidth 330; // i.e. more than 320
CGRect scrollFrame;
scrollFrame.origin.x = 0;
scrollFrame.origin.y = 0;
scrollFrame.size.width = kViewFrameWidth;
scrollFrame.size.height = 480;
UIScrollView* myScrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
myScrollView.bounces = YES;
myScrollView.pagingEnabled = YES;
myScrollView.backgroundColor = [UIColor redColor];
UIImage* leftImage = [UIImage imageNamed:#"ScrollTestImageL.png"];
UIImageView* leftView = [[UIImageView alloc] initWithImage:leftImage];
leftView.backgroundColor = [UIColor whiteColor];
leftView.frame = CGRectMake(0,0,320,480);
UIImage* rightImage = [UIImage imageNamed:#"ScrollTestImageR.png"];
UIImageView* rightView = [[UIImageView alloc] initWithImage:rightImage];
rightView.backgroundColor = [UIColor blackColor];
rightView.frame = CGRectMake(kViewFrameWidth * 2,0,320,480);
UIImage* centerImage = [UIImage imageNamed:#"ScrollTestImageC.png"];
UIImageView* centerView = [[UIImageView alloc] initWithImage:centerImage];
centerView.backgroundColor = [UIColor grayColor];
centerView.frame = CGRectMake(kViewFrameWidth,0,320,480);
[myScrollView addSubview:leftView];
[myScrollView addSubview:rightView];
[myScrollView addSubview:centerView];
[myScrollView setContentSize:CGSizeMake(kViewFrameWidth * 3, 480)];
[myScrollView setContentOffset:CGPointMake(kViewFrameWidth, 0)];
[leftView release];
[rightView release];
[centerView release];
Apologies if this doesn't compile, I tested it in a landscape app and hand edited it back to portrait. I'm sure you get the idea though. It relies on the superview clipping which for a full screen view will always be the case.
So I don't have enough "rep" to post a comment on the answer above. That answer is correct, but there is a BIG issue to be aware of:
If you're using a UIScrollView in a viewController that's part of a UINavigationController, the navigation controller WILL resize the frame of your scrollView.
That is, you have an app that uses a UINavigationController to switch between different views. You push a viewController that has a scrollView and you create this scrollView in the viewController's -init method. You assign it a frame of (0, 0, 340, 480).
Now, go to your viewController's -viewDidAppear method, get the frame of the scrollView you created. You'll find that the width has been reduced to 320 pixels. As such, paging won't work correctly. You'll expect the scrollView to move 340 pixels but it will, instead, move 320.
UINavigationController is a bit notorious for messing with subviews. It moves them and resizes them to accommodate the navigation bar. In short, it's not a team player -- especially in this case. Other places on the web suggest that you not use UINavigationController if you need precise control over your views' size and locations. They suggest that, instead, you create your own navigationController class based on UINavigationBar.
Well that's a ton of work. Fortunately, there's an easier solution: set the frame of the scrollView in your viewController's -viewDidAppear method. At this point, UINavigationController is done messing with the frame, so you can reset it to what it should be and the scrollView will behave properly.
This is relevant for OS 3.0. I have not tested 3.1 or 2.2.1. I've also filed a bug report with Apple suggesting that they modify UINavigationController with a BOOL such as "-shouldAutoarrangeSubviews" so that we can make that class keep its grubby hands off subviews.
Until that comes along, the fix above will give you gaps in a paginated UIScrollView within a UINavigationController.
Apple has released the 2010 WWDC session videos to all members of the iphone developer program. One of the topics discussed is how they created the photos app!!! They build a very similar app step by step and have made all the code available for free.
It does not use private api either. Here is a link to the sample code download. You will probably need to login to gain access.
http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645
And, here is a link to the iTunes WWDC page:
http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj
The way to do this is like you said, a combination of a few things.
If you want a gap of 20px between your images, you need to:
First, expand your scroll view's total width by 20px and move it left by 10px.
Second, when you lay out the xLoc of your images, add 20px for each image so they're spaced 20px apart.
Third, set the initial xLoc of your images to 10px instead of 0px.
Fourth, make sure you set the content size of your scroll view to add 20px for each image. So if you have kNumImages images and each is kScrollObjWidth, then you go like this:
[scrollView setContentSize:CGSizeMake((kNumImages * (kScrollObjWidth+20)), kScrollObjHeight)];
It should work after that!
This is just a hunch, so apologies if completely wrong, but is it possible that the contentSize is just set to slightly wider than the screen width.
The correct information is then rendered within the view to the screen width and UIScrollView takes care of the rest ?
Maybe you want to try UIScrollView's contentInset property?
myScrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10.0);
I just thought I'd add here for posterity the solution I ended up going with. For a long time I've been using Bryan's solution of adjusting the frame in -viewDidAppear, and this has worked brilliantly. However since iOS introduced multitasking I've been running into a problem where the scroll view frame gets changed when the app resumes from the background. In this case, -viewDidAppear was not being called and I couldn't find a delegate method that would be called at the right time to reverse the change. So I decided to make my scroll view a subview of my View Controller's view, and this seemed to fix the problem. This also has the advantage of not needing to use -viewDidAppear to change the frame - you can do it right after you create the scroll view. My question here has the details, but I'll post them here as well:
CGRect frame = CGRectMake(0, 0, 320, 460);
scrollView = [[UIScrollView alloc] initWithFrame:frame];
// I do some things with frame here
CGRect f = scrollView.frame;
f.size.width += PADDING; // PADDING is defined as 20 elsewhere
scrollView.frame = f;
[self.view addSubview:scrollView];
To avoid messing with UIScrollView's frame, you could subclass UIScrollView and override layoutSubviews to apply an offset to each page.
The idea is based on the following observations:
When zoomScale !=1, the offset is zero when it is at the left / right edge
When zoomScale ==1, the offset is zero when it is at the visible rect centre
Then the following code is derived:
- (void) layoutSubviews
{
[super layoutSubviews];
// Find a reference point to calculate the offset:
CGRect bounds = self.bounds;
CGFloat pageGap = 8.f;
CGSize pageSize = bounds.size;
CGFloat pageWidth = pageSize.width;
CGFloat halfPageWidth = pageWidth / 2.f;
CGFloat scale = self.zoomScale;
CGRect visibleRect = CGRectMake(bounds.origin.x / scale, bounds.origin.y / scale, bounds.size.width / scale, bounds.size.height / scale);
CGFloat totalWidth = [self contentSize].width / scale;
CGFloat scrollWidth = totalWidth - visibleRect.size.width;
CGFloat scrollX = CGRectGetMidX(visibleRect) - visibleRect.size.width / 2.f;
CGFloat scrollPercentage = scrollX / scrollWidth;
CGFloat referencePoint = (totalWidth - pageWidth) * scrollPercentage + halfPageWidth;
// (use your own way to get all visible pages, each page is assumed to be inside a common container)
NSArray * visiblePages = [self visiblePages];
// Layout each visible page:
for (UIView * view in visiblePages)
{
NSInteger pageIndex = [self pageIndexForView:view]; // (use your own way to get the page index)
// make a gap between pages
CGFloat actualPageCenter = pageWidth * pageIndex + halfPageWidth;
CGFloat distanceFromRefPoint = actualPageCenter - referencePoint;
CGFloat numOfPageFromRefPoint = distanceFromRefPoint / pageWidth;
CGFloat offset = numOfPageFromRefPoint * pageGap;
CGFloat pageLeft = actualPageCenter - halfPageWidth + offset;
view.frame = CGRectMake(pageLeft, 0.f, pageSize.width, pageSize.height);
}
}