4
votes

I have seen this question being addressed several times here at SO, e.g Problem with UIScrollView Content Offset, but I´m still not able to solve it.

My iphone app is basically a tab bar controller with navigation bar. I have a tableview controller made programmatically and a DetailViewController that slides in when I tap a cell in my tableview controller.

The DetailViewController is made in IB and has the following hierarchy:

top view => UIScrollView => UIView => UIImage and a UITextField.

My goal is to be able to scroll the image and text field and this works well. The problem is that my UIScrollView always gets positioned at the bottom instead at the top.

After recommendations her at SO, I have made my UIScrollView same size as the top view and instead made the UIView with the max height (1500) of my variable contents.

In ViewDidLoad I set the contentSize for the UIScrollView (as this is not accessible from IB):

- (void)viewDidLoad {

  [scrollView setContentSize:CGSizeMake(320, 1500)];
  [scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
  NSLog(@"viewDidLoad: contentOffset y: %f",[scrollView contentOffset].y);
}

Specifically setting the contentOffset, I would expect my scrollView to always end up at the top. Instead it always go to the bottom. It looks to me that there is some autoscrolling beyond my control taking place after this method.

My read back of the contentOffset looks OK. It looks to me that there may be some timing related issues as the scrolling result may vary whether animation is YES or NO.

A ugly workaround I have found is by using this delegate method:

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrView {
    NSLog(@"Prog. scrolling ended");
    [scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}

This brings my scrollview to top, but makes it bounce down and up like a yo-yo

Another clue might be that although my instance variables for the IBOutlet are set before I push the view controller, the first time comes up with empty image and textfield:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath  *)indexPath {

    if (!detailViewController) {
       detailViewController = [[DayDetailViewController alloc] init];
    }

    // Pass dictionary for the selected event to next controller
    NSDictionary *dict = [eventsDay objectAtIndex:[indexPath row]];
    // This method sets values for the image and textfield outlets
   [detailViewController setEventDictionary:dict];  

    // Push it onto the top of the navigation controller´s stack.
    [[self navigationController] pushViewController:detailViewController animated:NO];


}

If I set animation to YES, and switch the order of the IBOutlet setting and pushViewController, I can avoid the emptiness upon initialization. Why?

Any help with these matters are highly appreciated, as this is really driving me nuts!

2

2 Answers

2
votes

Inspired of Ponchotg´s description of a programmatically approach, I decided to skip interface builder. The result was in some way disappointing: The same problem, with the scrollview ending up in unpredictable positions (mostly at bottom), persisted.

However, I noticed that the scroll offset error was much smaller. I think this is related to the now dynamic (and generally smaller) value of ContentOffset. After some blind experimenting I ended up setting

[textView setScrollEnabled:YES];

This was previously set to NO, as the UITextView is placed inside the scrollview, which should take care of the scrolling. (In my initial question, I have erroneously said it was a UITextField, that was wrong)

With this change my problem disappeared, I was simply not able to get into the situation with scrollview appearing at bottom anymore in the simulator! (At my 3G device I have seen a slight offset appear very seldom, but this is easily fixed with scrollViewDidEndScrollingAnimation delegate described previously ).

I consider this as solved now, but would appreciate if anyone understand why this little detail messes up things?

0
votes

OK! i have a question before i can give a correct answer.

Why are you using a UIView inside the Scrollview?

You can always only put your UIImageView and UITextField inside the UIScrollView without the UIView

and set the contentSize dynamically depending on the size of the text.

to give you an example how i do it:

int contSize = 0;
imageView.frame = CGRectMake(10, 0, 300, 190);
imageView.image = [UIImage imageNamed:@"yourimage"];

contSize = 190 //or add extra space if you dont want your image and your text to be so close

[textField setScrollEnabled:NO];
textField.font = [UIFont systemFontOfSize:15];
textField.textColor = [UIColor grayColor];
textField.text = @"YOUR TEXT";
[textField setEditable:NO];
textField.frame = CGRectMake(5, contSize, 310, 34);
CGRect frameText = textField.frame;
frameText.size.height = textField.contentSize.height;
textField.frame = frameText;
contSize += (textField.contentSize.height);

[scrollView setScrollEnabled:YES];
[scrolView setContentSize:CGSizeMake(320, contSize)];

In the above example I first create an int to keep track of the ysize of my view then Give settings and the image to my UIImageView and add that number to my int then i give settings and text to my UITextField and then i calculate the size of my text depending on how long is my text and the size of my font, then add that to my int and finally assign the contentSize of my ScrollView to match my int.

That way the size of your scrollview will always match your view, and the scrollView will always be at top.

But if you don't want to do all this, you can allways just:

[scrollView setContentOffset:CGPointMake(0, 0) animated:NO];

at the end of the code where you set your image and your text, and the NOto avoid the bouncing.

Hope this helps.