4
votes

I'm having some problems when I change the frame of my scrollview... sometimes this changing causes a scroll and sometimes not.

Here is the situation. I have a custom UIScrollView as the subview of my root view controller. In the parent view controller I have a button to change the frame of scrollview. It change between 2/3 of screen and full screen. This frame change never cause a change on the contentOffset of scrollview.

In the content of scrollview I have some buttons. This buttons change the frame of scrollview too. But, sometimes, this change make the scrollview change its contentOffset...

I can't figure out why the button inside the scrollview causes this...

I've already tried to call a delegate when the button is touched (and change frame of scrollview in the parent view controller). And tried to change frame inside scrollview (when the button is touched). But the problem occurs the same way.

Any idea what is going on or some workaround to this situation?

Thanks!


I tried to isolate the problem to put here some simple example with code.

In my xib there's only a scrollview with frame ((20,44),(728,300)) and a button that call the event "btnOut". That scrollview is with Paging Enabled and Autoresize Subviews disabled (the rest is default).

I will use a boolean to know if scrollview is big or not (bigScroll).

Here is my viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // the initial frame of scrollView is the big frame
    _bigScroll = YES;

    // here I put a big content to create some pages in scrollView
    [_scrollView setContentSize:CGSizeMake(2184, 300)];

    // I put one button in each column
    // When scrollView is with big frame it shows two columns and when it is with small frame it shows only one column.

    UIButton *btn01 = [UIButton buttonWithType:UIButtonTypeSystem];
    [btn01 setFrame:CGRectMake(159, 30, 46, 30)];
    [btn01 setTitle:@"01" forState:UIControlStateNormal];
    [btn01 addTarget:self action:@selector(btnIn:) forControlEvents:UIControlEventTouchDown];
    [_scrollView addSubview:btn01];

    UIButton *btn02 = [UIButton buttonWithType:UIButtonTypeSystem];
    [btn02 setFrame:CGRectMake(523, 30, 46, 30)];
    [btn02 setTitle:@"02" forState:UIControlStateNormal];
    [btn02 addTarget:self action:@selector(btnIn:) forControlEvents:UIControlEventTouchDown];
    [_scrollView addSubview:btn02];

    UIButton *btn03 = [UIButton buttonWithType:UIButtonTypeSystem];
    [btn03 setFrame:CGRectMake(887, 30, 46, 30)];
    [btn03 setTitle:@"03" forState:UIControlStateNormal];
    [btn03 addTarget:self action:@selector(btnIn:) forControlEvents:UIControlEventTouchDown];
    [_scrollView addSubview:btn03];

    UIButton *btn04 = [UIButton buttonWithType:UIButtonTypeSystem];
    [btn04 setFrame:CGRectMake(1251, 30, 46, 30)];
    [btn04 setTitle:@"04" forState:UIControlStateNormal];
    [btn04 addTarget:self action:@selector(btnIn:) forControlEvents:UIControlEventTouchDown];
    [_scrollView addSubview:btn04];

    UIButton *btn05 = [UIButton buttonWithType:UIButtonTypeSystem];
    [btn05 setFrame:CGRectMake(1615, 30, 46, 30)];
    [btn05 setTitle:@"05" forState:UIControlStateNormal];
    [btn05 addTarget:self action:@selector(btnIn:) forControlEvents:UIControlEventTouchDown];
    [_scrollView addSubview:btn05];

    UIButton *btn06 = [UIButton buttonWithType:UIButtonTypeSystem];
    [btn06 setFrame:CGRectMake(1979, 30, 46, 30)];
    [btn06 setTitle:@"06" forState:UIControlStateNormal];
    [btn06 addTarget:self action:@selector(btnIn:) forControlEvents:UIControlEventTouchDown];
    [_scrollView addSubview:btn06];
}

Both actions "btnIn" and "btnOut" call the same function (changeFrameScrollView).

- (void)changeFrameScrollView {
    _bigScroll = !_bigScroll;

    if (_bigScroll) {
        [_scrollView setFrame:CGRectMake(20, 44, 728, 300)];
    } else {
        [_scrollView setFrame:CGRectMake(20, 44, 364, 300)];
    }
}

What I expected: Using the button that is out of the scrollview, the frame change works as I expected.

  • If it change to small frame it hide the column from right and keep showing the column from left.
  • If it change to big frame it show the column from the right and don't move the contentOffset.

** Independent of the page I'm viewing.

The problem: Using the button that is inside the scrollview, sometimes, the frame change causes a change in the contentOffset.

  • If scrollview is in small frame and it is showing the column 02 and I press the inside button it change frame and show columns 03 and 04 (that same action with the button is outside show columns 02 and 03).

Well... I can't explain so well, so I put a small example when that occurs.

2
Maybe some code would help. Also, describe the content offset change.Mundi

2 Answers

1
votes

I found out that is a private method that is causing that => _adjustContentOffsetIfNecessary

It change the offset in some cases and don't change in others. Like I explained in my example.

That private method isn't called if the paging is disabled so to solve my problem I created a subclass of UIScrollView and overwrite the method touchesShouldBegin (it is called only when the button inside scrollView is pressed) and disable the paging:

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view {
    [self setPagingEnabled:NO];
    return YES;
}

To set the paging enabled again, I use the delegate scrollViewWillBeginDragging.

Doing that, the contentOffset don't change when I change the frame and the scrollView continues to work with paging.

-1
votes

Here is what might be happening:

Suppose you have a scroll view with

contentSize.height   |  200 
frame.size.height    |  100
contentOffset.y      |    0

then half of the content will be invisible. If you change the frame

frame.size height    |  200

the contentOffset should not change.

If, however, you start with

contentSize.height   |  200 
frame.size.height    |  100
contentOffset.y      |  100  

and do the same change, I would suppose that the scroll view will try to fit its content into the visible frame, so you would end up with

contentOffset.y      |    0

again, effectively changing it from 100 to 0.