In StoryBoard, I have setup two view controllers:
PageViewRootViewController - this is just blank (in storyboard) as everything is setup programmatically.
VillagerTextViewController - Storyboard sets the layout
Additionally, I have a ModelController (NSObject) that acts as the data source.
Everything is working fine. I can transition between pages, no warnings or errors and no crashes.
However, when transitioning, the bottom of the page is cropped off. I've been trying to fix it to no avail.
I can't post images yet so http://s10.postimg.org/qbjlat649/Screenshot_2013_04_20_22_12_04.png
The UIPageViewController is created in the viewDidLoad method of PageViewRootViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
if (!pageViewController) {
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:UIPageViewControllerSpineLocationMin] forKey:UIPageViewControllerOptionSpineLocationKey];
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:options];
self.pageViewController.delegate = self;
VillagerTextViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self.modelController;
[self.pageViewController.view setClipsToBounds:NO];
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
}
}
In storyboard, I have the view for PageViewRootViewController set to popover width 768 and height 200. I also display this as a popover.
The VillagerTextViewController and ModelController do not have anything (in code or storyboard) explicitly related to size, frame, or bounds.
Any help is appreciated!
EDIT:
Fixed with:
[self.pageViewController.view setFrame:CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y, self.view.bounds.size.width, self.view.bounds.size.height+600)];
I don't see you doing anything in your code about giving the UIPageViewController's view a frame. It's important not to omit that! I don't guarantee that this is the source of your problem, but it might be.
self.pageViewController.view.frame = ???????
The reason this doesn't appear to be a problem is that you're covering it up, as it were, by setting clipsToBounds to NO; thus you are making yourself unaware of where the frame is. Much better, I think, not to set clipsToBounds to NO, but to get the frame right.
Related
hey people,
I have some data and want to show this in a new view inside a navigation-stack.
I created some new viewcontroller class with XIB file. Then I edited the XIB file and placed the following hierachy:
1 files owner
2 first responder
3 scrollview
3.1 view
3.1.1 label1
3.1.2 label2
3.1.3 label3
3.1.4 image4
I arranged the labels and the image. the content of the labels may differ and they should size dynamically. I also did the IBOutlets in the viewcontroller class and connected everything correctly. the files owner's view delegate is set to view..
then I load the viewcontroller and I do in the "viewDidLoad" - method the following:
- (void)viewDidLoad {
[super viewDidLoad];
self.currentPageURL.text = [self.offerItem objectForKey: #"page-url"];
self.currentPrice.text = [self.offerItem objectForKey: #"price"];
self.currentRank.text = [self.offerItem objectForKey: #"rank"];
self.currentName.text = [self.offerItem objectForKey: #"name"];
self.currentProducerName.text = [self.offerItem objectForKey: #"producer-name"];
self.currentDescription.text = [self.offerItem objectForKey: #"description"];
self.imageViewForImage.image = [helperClass resizeImage:[self.offerItem objectForKey: #"picture"] forSize:CGSizeMake(280.0, 280.0) ];
[theScrollview setScrollEnabled:YES];
[theScrollview setContentSize:CGSizeMake(320, 1200)];
[theScrollview flashScrollIndicators];
[theScrollview addSubview:theView];
}
when I start the app in my simulator, everything is shown, but if I try to scroll, nothing happens..
what do I do wrong?
Autolayout set some constraints after the view loads, so, pick your code that sets the content size in viewDidLoad and put in viewDidAppear, and your code won't be rewritten.
This worked for me.
-(void)viewDidAppear:(BOOL)animated{
[self.scrollView setContentSize:CGSizeMake(320, 1000)];
}
and sorry for my poor english.
Ensure that "Use Autolayout" is unchecked in the IB Document attributes. I had the exact same issue, setting the correct contentSize and all, but with this feature enabled, scrolling was always disabled.
UPDATE To use Autolayout, explicitly set the width and height of the scrollView's content in the viewDidAppear method, like this:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// set the scrollview to the specified size
CGRect screenRect = [[UIScreen mainScreen] bounds];
[scrollView setContentSize:CGSizeMake(screenRect.size.width, 1100)];
[scrollView setBounds:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)];
[scrollView setScrollIndicatorInsets:UIEdgeInsetsFromString(#"{0,0,0,-1.0}")];
}
Immediately change the frame of theScrollView to 320x480 and you should see scrolling.
I'm trying to display transparent UINavigationBar on top of Scrollview.
This is actual result of code that I have written...
where as I'm expecting view to be displayed like below image, which happens after I slightly scroll the image.
Code :
- (void) loadView {
CGRect pagingScrollViewFrame = [self frameForPagingScrollView];
pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame];
pagingScrollView.pagingEnabled = YES;
pagingScrollView.backgroundColor = [UIColor blackColor];
pagingScrollView.showsVerticalScrollIndicator = NO;
pagingScrollView.showsHorizontalScrollIndicator = NO;
pagingScrollView.contentSize = CGSizeMake(pagingScrollViewFrame.size.width * [self imageCount],
pagingScrollViewFrame.size.height);
pagingScrollView.delegate = self;
self.wantsFullScreenLayout = YES;
pagingScrollView.scrollsToTop = YES;
self.view = pagingScrollView;
}
question is how do I make view to load as I expected without user interacting to it?
any suggestion or help is appreciated..
EDIT: I'm creating view totally from CODE
It seems like you're trying to do this in code not in the IB. If so, you have to put your code in the viewDidLoad of the Application Delegate (e.g. MyProgramAppDeligate class or whatever). If you want it in some certain views, put it in the viewDidLoad of the UINavigationController class/subclass.
Does this satisfy your requirement?
self.navigationController.navigationBar.translucent = YES;
self.navigationController.navigationBar.tintColor = [UIColor blackColor];
And to make your statusbar translucent.
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
[self setWantsFullScreenLayout:YES];
I have this inside my willWillAppear and I reset it in my viewWillDisappear.
You have to set
self.navigationController.navigationBar.translucent = YES;
As soon as you do this, the 0,0 coordinate is behind your navigation bar not below it and your view shifts behind the bar.
It may be a conflict between IB and your code. I would add the line of code suggested by Ortwin in the viewDidLoad method and then double check you've set the navBar to translucent in IB.
The code you have posted has nothing to do with the opacity of the navigation bar. Show where you are setting the configuration of the components of the view. There you could just set the alpha of the navigation bar. Alternatively if you are using nibs, just set the alpha in IB.
Since you say that it works fine after the user (you) slightly scrolls the image, the problem might be that the UINavigationBar's drawRect: method does not get called after the UIScrollView is loaded.
Suggestion: Can you explicitly call setNeedsDisplay on the navigation bar after the view is loaded?
Have you tried setting the frame of the scroll view with an Y origin of 0 after setting the nav bar to transparent?
EDIT: I mean, you don't say what's the frame used in your code.
In viewDidLoad, try moving the origin up 32 pixels and grow the height by 32 pixels as well:
pagingScrollView.frame = CGRectMake(pagingScrollView.frame.origin.x, pagingScrollView.frame.origin.y-32, pagingScrollView.frame.size.width, pagingScrollView.frame.size.height+32);
In viewWillAppear scroll the content to the correct location.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIScrollView *scrollView = (UIScrollView *)self.view;
[scrollView setContentSize:CGSizeMake(320,568)];
[scrollView scrollRectToVisible:CGRectMake(0, 548, 320, 20) animated:NO];
}
It looks like a problem which could have simple solution, but I haven't found anything what could lead the way to it. I'm using UIWebView inside of UIScrollView and tapping on statusBar (to scroll content to top) is not working.
I've made simple test application to see if it's really UIWebViews fault. And it really is.
// scrolls to top on status bar tap
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
[self.view addSubview:sv];
// doesn't scroll
UIScrollView *sv = [[UIScrollView alloc] init];
sv.frame = CGRectMake(0, 0, 320, 480);
sv.contentSize = CGSizeMake(320, 1200);
UIWebView *wv = [[UIWebView alloc] init];
wv.frame = CGRectMake(0, 0, 320, 100);
[sv addSubview:wv];
[self.view addSubview:sv];
So, I think maybe there's something I could disable to make UIWebView not to mess with scrollToTop? Or some kind of workaround also would be nice.
Any ideas?
I ran into this last night until I finally found the answer buried in a comment to a comment. The idea of that original post is that when you add the UIWebView to your UIScrollingView, you use the following:
- (void) ensureScrollsToTop: (UIView*) ensureView {
((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
}
This seemed fishy to me since the first sub-view of a UIWebView claims to be a UIScroller which is not a subclass of UIScrollView. However, since UIScroller supports the scrollsToTop property, the cast just gives us a way past the compiler warning:
Class List:
Class = UIScroller
Class = UIView
Class = UIResponder
Class = NSObject
Supported Methods:
...
Method _scrollToTop
Method setScrollsToTop:
Method scrollsToTop
...
Supported Properties:
Property scrollsToTop
EDIT:
Just another quick note about where this actually needs to occur: in the webViewDidFinishLoad callback. Calling it on UIWebView construction isn't good enough because at that time the UIWebView hasn't created it's child views yet, which are the ones causing the problem:
- (void)webViewDidFinishLoad:(UIWebView *) wv {
[self ensureScrollsToTop: wv];
}
EDIT #2:
now, in iOS 5, as noted in iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back use UIWebView's new #property scrollView, making ensureScrollsToTop implementation unnecessary for projects that aren't using deployment targets lower than iOS 5.0 .
In iPhone OS, if there is more than one UIScrollView (or its subclass, for example UITableView, UIWebView) in the current viewController, the system doesn't know which UIScrollView should be scrolled to the top.
Quick fix: for all the UIScrollViews that you don't want to support scrollsToTop, just set the scrollsToTop as NO, then every thing works perfect.
self.scrollView1.scrollsToTop = NO;
self.scrollView2.scrollsToTop = NO;
self.scrollView1.scrollsToTop = YES; // by default scrollsToTop is set as YES, this line is not necessary
Webviews by default will have YES for scrollsToTop-value. I've written a simple class for this specific issue. In my app we're having multiple webviews and scrollviews. This makes it all much easier.
https://gist.github.com/hfossli/6776203
It basically sets scrollsToTop to NO on all other scrollViews than the one you are specifying.
I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr said:
If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored
So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.
And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.bounds;
scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
[self.view addSubview:scrollView];
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = scrollView.bounds;
[scrollView addSubview:webView];
I have a UIView and a UIController view. My is standard a 320x460 view. In applicationDidFinishLaunching I do:
[window addSubview:[controller view]];
The weird thing is that the UIView goes under the status bar (like there's missing outlet). However, if I rotate iPhone to the side and then back, it shows up ok.
Is this an expected behavior (I bet I can fix it by setting offset) or am I doing smth wrong?
I ran into this issue when displaying a UIViewController via presentModalViewController.
You can get around it by manually resizing the controller's view after the view has appeared:
- (void) viewDidAppear: (BOOL) animated {
//manually adjust the frame of the main view to prevent it from appearing under the status bar.
UIApplication *app = [UIApplication sharedApplication];
if(!app.statusBarHidden) {
[self.view setFrame:CGRectMake(0.0,app.statusBarFrame.size.height, self.view.bounds.size.width, self.view.bounds.size.height - app.statusBarFrame.size.height)];
}
}
I think your problem is that when you add a view to a window, you need to be aware of the state of the status bar and compensate for it:
if showing the status bar :
[controller view].frame = CGRectMake(0, **20**, 320, 460);
else
[controller view].frame = CGRectMake(0, 0, 320, **480**);
this is why IB shows you a dummy status bar.
I add this issue today. It turned out that I had "Wants Full Screen" checked in the ViewController's Attribute inspector.
Turning off "Wants Full Screen" resolved the problem.
Finally, I got to this solution. Works well for both iPhone & iPad:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Allocate view controller and load nib file
if (isIPhone) {
self.mainViewController = [[[tfdMainViewController_iPhone alloc] initWithNibName:#"tfdMainViewController_iPhone" bundle:nil] autorelease];
} else {
self.mainViewController = [[[tfdMainViewController_iPad alloc] initWithNibName:#"tfdMainViewController_iPad" bundle:nil] autorelease];
}
// Offset correction (iPhone bug?)
CGRect r = self.mainViewController.view.frame;
r = CGRectOffset(r, 0, [UIApplication sharedApplication].statusBarFrame.size.height);
[self.mainViewController.view setFrame:r];
[window addSubview: self.mainViewController.view];
[self.window makeKeyAndVisible];
return YES;
}
P.S. For some reason view has correct height:
480 (screen height in iPhone Portrait mode) - 20 (status bar) = 460,
but failed to set vertical offset. It is pretty strange behavior, looks like bug.
Fixes to the window didn't work for me as I had a modal view. A UIModalPresentationCurrentContext modal view. OK, here's what worked for me. I've been searching the web up and down before getting this to work.
I'm unable to move the view.frame from the parent. However in the viewWillAppear I'm able to move it down:
- (void)viewWillAppear:(BOOL)animated
{
// Move down to compensate for statusbar
CGRect frame = parentView.navCon.view.frame;
frame.origin.y = [UIApplication sharedApplication].statusBarFrame.size.height;
parentView.navCon.view.frame = frame;
}
If you are using Interface Builder's "Simulated User Interface Elements", then you also need to make sure that you have set the flag for "Resize View From NIB" in your MainWindow nib.
This appears to be a bug in iOS 5. One fix would be to use wantsFullScreenLayout in whatever view controller needs to present modally and manually layout the view always below the status bar.
http://www.cocoanetics.com/2012/06/radar-view-frame-inconsistency-using-presentviewcontroller-wantsfullscreenlayout-yn/
http://openradar.appspot.com/radar?id=1758406
Are you manually setting the application bar hidden property AFTER adding the subview? I don't imagine this is the case, but if it's set to none when you first load the view it will layout as if there isn't one, and if you then set the status bar to not hidden it will pop up on top of your view.
A possible solution is to use [[controller view] setNeedsLayout]; after adding the subview, or possibly [window layoutSubviews];. I've never had a lot of success using those to fix layout problems, but since it works after a rotation it's worth a shot.
Even me too got the same issue. When we are using some coding for device orientation we have wrote some coding in app delegate or in our view controller. There we need to change the condition to use the orientation return YES or NO. That solved our issue.
I prefer to use UINavigationController to wrap the UIViewController you, after that, set the NavigationBarHidden to the UINavigationController. It's perfect solution cause UINavigationController do handle the height of status bar in iOS 7.
Here is my code and my screen capture.
UINavigationController *wrapNavController = [[UINavigationController alloc] initWithRootViewController:yourViewController] ;
[wrapNavController setNavigationBarHidden:YES] ;
The Xcode 6, iOS7/8 solution is in to uncheck the "Under Top Bars" checkmark in the "Extend Edges" section of the View Controller section of the Attributes Inspector.
For Xamarin.iOS it would be:
if (UIApplication.SharedApplication.StatusBarHidden == false)
{
var statusBarHeight = UIApplication.SharedApplication.StatusBarFrame.Height;
View.Frame = new CoreGraphics.CGRect(0, statusBarHeight, View.Frame.Width, View.Frame.Height - statusBarHeight);
}
I'm trying to do something that shouldn't be that complicated, but I can't figure it out.
I have a UIViewController displaying a UITableView. I want to present a context menu when the user press on a row. I want this to be a semi-transparent view with labels and buttons.
I could use an AlertView, but I want full control on the format of the labels and buttons and will like to use Interface Builder.
So I created my small view 250x290, set the alpha to .75 and create a view controller with the outlets to handle the different user events.
Now I want to present it.
If I use presentModalViewController two (undesired) things happen
1) the view covers all of the screen (but the status bar).
2) It is semi-transparent, but what I see "behind" it its not the parent view but the applications root view.
Ive tried adding it as a subview, but nothing happens, so Im not doing something right:
RestaurantContextVC* modalViewController = [[[RestaurantContextVC alloc] initWithNibName:#"RestaurantContextView" bundle:nil] autorelease];
[self.view addSubview:modalViewController.view];
Is it possible to do what I want?
Thanks in advance.
Gonso
I'm coding similar thing. My approach include.....
Not using dismissModalViewControllerAnimated and presentModalViewController:animated.
Design a customized full sized view in IB. In its viewDidLoad message body, set the background color to clearColor, so that space on the view not covered by controllers are transparent.
I put a UIImageView under the controllers of the floating view. The UIImageView contains a photoshoped image, which has rounded corners and the background is set to transparent. This image view serves as the container.
I uses CoreAnimation to present/dismiss the floating view in the modal view style: (the FloatingViewController.m)
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor clearColor]];
[UIView beginAnimations:nil context:nil];
[self.view setFrame:CGRectMake(0, 480, 320, 480)];
[UIView setAnimationDuration:0.75f];
[self.view setFrame:CGRectMake(0, 0, 320, 480)];
[UIView commitAnimations];
}
wangii
Thats pretty much the solution I found.
I load the view with loadNibNamed and then just add it on top with addSubView, like this:
//Show a view on top of current view with a wait indicator. This prevents all user interactions.
-(void) showWaitView{
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:#"WaitView" owner:self options:nil];
#ifdef __IPHONE_2_1
waitView = [ nibViews objectAtIndex: 0];
#else
waitView = [ nibViews objectAtIndex: 1];
#endif
CGFloat x = self.view.center.x - (waitView.frame.size.width / 2);
CGFloat y = self.view.center.y - (waitView.frame.size.height / 2);
[waitView setFrame:CGRectMake(x,y,waitView.bounds.size.width,waitView.bounds.size.height)];
[self.view addSubview:waitView];
}
Could you elaborate on points 3 and 4?
What I did to give the view the round rect aspect is put it inside a round rect button.
This code will actually allow you to have a small floating view, but if the view is smaller that its parent, the user could interact with the visible part of the parent.
In the end I create my view with the same size, but kept the code just in case.
Gonso
I would strongly consider using a navigation controller to slide in your subview instead of overlaying it. This is the expected model and any small benefit you may think you'll get by doing it your own way will be greatly offset by the principle of (least) surprise.
If you really really have to do it this way, I believe the trick is to add the first table view as a subview of a transparent "holding" view that the view controller maintains. Then add your new sub view as another subview of that.
Again, if you really want to do this, instead of adding a transparent "holding" view, since this pop-up is essentially modal, I would make it a subview directly of the window.
You might want to put in a transparent black shield behind it to prevent touches on the background and focus input on the popup.
But seriously, consider either popping a controller on the stack or using that alert view. Unless you've hired a $$ designer, it's probably not going to look appropriate on the iPhone.
What I did was create a UIViewController on top of my UINavigation controller in my app delegate and made it a property of a singleton object for convenience:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//--- create root navigation controller
self.window.rootViewController = self.navigationController;
//--- create view controller for popups:
popupViewController = [[BaseViewController alloc] init];
popupViewController.view.backgroundColor = [UIColor clearColor];
popupViewController.view.hidden = true; //for rendering optimisation
[self.window addSubview:popupViewController.view];
[AppState sharedInstance].popupViewController = self.popupViewController;
//--- make all visible:
[self.window makeKeyAndVisible];
return YES;
}
At any point in my app, I can then call e.g.
MyViewController * myVC = [[UIViewController alloc] init];
//... set up viewcontroller and its view...
// add the view of the created view controller to the popup view:
[AppState sharedInstance].popupViewController.view.hidden = false;
[[AppState sharedInstance].popupViewController.view addSubview:myVC.view];
The BaseViewController used on the top just inherits from UIViewController and sets up a full-screen view:
//----- in BaseViewController implementation
- (void)loadView {
//------- create root view:
CGRect frame = [[AppState sharedInstance] getScreenFrame];
rootView = [[VCView alloc] initWithFrame:frame];
rootView.backgroundColor = [UIColor whiteColor];
self.view = rootView;
}