I have made a very simple web browser app using a web view. Now I need to get the app so that when the iPhone is rotated, the text of the page is rotated as well.
How do I do this?
I am very confused by the auto-resize dialog, so it is possible I have done something wrong there.
Any help would be appreciated!
I think you sholud rotate UIWebView widget, not its contents. Contents should rotate as well. To support rotating add following code to your view controller:
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Rotated widget might look different then expected. Adjust struts and springs in Interface Builder.
I think you need to give us some sample code in order to determine what goes wrong. It is as Jacek says, the only think you should need to do is to support auto rotation on the UIWebView itself. The content should be rotated automatically.
I think you are confused by device orientation and view frame.
In most cases UIViews do change with respect to the orientation change. But to clarify - it is not because of the orientation change, but the layout change.
Only UIViewControllers need to consider device orientation - UIViews do NOT. When the device orientation changes, the UIViewController captures the event from its instance methods:
– willRotateToInterfaceOrientation:duration:
– willAnimateRotationToInterfaceOrientation:duration:
– didRotateFromInterfaceOrientation:
The UIViewController then re-layout the views - leading to reframing of the UIViews. In many cases, iOS can helps you in simplifying the relayout process by setting the UIViewAutoresizeMask. For example:
myWebview.autoresizeMask = UIVIewAutoresizeMaskFlexibleHeight | UIVIewAutoresizeMaskFlexibleHeight;
implies that when webview's superview changed its bounds, the webview will change accordingly.
As a summary, UIView only takes care of its frame / bounds etc.
Related
I need to know if there is a way to tell a iOS7 device to set a views orientation without the device being rotated. Some way in code to trigger the device to calling the code that tells it which way to display the view.
If the device is in landscape and remains held in landscape orientation while a certain change happens I want to force a change to show the view in portrait orientation, at which point the user would need to turn the device to look at it properly. I'll explain why below
Looking at my app might make my description clearer - it is free to download
I have a number of view controllers (embedded in navigationControllers) and only one of them needs to be rotated into landscape and then only under certain conditions.
Solutions here on StackOverflow seem to be to make a category on UINavigationController giving it shouldAutorotate and supportedInterfaceOrientations methods and then use those methods in the individual viewControllers to block or allow rotations.
This has worked for me .... however
On the one view controller I wish to rotate , I don't want it to rotate all the time.
This view controller is the diveSiteDetailsController, (if you have downloaded the app you need to select dive sites on the first page then click the '+' to see it). It has a UISegmentedController and 4 subviews (3 tableviews and 1 other UIView). The current version on the App Store works fine now i've solved this - but looking at it may help you understand my issue better).
On diveSiteDetailViewController the UISegmentedController is used to switch between the 4 subviews.
All the subviews are used to enter data about the same dive site but as there is a lot of potential data, I have broken it into logical chucks each of which is a subview - location, data (depths,currents, visibility), type of environment and notes.
The .hidden property of each subview is used to make them appear and disappear.
I only want the second subview to rotate (the data view - it has some sliders on it that are easier to work with if in landscape).
restricting this rotation is easy - iI achieved it like this
- (NSUInteger)supportedInterfaceOrientations{
if (self.dsDataRangeSlidingTV.hidden) {
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAllButUpsideDown;
}
Now the view will only rotate to landscape when the data table view is displayed.
However, once in landscape, if I chose a different subview with the UISegmentedController then they are, obviously, shown in landscape also as the iOS device hasn't done a rotation. This is the situation I am trying to avoid.
Rotating the iOS device will return those views to portrait as expected but i need to trigger the device to to reevaluate its display when I use the UISegmentedController to switch from the data subview to another subview and its that triggering that I don't know how to do.
any suggestions greatly received.
Heres a workaround that is working for me
I've added the following few lines to the end of my method that responds to the UISegmentedControl being tapped.
UIViewController *aDummyController = [[UIViewController alloc]init];
[self presentViewController:aDummyController animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
adding a new viewController and popping it off triggers the rotation . This is a kludgey way of achieving what I wanted.
I found the solution in this post
Is there a documented way to set the iPhone orientation?
all credit to Josh who although not the accepted answer is the one that 99 people currently have up voted.
I still have a bug in that, if I were holding the device in landscape (although the display is portrait view) whilst on the screen that segues into the diveSiteDetailsController then the initial view the diveSiteDetailsController display will be in landscape.
To get around this I created a Bool property called notThisTime on the diveSiteDetailsController and set it to true in the prepareFor Segue on the viewController that called it.
i then did changed supportedInterfaceOrientation to
- (NSUInteger)supportedInterfaceOrientations
{// DLog(#"Running %# '%#'", self.class, NSStringFromSelector(_cmd));
if (self.notThisTime){
return UIInterfaceOrientationMaskPortrait;
}
if (!self.dsDataRangeSlidingTV.hidden) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
then at the end of the ViewDidLoad method I added
self.notThisTime = NO;
I would still love to hear from anyone with a suggestion how better to handle this. pushing and popping a dummy view to get the iPhone to do an orientation check seems like a work around for something that should just be available as a standard method call.
One final Note - the iOS simulator does not like this - you need to check on the device - it sometimes tries to draw the iPhone container in landscape while the screen is drawn vertically - however it does work fine on the iPhone
I have a UICollectionView, and it works great, but I have a doubt.
In my view I have a UICollectionViewCell and inside that I have a UIImage.
The cell is linked to a blank view controller, and inside that I have a UIScrollView (for managing the zoom) and a UIImage (the full-size image).
I wondered if there was some delegate or something that could handle the image opening process automatically (with zoom, etc.).
Now I'm handling the zoom effect with UIScrollViewDelegate delegate and method viewForZoomingInScrollView:... but the result is very poor, definitely not fluid!
There's no built in view for doing what you want, no. You're doing the right thing with a UIImageView inside UIScrollView. If it's not very fluid, then it's likely because your image is huge. The way to get around that is to load different images for different zoom levels. So as you zoom in, listen to the UIScrollViewDelegate method called scrollViewDidZoom: and change the image to better resolution as you zoom in. Or, take a look at CATiledLayer.
Note that this has nothing to do with your UICollectionView.
I've been driving myself mad over this one. It might be one of those things where I need to take a step back and figure out the simplest way to implement this. Can't find anything on this either. I google-fu'd the heck out of this one.
In the Pocket App when you pull down a menu reveals itself just like the searchBar does. In this instance the faux bar when you pull it past its halfway point if you release it shows springs into place. If it is release before the halfway point the bar will snap back and hide. As shown here
In my case I've been trying to replicate this with no luck. In my case I have a UITextView inside of a UIViewController view. I think I have it all wrong.
I can get it to work with a UIScrollView hidden by initiating with it offscreen and then when I press a button the UIScrollView reveals itself. The problem is that this method covers everything so I'll have to resize and relayout a bunch of views. Is this in a UITableView possibly? I want it to be a pull action though and just want to put some TextStrings/Labels in this bar.
Thank you in advance.
Feels like you need a UIScrollView (or UITableView) and to put the menu you want to reveal at the top (in the table view header, for example) and then get the delegate callbacks for scrolling.
UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
You might also need to watch for some of the dragging delegate callbacks
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
You can initially hide the menu by setting the content offset to the height of the menu, then catch the delegate callbacks for scrolling and, if the scrolling has reached beyond half the size of the menu set the content offset with animation.
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
If I understand your goal correctly you don't need the scroll view.
What I would do is have an simple UIView containing all the stuff you need and place it outside of the visible area. This will be your pull-down view. Then add an UIPanGestureRecognizer to the view in your UIViewController and use it to track the movement of your finger and update the frame of the pull-down view accordingly. Then in this update method you simply check if the position has passed some threshold and if so you let the pull-down view snap to its final position (using animations of course).
If you are unfamiliar with the UIPanGestureRecognizer there is a really good tutorial here:
http://www.raywenderlich.com/6567/uigesturerecognizer-tutorial-in-ios-5-pinches-pans-and-more
I'm having difficulty figuring out how to deal with different device orientations for one screen of my iPad app. Here's my situation:
~ All of this screen is rotating perfectly using springs and struts except for one label. The problem with this label is that I want it to move in an unorthodox manner (diagonally), thus springs and struts (or resizing masks will not work).
~ The way that I'm considering doing this is as such:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)newInterfaceOrientation duration:(NSTimeInterval)duration
{
if(UIInterfaceOrientationIsLandscape(newInterfaceOrientation))
{
self.myScreenLabel.frame = CGRectMake(600,0,400,100);
}
else {
self.myScreenLabel.frame = CGRectMake(...//something); }
}
I would also put a check in viewDidLoad with similar logic. If in portrait mode, put label at... else put label at....
I think that this will work; however, I'm kinda wondering if there's a better designed way to do this. The method above, has hard-coded numbers everywhere; thus, is there a better way to do this? Also, this method does not take advantage of the fact that I have my label positioned perfectly in the storyboard for portrait mode and it's just landscape that I need to change.
Any suggestions on better design?
First question, I've implemented behavior on orientation change with your approach with no bad results, if you are okay that the method is triggered right before rotation happens. Alternatively, you can use NSNotifications to add a trigger on orientation change:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:)name:UIDeviceOrientationDidChangeNotification object:nil];
Then add a method like:
- (void) didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft) {
//your code here
}
}
Regarding your second question, positioning frames like that is scary, but I think you realize that. Instead, position the element related to something else, just like a strut (which would say, always position the widget relative to a distance between it is strutted against). So use the window's frame, the view's frame, or some other UIView subclass in the view to position the object against, rather than absolute numbers.
A couple of thoughts:
If iOS 5+, you might want to use viewWillLayoutSubviews, probably even more important given the comments in the iOS 6 release notes re modal views and the screen reorientation methods. This also has the advantage that your code is in one spot. Since I still support pre 5 (though I won't for much longer), I actually have dynamic checking of iOS version and invoke my viewWillLayoutSubviews from the other methods if pre 5.0, otherwise I let viewWillLayoutSubviews just do the heavy lifting.
If your landscape orientation is radically different, you probably want to pursue Creating an Alternate Landscape Interface. I've never done this, but it seems like it's up your alley. There are also postings on SO about using different NIBs for different orientations. Not sure this makes sense in a storyboard environment, though.
For these controls that we occasionally have to move around or resize based upon screen dimensions, I think most of us do it with viewWillLayoutSubviews. That's the entire purpose of that method (though I generally use it for labels whose height changes based upon the data contents and the screen width). I had never stopped to think that there might be another way. If you only have one control that you're moving around as you change your orientation, maybe you could create two additional, hidden controls, one for where you want your visible control in portrait, the other hidden control for where you want it in landscape (and in IB, you can toggle your view orientation to facilitate the layout of controls). Then in your viewWillLayoutSubviews set your frame of your actual visible control to be the frame of one of those two hidden controls (depending upon orientation, of course). That gets you out of the business of hardcoding frame coordinates in your code, and take advantage of the benefits of IB. This whole suggestion might be too cute by half, but it's an alternative approach if you don't want to go through the effort of my second point.
I am working on an app, which actually works like MSPaint (something to draw lines, etc...).
I got a white UIView, basically where the user draws. On top of this UIView I set up a UIImage, which is gray, with a 0,4 alpha. I want this UIImage to be used as a blotting paper. The idea is to disable touch when the user put the palm of his hand on this area, so it's more comfortable to draw (multitouch is disabled, and with this "blotting paper" you won't draw something accidentally with your palm...)
Even if I bring the UIImage to the front, on top of the view, and even if I disable user interactions on this UIImage, it is still possible to draw on the UIView. , behind the UIImage (kind of strange!)
I do not understand what's happening, because, it seems that the image is transparent, and that the UIView "behind" is still active, even if she's overlaid by the UIImage?!
Any help/indication/idea would be much appreciated! Thank you :-)
Have you set the "userInteractionEnabled" property of the UIImage to "NO" ?
You may actually want to do the opposite. When you disable user interaction or touches, the view basically becomes invisible to touches and they are passed on to the next view.
In your case you do want userInteractionEnabled because you want the view to catch those touches.
You have to disable the user interaction on the UIImageView not the UIImage and it should work.
Edit:
Or you could be sneaky and just add an empty view over it. Use the same frame size so it overlaps perfectly and thats it. You'll be able to see everything you need and it's not a subview of it so there will eb no interaction and touches will get registered but won't have any effect. :P
No better ideas unless you post some of your code...
OK, so I managed to do what I wanted to! YAY!
I got 3 different classes :
StrokesViewController (UIViewController)-the view controller
StrokesView (UIView) - the view where the user draws the strokes.
BlottingPaper (UIView) - the blotting paper.
I got a XIB file "linked" to all three.
I created this new class, called "BlottingPaper", typed UIView. the .h and .m file are actually empty (I do import #import < Foundation/Foundation.h >)
User interaction is enable on BlottingPaper.
I do not use the exclusive touch on this class.
On the XIB file, I just put a view on top of StrokesView. I link it to BlottingPaper (modify the alpha as I want, blablabla...)
And that's it! When I put the palm of my hand on it, it doesn't draw anything on the area where my hand is, but I still can draw with my finger on the rest of the StrokesView!
In addition to Dancreek's response, you should be setting buvard.userInteractionEnabled = YES; so that it captures interaction.
You should also set buvard.exclusiveTouch = YES; so that buvard is the only view which will receive touch events.
When you remove buvard you should set buvard.exclusiveTouch = NO; so that other views will regain their ability to receive touches.