Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID
Please do not post the same thing multiple times. The board software automatically flags certain posts as needing moderator attention. This happens the most often for new users. I'm pretty sure this is made clear at the time you attempt to post. Posting the same thing over and over again just makes that many more posts the moderators have to weed through later. This makes us sad. Don't make us sad. If your post/thread doesn't appear, just wait a while. Don't post it again. If it hasn't shown up by the next day, then you can try again. I normally go through posts in the mornings, and try to check a few times throughout the day, but I'm not here 24/7. There will typically be a significant delay before posts are approved. Just be patient.

UIScrollView - making a interactive book

DrwallDrwall Posts: 3New Users
Hello,

I'm making a interactive book that consists of about 30 pages, each being represented by a separate UIViewController subclass with a XIB for user interface. There are animations, sounds and interactive elements on most of the pages. I'd like to know what is the best practise in making a interactive application like this.

My PageController class is responsible for all the initialization and handling page changes. It creates a UIScrollView that displays the pages. In order to use as less memory as needed, I decided to store in memory a maximum amount of 3 pages at a time. I'm using 3 UIViewControllers - pagePrevious, pageCurrent and pageNext. Here is my code for the UIScrollView's scrolling part:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
int newPage = scrollView.contentOffset.x / self.view.frame.size.height + 1;

if(newPage > currentPage) {
if(pagePrevious != nil) {
[pagePrevious.view removeFromSuperview];
[pagePrevious release];
}

pagePrevious = pageCurrent;
pageCurrent = pageNext;

if(newPage < PAGE_COUNT) {
NSString *pageClass;

if(newPage < 9) {
pageClass = [NSString stringWithFormat:@\"Page0%d\", (newPage + 1)];
} else {
pageClass = [NSString stringWithFormat:@\"Page%d\", (newPage + 1)];
}

pageNext = [[NSClassFromString(pageClass) alloc] init];
pageNext.view.frame = CGRectMake(self.view.frame.size.height * newPage, 0, self.view.frame.size.height, self.view.frame.size.width);
[scrollView addSubview:pageNext.view];
}
} else if(newPage < currentPage) {
if(pageNext != nil) {
[pageNext.view removeFromSuperview];
[pageNext release];
}

pageNext = pageCurrent;
pageCurrent = pagePrevious;

if(newPage > 1) {
NSString *pageClass;

if(newPage < 11) {
pageClass = [NSString stringWithFormat:@\"Page0%d\", (newPage - 1)];
} else {
pageClass = [NSString stringWithFormat:@\"Page%d\", (newPage - 1)];
}

pagePrevious = [[NSClassFromString(pageClass) alloc] init];
pagePrevious.view.frame = CGRectMake(self.view.frame.size.height * (newPage - 2), 0, self.view.frame.size.height, self.view.frame.size.width);
[scrollView addSubview:pagePrevious.view];
}
}

currentPage = newPage;
}


Unfortunately, this code gives me some bad access issues. For example, when I change pages like this: 1 -> 2 -> 1 -> 2 -> 1, I get a blank screen instead of page 1 and then, when I slide to page 2, the application crashes (EXC_BAD_ACCESS). Having "[pagePrevious release]" and "[pageNext release]" removed solves the problem with the crashes but not with the blank screens. Having removed removeFromSuperview lines solves it entirely, but I'm aware of the fact that those viewControllers still reside in memory which was clearly not my point.

I don't really know what exactly is wrong with this code. My initialization method of PageController looks like:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if(self) {
pageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.height, self.view.frame.size.width)];
pageScrollView.pagingEnabled = YES;
pageScrollView.scrollEnabled = YES;
pageScrollView.showsVerticalScrollIndicator = NO;
pageScrollView.showsHorizontalScrollIndicator = NO;
pageScrollView.bounces = NO;

pagePrevious = nil;
pageCurrent = [[Page01 alloc] init];
pageNext = [[Page02 alloc] init];

[pageCurrent.view setFrame:CGRectMake(0, 0, self.view.frame.size.height, self.view.frame.size.width)];
[pageNext.view setFrame:CGRectMake(self.view.frame.size.height, 0, self.view.frame.size.height, self.view.frame.size.width)];

[pageScrollView addSubview:pageCurrent.view];
[pageScrollView addSubview:pageNext.view];

pageScrollView.contentSize = CGSizeMake(self.view.frame.size.height * PAGE_COUNT, self.view.frame.size.width);

[pageScrollView setDelegate:self];

[self.view addSubview:pageScrollView];

currentPage = 1;
}

return self;
}


By the way: should I use a different UIScrollView delegate method for handling page changes? And should I store more pages (like 2 previous and 2 next) at a time?

I hope you can help me out :)

Regards,
Drwall
Post edited by Drwall on

Replies

  • DrwallDrwall Posts: 3New Users
    Shame on me... This slightly altered code works just fine:

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    if(scrollView != pageScrollView) return;

    int newPage = floor(scrollView.contentOffset.x / self.view.frame.size.height) + 1;

    if(newPage > currentPage) {
    if(pagePrevious != nil) {
    [pagePrevious.view removeFromSuperview];
    [pagePrevious release];
    }

    pagePrevious = pageCurrent;
    pageCurrent = pageNext;

    if(newPage < PAGE_COUNT) {
    NSString *pageClass;

    if(newPage < 9) {
    pageClass = [NSString stringWithFormat:@\"Page0%d\", (newPage + 1)];
    } else {
    pageClass = [NSString stringWithFormat:@\"Page%d\", (newPage + 1)];
    }

    pageNext = [[NSClassFromString(pageClass) alloc] initWithNibName:pageClass bundle:nil];
    pageNext.view.frame = CGRectMake(self.view.frame.size.height * newPage, 0, self.view.frame.size.height, self.view.frame.size.width);
    [scrollView addSubview:pageNext.view];
    } else {
    if(pageNext != nil) {
    pageNext = nil;
    }
    }
    } else if(newPage < currentPage) {
    if(pageNext != nil) {
    [pageNext.view removeFromSuperview];
    [pageNext release];
    }

    pageNext = pageCurrent;
    pageCurrent = pagePrevious;

    if(newPage > 1) {
    NSString *pageClass;

    if(newPage < 11) {
    pageClass = [NSString stringWithFormat:@\"Page0%d\", (newPage - 1)];
    } else {
    pageClass = [NSString stringWithFormat:@\"Page%d\", (newPage - 1)];
    }

    pagePrevious = [[NSClassFromString(pageClass) alloc] initWithNibName:pageClass bundle:nil];
    pagePrevious.view.frame = CGRectMake(self.view.frame.size.height * (newPage - 2), 0, self.view.frame.size.height, self.view.frame.size.width);
    [scrollView addSubview:pagePrevious.view];
    } else {
    if(pagePrevious != nil) {
    pagePrevious = nil;
    }
    }
    }

    currentPage = newPage;
    }


    But another question came to my mind - how could I prevent UIScrollView from scrolling "too fast"? When I swipe really quickly scrollViewDidEndDecelerating doesn't get called so pages don't get loaded and I end up getting blank screens. Should I change the delegate method or think about limiting the contentSize of UIScrollView?
  • DrwallDrwall Posts: 3New Users
    Alright... Never mind :O I feel really stupid but I solved that myself as well.

    I simply used scrollViewDidScroll instead of scrollViewDidEndDecelerating.

    Sorry for this mess. I hope I will at least help someone in the future...

    Regards,
    Drwall
  • Bhanu BiraniBhanu Birani Posts: 2New Users
    Hi, I am also having the same piece of problem, but the difference is i am having the web views in place of views, so can u please attach a sample code of yours. So that i can figure out my error.
  • Bhanu BiraniBhanu Birani Posts: 2New Users
    Thanks for your posts. I got the solution. Thanks a lot...
Sign In or Register to comment.