I'm subclassing UIScrollView and on the start I fill this ShowsScrollView with some items. After filling it, I setup frame and contentSize to this ShowsScrollView. Everything works fine for now, i get touches events, scrolling is working..
But after rotation to landscape, I change x and y coordinates of ShowsScrollView frame, to move it from bottom to top right corner. Then I resize it (change width and height of ShowsScrollView frame) and reorder items in this scroll. At the end I setup new contentSize.
Now i get touches event only on first 1/4 of scrollview, scrolling also work only on 1/4 of scrollview, but scroll all items in scrollview.
After all actions I write a log: NSLog(#"ViewController: setLandscape finished: size: %f, %f content: %f,%f",scrollView.frame.size.width,scrollView.frame.size.height, scrollView.contentSize.width, scrollView.contentSize.height );
Values are correct:
ViewController: setLandscape finished: size: 390.000000, 723.000000 content: 390.000000,950.000000
On rotating back to portrait, I move and resize all thing back and everything works fine..
Please help!
I had the same issue and managed to get it working by setting the size of self.view again AFTER changing the scrollview's frame. I don't know why this works, but it does.
// Set the view's frame
if (UIDeviceOrientationIsLandscape(toOrientation)) {
[self.view setSize:CGSizeMake(1024, 724)];
} else {
[self.view setSize:CGSizeMake(768, 960)];
}
// Set scrollview frame
if (UIInterfaceOrientationIsLandscape(toOrientation)) {
self.scrollView.frame = CGRectMake(0, 0, 100, 300);
self.scrollView.contentSize = CGSizeMake(100, 600);
}
else {
self.scrollView.frame = CGRectMake(0, 0, 300, 100);
self.scrollView.contentSize = CGSizeMake(600, 100);
}
// Move your content around here
// Set the view's frame again
if (UIDeviceOrientationIsLandscape(toOrientation)) {
[self.view setSize:CGSizeMake(1024, 724)];
} else {
[self.view setSize:CGSizeMake(768, 960)];
}
You have to bring scrollView to front of the superView, for example:
[self.view bringSubviewToFron:scrollView];
Related
I have a scrollview with pagination. In viewDidLoad i check if the current orientation is landscape then i set its contentsize's height 440
if (UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]))
{
[scroll setContentSize:CGSizeMake(self.scroll.frame.size.width*numberOfPages,340)];
}
else if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
{
[scroll setFrame:CGRectMake(0,0,480,480)];
[scroll setContentSize:CGSizeMake(self.scroll.frame.size.width*numberOfPages, 440)];
}
everything works fine scrollview scrolls smoothy and there is no diagonal scrolling.
but when orientation changes,
i have to set scrollview's frame and contentsize again and i am setting it as follow
-(void)orientationChanged:(id)object
{
if(UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]))
{
self.scroll.frame = [[UIScreen mainScreen]bounds];
[scroll setContentSize:CGSizeMake(self.scroll.frame.size.width*numberOfPages, 340)];
}
else
{
self.scroll.frame = CGRectMake(0,0,480,480);
[scroll setContentSize:CGSizeMake(self.scroll.frame.size.width*numberOfPages, 600)];
}
}
i cant understand why i have to set content size's height upto 600 in landscape mode, and that too isnt enough. and it adds one more problem that scrollview starts scrolling diagonally which i dont want as it looks so weird. Can anyone help me understanding where and what i am missing?
i have set scrollview's autoresizing mask as
[scroll setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleHeight];
but changing it doesnt help.
Don't use UIDeviceOrientation. Use UIInterfaceOrientation instead. DeviceOrientation has two extra options you don't need here. (UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown)
Return Yes from shouldAutorotateToInterfaceOrientation
Now willRotateToInterfaceOrientation: duration: will be called every time you rotate your device.
Implement this method like this.
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
CGRect frame;
int pageNumber = 2;
int statusBarHeight = 20;
if ((toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)) {
frame = CGRectMake(0, 0, 480, 320 - statusBarHeight);
} else {
frame = CGRectMake(0, 0, 320, 480 - statusBarHeight);
}
scrollView.frame = frame;
scrollView.contentSize = CGSizeMake(frame.size.width * 2, frame.size.height);
}
Let,
pageNumber = 2
statusBarHeight = 20
Here it is a problem in your code. Why you are setting the frame size like this?? You have only the screen size of 320px width. And when it changes to landscape, height will be only 320px. But you are setting the scroll height as 480px and it goes out of the screen and start to scroll diagonally.
self.scroll.frame = CGRectMake(0,0,480,480);
Instead of that frame size, change like this
self.scroll.frame = CGRectMake(0,0,480,320);
And you need to set the content size depend on the content you are having inside the scroll view in either orientation.
I have a scrollview with an image as a subview. I would like to set the boundaries of the scrollview to be the size of the image view, so that you wouldn't be able to see any of the background.
I don't want this happening anymore.
The weird part is, that after you zoom in or out on the image, then the boundaries seem to fix themselves, and you can no longer move the image out of the way and see the background.
This is what I have going for code:
-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
{
// return which subview we want to zoom
return self.imageView;
}
-(void)viewDidLoad{
[super viewDidLoad];
[self sendLogMessage:#"Second View Controller Loaded"];
//sets the initial view to scale to fit the screen
self.imageView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));
//sets the content size to be the size our our whole frame
self.scrollView.contentSize = self.imageView.image.size;
//setes the scrollview's delegate to itself
self.scrollView.delegate = self;
//sets the maximum zoom to 2.0, meaning that the picture can only become a maximum of twice as big
[self.scrollView setMaximumZoomScale : 2.5];
//sets the minimum zoom to 1.0 so that the scrollview can never be smaller than the image (no matter how far in/out we're zoomed)
[self.scrollView setMinimumZoomScale : 1.0];
[imageView addSubview:button];
}
I thought that this line would solve my problem
//sets the content size to be the size our our whole frame
self.scrollView.contentSize = self.imageView.image.size;
But like I said, it only works after I zoom in or out.
EDIT: When I switch
self.scrollView.contentSize = self.imageView.image.size;
to
self.scrollView.frame = self.imageView.frame;
It works like I want it to (you can't see the background), except the toolbar on the top is covered by the image.
imageView.image.size isn't necessarily the frame of the imageView itself, try setting the
scrollview.frame = imageView.frame
and then
scrollView.contentSize = imageView.image.size
Then you won't see any border. If you want the image to be the maximum size to start with,
do
imageView.frame = image.size;
[imageView setImage:image];
scrollView.frame = self.view.frame; //or desired size
[scrollView addSubView:imageView];
[scrollView setContentSize:image.size]; //or imageView.frame.size
To fix this, I ended up declaring a new CGRect , setting its origin to my scrollView's origin, setting its size with the bounds of my view, and then assigning this CGRect back to my scrollview frame
CGRect scrollFrame;
scrollFrame.origin = self.scrollView.frame.origin;
scrollFrame.size = CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));
self.scrollView.frame = scrollFrame;
I am using a UIScrollView with Paging enabled and the following code to add subviews (core plot charts) to it.
The horizontal scrolling between the views works properly.
However, when showing the second view and then rotating from landscape to portrait mode, the second view is shifted partly to the right and a portion of the first view's right hand side is shown on the left side, hence "destroying" the paging mode.
Could you help me with these issue please? I tried many alternatives, but can't find my bug. Thank you so much!
This is how my iPad screen looks after rotating to portrait mode with the second view:
:
This is my viewDidLoad method:
- (void)viewDidLoad {
self.scrollView.contentSize = CGSizeMake(768 * 2, 400);
chart1 = [[CPTGraphHostingView alloc]initWithFrame:CGRectMake(0, 0, 768, 400)];
chart2 = [[CPTGraphHostingView alloc]initWithFrame:CGRectMake(768, 0, 768, 400)];
self.scrollView.autoresizesSubviews = NO;
chart1.autoresizesSubviews = YES;
chart2.autoresizesSubviews = YES;
self.scrollView.contentOffset = CGPointZero;
self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth ;
chart1.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth ;
chart2.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth ;
[self.scrollView addSubview:chart1];
[self.scrollView addSubview:chart2];
}
This is how I have implemented rotation:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if (UIDeviceOrientationIsPortrait(fromInterfaceOrientation)) {
self.scrollView.contentSize = CGSizeMake(704 * 2, 400);
chart1.frame = CGRectMake(0, 0, 704, 400);
chart2.frame = CGRectMake(704, 0, 704, 400);
}
else {
self.scrollView.contentSize = CGSizeMake(768 * 2, 400);
chart1.frame = CGRectMake(0, 0, 768, 400);
chart2.frame = CGRectMake(768, 0, 768, 400);
}
}
I think you should change the contentOffset of the scrollview when rotation is taking place.
You should have a way to know which page is currently displayed before rotation (maybe put this information in a variable). Then in your didRotate.. method set the contentOffset of the scrollview after resizing it, like this:
CGFloat offset = self.scrollView.frame.size.width * currentPageIndex;
[self.scrollView setContentOffset: offset];
As an alternative to laying out your subviews in your view controller, have you considered subclassing your UIScrollView and overriding it's layoutSubviews method? You might also consider defining your dimensions as percentages rather than fixed points - because the point values will shift according to rotation and presence of other UI elements such as navigation and toolbars. You may run into trouble as you're manually resizing UI elements in your rotation method, at the same time that the UI is going to be attempting to automatically resize elements according to your resizing masks. Just my thought...
I have a main view that is supposed to display several subviews. Those subviews are directly above and below one another (in the z axis) and will drop down (in the y axis) and move up using this code:
if (!CGRectIsNull(rectIntersection)) {
CGRect newFrame = CGRectOffset (rectIntersection, 0, -2);
[backgroundView setFrame:newFrame];
} else{
[viewsUpdater invalidate];
viewsUpdater = nil;
}
rectIntersection is used to tell when the view has entirely moved down and is no longer behind the front one (when they no longer overlap rectIntersection is null), it moves down by 2 pixels at a time because this is all inside a repeating timer. I want my main view, the one that contains these two other views, to resize downward so that it expands just as the view in the background is being lowered. This is the code I'm trying for that:
CGRect mainViewFrame = [mainView frame];
if (!CGRectContainsRect(mainViewFrame, backgroundFrame)) {
CGRect newMainViewFrame = CGRectMake(0,
0,
mainViewFrame.size.width,
(mainViewFrame.size.height + 2));
[mainView setFrame:newMainViewFrame];
}
The idea is to check if the mainView contains this background view. When the backgroundView is lowered, the main view no longer contains it, and it (should) expand downward by 2 pixels. This would happen until the background view stopped moving and the mainView finally contains backgroundView.
The problem is that the mainView is not resizing at all. the background view is being lowered, and I can see it until it disappears off the bottom of the mainView. mainView should have resized but it does not change in any direction. I tried using setFrame and setBounds (with and without setNeedsDisplay) but nothing worked.
I'm really just looking for a way to programmatically change the size of the main view.
I think I understood, what the problem is. I read carefuly the code.
if (!CGRectIsNull(rectIntersection)) {
// here you set the wrong frame
//CGRect newFrame = CGRectOffset (rectIntersection, 0, -2);
CGRect newFrame = CGRectOffset (backgroundView.frame, 0, -2);
[backgroundView setFrame:newFrame];
} else{
[viewsUpdater invalidate];
viewsUpdater = nil;
}
rectIntersection is actually the intersection of the two views, that overlap, and as the backgroundView is moved downward, that rect's height decreases.
That way the mainView gets resized only one time.
To add on this, here is a simple solution using block syntax, to animate your views, this code would typically take place in your custom view controller.
// eventually a control action method, pass nil for direct call
-(void)performBackgroundViewAnimation:(id)sender {
// first, double the mainView's frame height
CGFrame newFrame = CGRectMake(mainView.frame.origin.x,
mainView.frame.origin.y,
mainView.frame.size.width,
mainView.frame.size.height*2);
// then get the backgroundView's destination rect
CGFrame newBVFrame = CGRectOffset(backgroundView.frame,
0,
-(backgroundView.frame.size.height));
// run the animation
[UIView animateWithDuration:1.0
animations:^{
mainView.frame = newFrame;
backgroundView.frame = newBVFrame;
}
];
}
I have several UIViews added as subViews to my main view controller. The way I have the views laid out looks fine in portrait mode, however, when it is tilted in to landscape mode, the bottom parts of the subviews gets cut off. I figured if I set the height of the frame, it would allow the screen to scroll and thus reveal the parts of the subViews that were cut off - but it doesn't.
- (void)didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[notification object] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft) {
self.view.frame = CGRectMake(0.0, 0.0, 1024.0, maxHeight);
} else if (orientation == UIDeviceOrientationLandscapeRight) {
self.view.frame = CGRectMake(0.0, 0.0, 1024.0, maxHeight);
}
}
I also tried adding a UIScrollView to the main view, then adding the afore mentioned subViews to the scrollView
- (void)viewDidLoad
{
scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
[self.view addSubview:scrollView];
//add views to scrollView
[super viewDidLoad];
}
How can I make the main view "scroll" if the sub-views exceed the screen size?
After you add your views to the scroll view, you must set the contentSize property of the scroll view so that the scroll view knows there's content to be scrolled to.