I have to lock the scrollview in potrait orientation and not in landscape.
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
scrollview.scrollEnabled=YES;
NSLog(#"inside the landscape rotation");
}
else
{
scrollview.scrollEnabled=NO;
NSLog(#"inside the portrait rotation");
}
}
The above method is working fine, but I have to rotate the device for once - is there any way to lock the scrollview in potrait without change the orientation?
Thanks in advance.
You can put your your locking code in viewDidLayoutSubviews like so:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if(UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation))
{
scrollview.scrollEnabled = YES;
NSLog(#"inside the landscape roatation");
}
else
{
scrollview.scrollEnabled = NO;
NSLog(#"inside the portrait roatation");
}
}
Related
UIWebview is working perfectly whenever its launched first in potrait mode.
But after switching to Landscape mode, even though I specify
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[self layoutsubviews];
}
please advise how can I make the UIWebView to recalculate its intrinsic contentsize as of now its not rendered properly in landscape mode
Just have to use the animateAlongsideTransition:completion: method
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
// do whatever
} completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
}];
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
If I push from rootViewController to detailViewController in landscape mode. My ScrollView is not changing the 'y' position. My code:-
- (void)viewDidLoad
{
NSLog(#"DetailViewController viewDidload - Start");
[super viewDidLoad];
// Do any additional setup after loading the view.
[self delayedCheck];
NSLog(#"DetailViewController viewDidload - End");
}
-(void)delayedCheck {
NSLog(#"delayedCheck start");
UIInterfaceOrientation toStatusBarInterfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
if (toStatusBarInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toStatusBarInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"Landscape");
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgL.jpg"]];
[self.detailContentScrollView setFrame:CGRectMake(self.detailContentScrollView.frame.origin.x, 170.0, self.detailContentScrollView.frame.size.width, self.detailContentScrollView.frame.size.height)];
} else {
NSLog(#"Portrait");
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgP.jpg"]];
[self.detailContentScrollView setFrame:CGRectMake(self.detailContentScrollView.frame.origin.x, 185.0, self.detailContentScrollView.frame.size.width, self.detailContentScrollView.frame.size.height)];
}
NSLog(#"delayedCheck End");
}
UPDATE
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
NSLog(#"willAnimateRotationToInterfaceOrientation");
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"Landscape");
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgL.jpg"]];
[self.detailContentScrollView setFrame:CGRectMake(self.detailContentScrollView.frame.origin.x, 170.0, self.detailContentScrollView.frame.size.width, self.detailContentScrollView.frame.size.height)];
} else {
NSLog(#"Portrait");
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgP.jpg"]];
[self.detailContentScrollView setFrame:CGRectMake(self.detailContentScrollView.frame.origin.x, 185.0, self.detailContentScrollView.frame.size.width, self.detailContentScrollView.frame.size.height)];
}
}
I am trying to change the scrollview 'y' position in landscape mode. I navigate from rootViewController to detailViewController, In detailView - the position of scrollview is not changing.
Please help me out to change the position of 'y' origin of scrollView. Thanks in Advance....
- (void)viewWillLayoutSubviews
{
UIInterfaceOrientation toStatusBarInterfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;
if (toStatusBarInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toStatusBarInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgL.jpg"]];
}
else
{
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgP.jpg"]];
}
}
I placed the viewWillLayoutSubviews method and made changes as mentioned in code.
When updating my app to iOS6 standard the portrait / landscape is gone. Ir worked perfectly when I was building with Xcode 3. But now using latest Xcode and latest SDK the rotation is gone and it is always in portrait mode. No matter what I put in "Supported interface Orientations". And the code I used to get rotation before seems to have no effect at all.
I had these lines.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
switch (toInterfaceOrientation) {
case UIInterfaceOrientationPortrait:
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
return YES;
default:
return NO;
}
}
How do I change and what do I change to get it work again?
First of all, in AppDelegate, write this. THIS IS VERY IMP
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return (UIInterfaceOrientationMaskAll);
}
Then, For UIViewControllers, in which you need only PORTRAIT mode, write these functions
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskPortrait);
}
For UIViewControllers, which require LANDSCAPE too, change masking to All.
- (NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskAllButUpsideDown);
//OR return (UIInterfaceOrientationMaskAll);
}
Now, if you want to do some changes when Orientation changes, then use this function.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
}
EDIT :
A lot depends on with which controller is your UIViewController embedded in.
Eg, If its inside UINavigationController, then you might need to subclass that UINavigationController to override orientation methods like this.
subclassed UINavigationController (the top viewcontroller of the hierarchy will take control of the orientation.) did set it as self.window.rootViewController.
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
From iOS 6, it is given that UINavigationController won't ask its UIVIewControllers for orientation support. Hence we would need to subclass it.
How to support one or more landscape controllers in app that is portrait mainly in ios6:
1) in AppDelegate
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
UINavigationController* ns = (UINavigationController*)self.window.rootViewController;
if (ns) {
UIViewController* vc = [ns visibleViewController];
//by this UIViewController that needs landscape is identified
if ([vc respondsToSelector:#selector(needIos6Landscape)])
return [vc supportedInterfaceOrientations];
}
return UIInterfaceOrientationMaskPortrait; //return default value
}
2) in UIView controller(s) that needs landscape (or portrait+lanscape etc):
//flag method
-(void)needIos6Landscape {
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
3) in controllers, to which you can RETURN from controllers, that can be rotated in landscape - this is important, otherwise they remaind landscape on return from landscape-enabled VC.
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
4) (maybe not needed, but for sure..) - subclass navigation controller(s) you using, and add:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
UIViewController* vc = [self visibleViewController];
if (vc) {
if ([vc respondsToSelector:#selector(needIos6Landscape)]) {
return [vc supportedInterfaceOrientations];
}
}
return UIInterfaceOrientationMaskPortrait;
}
The important step is to ask for orientation only controllers from your app, because during transition between controllers, for some time there is some system controller as root, and will return incorrect value (this took me 2 hrs to find out, it was reason it was not working).
Don't know whether your issue was alike but with me, the status bar was oriented correctly (landscape) and the UIViewController was portrayed.
I changed following line in the application delegate application:didFinishLaunchingWithOptions:
//[window addSubview:navigationController.view];
self.window.rootViewController = navigationController;
Apple=> this costed me a day and a half to find out, and a lot of money!!!
Here is the event:
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)interfaceOrientation
{
[self setupScrollView];
return YES;
}
Any time the device is rotated, I setup my UIScrollView so that what's inside is always "right" side up.
if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait)
{
self.scrollView.transform = CGAffineTransformIdentity;
}
else if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortraitUpsideDown)
{
self.scrollView.transform = CGAffineTransformRotate(self.scrollView.transform, M_PI);
}
else if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationLandscapeLeft)
{
self.scrollView.transform = CGAffineTransformRotate(self.scrollView.transform, -M_PI/2);
}
else if ([[UIDevice currentDevice] orientation] == UIInterfaceOrientationLandscapeRight)
{
self.scrollView.transform = CGAffineTransformRotate(self.scrollView.transform, M_PI/2);
}
This works except when the device is rotated from landscape back to Portrait (right side up), breakpoints verify that shouldAutorotateToInterfaceOrientation is not being called. So when device is turned back to portrait the UIScrollView contents are sideways. How can I fix this?
Still not sure why the above did not work, but the following seems to work:
- (void)viewDidLoad {
[super viewDidLoad];
//for some reason shouldAutorotateToInterfaceOrientation isn't firing when returning to portrait so we need to register for notifications
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(setupScrollView) name:UIDeviceOrientationDidChangeNotification object:nil];
}
I've been unable to find an answer for this (maybe someone has hacked a solution together).
Is it possible to disable scrolling in a UIScrollView in one direction? I am not talking about disabling vertical or horizontal scrolling, but one direction only. So for example, in a UIScrollView, I want to be able to drag the scrollview in a downwards direction, but not in an upwards direction
Thanks
Turns out a simple solution was actually possible and easy:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > 60) {
[scrollView setContentOffset:CGPointMake(0, 60)];
}
}
This works for me:
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
scrollView.bounces = YES;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView.contentOffset.y < 0) {
[scrollView setContentOffset:CGPointMake(0, 0)];
scrollView.bounces = NO;
}
if (scrollView.contentOffset.y == 0){
scrollView.bounces = YES;
}
else scrollView.bounces = YES;
}
Fortunately, we can use scrollRectToVisible to avoid jittery behavior after the scroll has been limited:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > 60) {
[scrollView setContentOffset:CGPointMake(0, 60)];
CGFloat pageWidth = scrollView.frame.size.width;
CGFloat pageHeight = scrollView.frame.size.height;
CGRect rect = CGRectMake(0, 0, pageWidth, pageHeight);
[scrollView scrollRectToVisible:rect animated:YES];
}
}
The above solutions will reset you to zero,zero if the user accidentally scrolls vertically. Try this...
- (void)scrollViewDidScroll:(UIScrollView *) scrollView {
if (scrollView.contentOffset.y > 0) {
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, 0)];
}
}
this works for me
static CGPoint lastOffset;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
scrollView.scrollEnabled = YES;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
scrollView.scrollEnabled = YES;
lastOffset = scrollView.contentOffset;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint nowOffset = scrollView.contentOffset;
NSLog(#"delta %f", lastOffset.x - nowOffset.x);
if ((lastOffset.x - nowOffset.x) < 0) {
//uncomment to prevent scroll to left
//scrollView.scrollEnabled = NO;
} else if ((lastOffset.x - nowOffset.x) > 0) {
//uncomment to prevent scroll to right
//scrollView.scrollEnabled = NO;
} else {
scrollView.scrollEnabled = YES;
}
}
If you set the contentSize of the scroller equals to the size of the content, in one of the direction, the scroll will disappear in that direction because there will be nothing to scroll.
It's possible to remove scrolling in vertical direction by setting the scrollView.contentSize height to the same value as scrollView.frame.size.height. Any overflowing content will be hidden. Same can of course be done to restrict vertical scrolling.
An alternative might be:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y < 10) {
scrollView.bounces = NO;
}
else scrollView.bounces = YES;
}
But remember that this will only work for the scrollViews, which have a bigger content than their frames.
Instead of using a UIScrollViewDelegate to correct the already wrong contentOffset (which will result in a jittery behaviour) you may want to consider to sub class UIScrollView instead and overriding setContentOffset:
- (void)setContentOffset:(CGPoint)contentOffset {
if (contentOffset.y <= 60) {
[super setContentOffset:contentOffset];
}
}
Off course this can be generalized by adding a property for the min or max allowed value for the content offset. You may need to override setContentOffset:animated: as well.
Turn Off the auto layout. I had the same issues only fixed after disabling auto layout in the content view. Xcode 11 . Automatic -> Translate Masks to Constraints