Skip to content

Instantly share code, notes, and snippets.

@ZhukV

ZhukV/BookView.m Secret

Created October 29, 2015 15:43
Show Gist options
  • Save ZhukV/1f29fefa84a13f971ce1 to your computer and use it in GitHub Desktop.
Save ZhukV/1f29fefa84a13f971ce1 to your computer and use it in GitHub Desktop.
//
// BookView.m
// Tale
//
// Created by Vitaliy Zhuk on 15.10.14.
// Copyright (c) 2014 ZhukV. All rights reserved.
//
CGFloat const kBookViewPageChangeTimeout = 1.4f;
typedef NS_ENUM(short int, BookViewPageAnimate) {
BookViewPageAnimateLeftUp,
BookViewPageAnimateLeftDown,
BookViewPageAnimateRightUp,
BookViewPageAnimateRightDown
};
typedef NS_ENUM(short int, BookViewTouchOperation) {
BookViewTouchOperationNone,
BookViewTouchOperationPrevPage,
BookViewTouchOperationNextPage
};
typedef NS_ENUM(short int, BookViewButtonPage) {
BookViewButtonPageFirst,
BookViewButtonPageLast
};
#import "BookView.h"
#import "BookAudioNextPage.h"
@interface BookView()
@property (nonatomic) CGPoint startLocation;
@property (nonatomic, strong) UIView *bookPagesView;
@property (nonatomic, strong) UIView *pageLeftView;
@property (nonatomic, strong) UIView *pageRightView;
@property (nonatomic, strong) UIView *nextPageLeftView;
@property (nonatomic, strong) UIView *nextPageRightView;
@property (nonatomic, strong) UIView *pageCommonView;
@property (nonatomic, strong) UIImageView *pageCommonLeftView;
@property (nonatomic, strong) UIImageView *pageCommonRightView;
@property (nonatomic, strong) AVAudioPlayer *audio;
@property (nonatomic, strong) NSTimer *presentationTimer;
@property (nonatomic) NSTimeInterval presentationPauseOn;
@property (nonatomic) float pageCenterWidth;
@property (nonatomic) float indexCenterOffset;
@property (nonatomic) CGSize pageSize;
- (UIImage *)coverImage;
- (UIView *)createPageNative:(BookViewPage)page;
- (UIView *)createPageView:(NSInteger)index;
- (UIView *)createPageView:(NSInteger)index page:(BookViewPage)page;
- (void)renderCommonPages;
- (void)renderCommonPagesLeft;
- (void)renderCommonPagesRight;
- (void)hideCommonPages:(NSInteger)index;
- (void)hideCommonPages;
- (NSUInteger)countCommonPages:(BookViewPage)page viewIndex:(NSInteger)index;
- (NSUInteger)countCommonPages:(BookViewPage)page;
- (float)bookPagesViewOffset:(NSInteger)index;
- (float)bookPagesViewOffset;
- (void)renderButtonsOnLastPage;
- (void)renderButtonsOnFirstPage;
- (UIView *)createCommonButtons:(NSArray *)buttonModes page:(BookViewButtonPage)page;
- (UIButton *)createCommonButton:(BookViewActionButton)mode page:(BookViewButtonPage)page;
- (void)clickCommonButtonOnFirstPage:(UIButton *)button;
- (void)clickCommonButtonOnLastPage:(UIButton *)button;
- (void)presentationStart;
- (void)presentationUpdate;
- (void)presentationTimerTick;
- (int)presentationIndexByTime;
- (void)animatePagesViewOffset:(NSInteger)index;
- (void)animatePagesViewOffset;
- (void)animatePageWithMode:(BookViewPageAnimate)animate
oldView:(UIView *)oldView
newView:(UIView *)newView
completion:(void (^)(void))completion;
@end
#pragma mark -
@implementation BookView
#pragma mark Initialize
- (instancetype)initWithBook:(BookModel *)book delegate:(id<BookViewDelegate>)delegate
{
self = [super init];
if (!self) {
return nil;
}
_book = book;
_delegate = delegate;
_processed = NO;
CGRect bookPagesFrame, pageCommonFrame, pageCommonLeftFrame, pageCommonRightFrame;
UIView *bookPagesRootView = [UIView new];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
self.frame = CGRectMake(0, 0, 399, 291);
self.pageCenterWidth = 27;
self.pageSize = CGSizeMake(183, 284);
bookPagesFrame = CGRectMake(3.f, 4, 366, 274);
pageCommonFrame = CGRectMake(3.f, 4, 389, 281);
pageCommonLeftFrame = CGRectMake(0, 0, 100, 284);
pageCommonRightFrame = CGRectMake(293, 0, 100, 284);
} else {
self.frame = CGRectMake(0, 0, 960, 700);
self.pageCenterWidth = 64;
self.pageSize = CGSizeMake(438, 680);
bookPagesFrame = CGRectMake(10, 10, 876, 660);
pageCommonFrame = CGRectMake(10, 10, 940, 680);
pageCommonLeftFrame = CGRectMake(0, 0, 300, 680);
pageCommonRightFrame = CGRectMake(641.f, 0, 300, 680);
}
// Create cover mode
self.backgroundColor = [UIColor colorWithPatternImage:[self coverImage]];
// Create page root view
bookPagesRootView.frame = bookPagesFrame;
self.bookPagesView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, bookPagesFrame.size.width, bookPagesFrame.size.height)];
[bookPagesRootView addSubview:self.bookPagesView];
// Create left and right common view of pages
self.pageCommonView = [[UIView alloc] initWithFrame:pageCommonFrame];
self.pageCommonLeftView = [[UIImageView alloc] initWithFrame:pageCommonLeftFrame];
self.pageCommonLeftView.clipsToBounds = YES;
self.pageCommonRightView = [[UIImageView alloc] initWithFrame:pageCommonRightFrame];
self.pageCommonRightView.clipsToBounds = YES;
[self.pageCommonView addSubview:self.pageCommonLeftView];
[self.pageCommonView addSubview:self.pageCommonRightView];
// Create pager
int indexes = floor((float)[self.book.pages count] / 2) + 1;
_pager.indexes = indexes; // Because first and last page view with one image
self.indexCenterOffset = self.pageCenterWidth / (indexes - 3);
// View page with first page (Zero view index)
[self addSubview:self.pageCommonView];
[self addSubview:bookPagesRootView];
// Render puzzle button
[self renderButtonsOnLastPage];
[self renderButtonsOnFirstPage];
// Render common pages
[self renderCommonPages];
return self;
}
+ (instancetype)withBook:(BookModel *)book delegate:(id<BookViewDelegate>)delegate
{
return [[self alloc] initWithBook:book delegate:delegate];
}
#pragma mark -
#pragma mark Create views and helpers for view
- (UIImage *)coverImage
{
return [UIImage imageNamedWithoutCache:self.book.cover];
}
- (UIView *)createPageNative:(BookViewPage)page
{
NSString *imagePath;
if (page == BookViewPageLeft) {
imagePath = self.book.pageLeft;
} else {
imagePath = self.book.pageRight;
}
UIImage *image = [UIImage imageNamedWithoutCache:imagePath];
UIImageView *view = [[UIImageView alloc] initWithImage:image];
view.frame = CGRectMake(0, 0, self.pageSize.width, self.pageSize.height);
return view;
}
- (UIView *)createPageView:(NSInteger)index
{
if (!fmodf(index, 2)) {
return [self createPageView:index page:BookViewPageRight];
} else {
return [self createPageView:index page:BookViewPageLeft];
}
}
- (UIView *)createPageView:(NSInteger)index page:(BookViewPage)page
{
NSString *path = [self.book.pages objectAtIndex:index];
UIImage *image = [UIImage imageNamedWithoutCache:path];
UIImageView *view = [[UIImageView alloc] initWithImage:image];
CGRect viewFrame = view.frame;
if (page == BookViewPageLeft) {
viewFrame.origin = CGPointMake(0, 0);
view.layer.anchorPoint = CGPointMake(1, 0.5);
} else {
viewFrame.origin = CGPointMake(self.pageSize.width, 0);
view.layer.anchorPoint = CGPointMake(0, 0.5);
}
viewFrame.size = self.pageSize;
view.frame = viewFrame;
return view;
}
- (void)renderCommonPages
{
[self renderCommonPagesLeft];
[self renderCommonPagesRight];
}
- (void)renderCommonPagesLeft
{
int i;
UIView *page;
CGRect pageFrame;
UIView *commonLeftView = [UIView new];
commonLeftView.frame = self.pageCommonLeftView.frame;
commonLeftView.backgroundColor = [UIColor clearColor];
commonLeftView.opaque = NO;
for (i = 0; i <= self.pager.indexes / 2 + 2; i++) {
page = [self createPageNative:BookViewPageLeft];
pageFrame = page.frame;
pageFrame.origin.x = self.indexCenterOffset * i;
page.frame = pageFrame;
[commonLeftView addSubview:page];
}
UIImage *imageLeftCommon = [UIImage imageWithView:commonLeftView];
[self.pageCommonLeftView setImage:imageLeftCommon];
}
- (void)renderCommonPagesRight
{
int i;
UIView *page;
CGRect pageFrame;
UIView *commonRightView = [UIView new];
commonRightView.frame = self.pageCommonRightView.frame;
commonRightView.backgroundColor = [UIColor clearColor];
commonRightView.opaque = NO;
for (i = 0; i < self.pager.indexes / 2 + 2; i++) {
page = [self createPageNative:BookViewPageRight];
pageFrame = page.frame;
pageFrame.origin.x = -(self.pageSize.width - self.pageCommonRightView.frame.size.width) - (i * self.indexCenterOffset);
page.frame = pageFrame;
[commonRightView addSubview:page];
}
UIImage *imageRightCommon = [UIImage imageWithView:commonRightView];
[self.pageCommonRightView setImage:imageRightCommon];
}
- (void)hideCommonPages:(NSInteger)index
{
if (index == 0) {
self.pageCommonLeftView.hidden = YES;
} else {
self.pageCommonLeftView.hidden = NO;
}
if (index + 1 == self.pager.indexes) {
self.pageCommonRightView.hidden = YES;
} else {
self.pageCommonRightView.hidden = NO;
}
}
- (void)hideCommonPages
{
[self hideCommonPages:self.pager.index];
}
- (NSUInteger)countCommonPages:(BookViewPage)page viewIndex:(NSInteger)index
{
if (page == BookViewPageLeft) {
if (index <= 1) {
return 0;
}
return index - 1;
} else {
if (index >= self.pager.indexes - 1) {
return 0;
}
return self.pager.index - index - 1;
}
}
- (NSUInteger)countCommonPages:(BookViewPage)page
{
return [self countCommonPages:page viewIndex:self.pager.index];
}
- (float)bookPagesViewOffset:(NSInteger)index
{
if (index == 0 || index == 1) {
return 0;
} else if (index == self.pager.indexes - 2 || index == self.pager.indexes - 1) {
return self.pageCenterWidth;
}
return self.indexCenterOffset * [self countCommonPages:BookViewPageLeft viewIndex:index];
}
- (float)bookPagesViewOffset
{
return [self bookPagesViewOffset:self.pager.index];
}
#pragma mark -
#pragma mark Render buttons on first and last page
- (void)renderButtonsOnLastPage
{
NSMutableArray *buttons = [NSMutableArray new];
if (self.book.puzzle != nil) {
[buttons addObject:[NSNumber numberWithShort:BookViewActionButtonPuzzle]];
}
[buttons addObject:[NSNumber numberWithShort:BookViewActionButtonMoreTales]];
UIView *buttonsView = [self createCommonButtons:buttons page:BookViewButtonPageLast];
CGRect buttonsViewFrame = buttonsView.frame;
buttonsViewFrame.origin.x = self.pageSize.width + (self.pageSize.width - buttonsViewFrame.size.width) / 2;
buttonsViewFrame.origin.y = (self.pageSize.height - buttonsViewFrame.size.height) / 2;
buttonsView.frame = buttonsViewFrame;
buttonsView.layer.zPosition = -1000;
[self.bookPagesView addSubview:buttonsView];
}
- (void)renderButtonsOnFirstPage
{
NSMutableArray *buttons = [NSMutableArray new];
if (self.book.audioFile != nil) {
[buttons addObject:[NSNumber numberWithShort:BookViewActionButtonReadMe]];
}
if (self.book.puzzle != nil) {
[buttons addObject:[NSNumber numberWithShort:BookViewActionButtonPuzzle]];
}
UIView *buttonsView = [self createCommonButtons:buttons page:BookViewButtonPageFirst];
CGRect buttonsViewFrame = buttonsView.frame;
buttonsViewFrame.origin.x = (self.pageSize.width - buttonsViewFrame.size.width) / 2;
buttonsViewFrame.origin.y = (self.pageSize.height - buttonsViewFrame.size.height) / 2;
buttonsView.frame = buttonsViewFrame;
buttonsView.layer.zPosition = -1000;
[self.bookPagesView addSubview:buttonsView];
}
- (UIView *)createCommonButtons:(NSArray *)buttonModes page:(BookViewButtonPage)page
{
NSMutableArray *buttons = [NSMutableArray new];
for (NSNumber *buttonMode in buttonModes) {
[buttons addObject:[self createCommonButton:[buttonMode shortValue] page:page]];
}
float maxWidth = 0, fullHeight = 0;
int separated = 15;
UIView *buttonsView = [UIView new];
CGRect buttonFrame;
// First iteration: Get max width.
for (UIButton *button in buttons) {
if (button.frame.size.width > maxWidth) {
maxWidth = button.frame.size.width;
}
}
// Second iteration: Add buttons to buttons view
for (int i = 0; i < [buttons count]; i++) {
UIButton *button = [buttons objectAtIndex:i];
if (button.frame.size.width > maxWidth) {
maxWidth = button.frame.size.width;
}
buttonFrame = button.frame;
buttonFrame.origin.y = fullHeight;
buttonFrame.origin.x = (maxWidth - buttonFrame.size.width) / 2;
fullHeight += buttonFrame.size.height + separated;
button.frame = buttonFrame;
[buttonsView addSubview:button];
}
CGRect buttonsViewFrame = buttonsView.frame;
buttonsViewFrame.size.width = maxWidth;
buttonsViewFrame.size.height = fullHeight - separated;
buttonsView.frame = buttonsViewFrame;
return buttonsView;
}
- (UIButton *)createCommonButton:(BookViewActionButton)mode page:(BookViewButtonPage)page
{
NSString *imagePath;
switch (mode) {
case BookViewActionButtonPuzzle:
imagePath = @"button-puzzle-%@-%@@2x.png";
break;
case BookViewActionButtonMoreTales:
imagePath = @"button-more-tales-%@-%@@2x.png";
break;
case BookViewActionButtonReadMe:
imagePath = @"button-read-me-%@-%@@2x.png";
break;
default: {
NSString *reason = [NSString stringWithFormat:@"Undefined button book mode: %d", mode];
@throw [NSException exceptionWithName:@"InvalidArgument" reason:reason userInfo:@{@"mode": [NSNumber numberWithShort:mode]}];
}
}
imagePath = [NSString stringWithFormat:imagePath, TALE_LOCALE, UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? @"ipad" : @"iphone"];
UIImage *image = [UIImage imageNamedWithoutCache:imagePath];
UIButton *button = [[UIButton alloc] init];
button.backgroundColor = [UIColor colorWithPatternImage:image];
CGRect buttonFrame = button.frame;
buttonFrame.size = image.size;
button.frame = buttonFrame;
button.tag = mode;
if (page == BookViewButtonPageFirst) {
[button addTarget:self action:@selector(clickCommonButtonOnFirstPage:) forControlEvents:UIControlEventTouchUpInside];
} else if (page == BookViewButtonPageLast) {
[button addTarget:self action:@selector(clickCommonButtonOnLastPage:) forControlEvents:UIControlEventTouchUpInside];
} else {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Invalid page mode." userInfo:@{@"page": [NSNumber numberWithInt:(int)page]}];
}
return button;
}
- (void)clickCommonButtonOnFirstPage:(UIButton *)button
{
if (self.pager.index == 0) {
BookViewActionButton action = button.tag;
[self.delegate clickButtonAction:action];
}
}
- (void)clickCommonButtonOnLastPage:(UIButton *)button
{
if (self.pager.index + 1 == self.pager.indexes) {
BookViewActionButton action = button.tag;
[self.delegate clickButtonAction:action];
}
}
#pragma mark -
#pragma mark Set pages
- (void)viewPagesAtIndex:(NSUInteger)index
changeTo:(BookViewPageChange)changeTo
animate:(BOOL)animate
{
[self viewPagesAtIndex:index changeTo:changeTo animate:YES completion:nil pauseAudio:YES];
}
- (void)viewPagesAtIndex:(NSUInteger)index
changeTo:(BookViewPageChange)changeTo
animate:(BOOL)animate
completion:(void (^)(void))completion
pauseAudio:(BOOL)pauseAudio
{
if (self.processed) {
return;
}
_processed = YES;
self.presentationPauseOn = 0;
if (self.delegate) {
[self.delegate pageAnimationStart];
}
if (index == 0) {
self.nextPageLeftView = nil;
self.nextPageRightView = [self createPageView:0];
} else if (index + 1 == self.pager.indexes) {
self.nextPageLeftView = [self createPageView:[self.book.pages count] - 1];
self.nextPageRightView = nil;
} else {
self.nextPageLeftView = [self createPageView:index * 2 - 1];
self.nextPageRightView = [self createPageView:index * 2];
}
BOOL runInPresentation = NO;
if (animate && changeTo != BookViewPageChangeToNone) {
_pager.index = index;
[self animatePagesViewOffset];
// Hide next page views
self.nextPageLeftView.hidden = YES;
self.nextPageRightView.hidden = YES;
// Add views to root book view
[self.bookPagesView addSubview:self.nextPageLeftView];
[self.bookPagesView addSubview:self.nextPageRightView];
if (pauseAudio && self.presentation) {
[self presentationStop];
runInPresentation = YES;
}
// Run next page audio
[[BookAudioNextPage sharedInstance] play];
if (changeTo == BookViewPageChangeToLeft) {
if (index == 0) {
self.pageCommonLeftView.hidden = YES;
} else {
self.pageCommonLeftView.hidden = NO;
}
// First step of animation. Up page
[self animatePageWithMode:BookViewPageAnimateRightUp oldView:self.pageLeftView newView:self.nextPageLeftView completion:^{
// Set the really view and clear temporary
self.pageLeftView = self.nextPageLeftView;
self.nextPageLeftView = nil;
// Second step of animation. Down page.
[self animatePageWithMode:BookViewPageAnimateLeftDown oldView:self.pageRightView newView:self.nextPageRightView completion:^{
self.pageRightView = self.nextPageRightView;
self.nextPageRightView = nil;
self.pageCommonRightView.hidden = NO;
_processed = NO;
[self.delegate pageAnimationComplete];
if (pauseAudio && runInPresentation) {
[self presentationStart];
}
if (completion) {
completion();
}
}];
}];
} else if (changeTo == BookViewPageChangeToRight) {
if (index + 1 == self.pager.indexes) {
self.pageCommonRightView.hidden = YES;
} else {
self.pageCommonRightView.hidden = NO;
}
// First step of animation. Up page
[self animatePageWithMode:BookViewPageAnimateLeftUp oldView:self.pageRightView newView:self.nextPageRightView completion:^{
// Set the really view and clear temporary
self.pageRightView = self.nextPageRightView;
self.nextPageRightView = nil;
// Second step of animation. Down page.
[self animatePageWithMode:BookViewPageAnimateRightDown oldView:self.pageLeftView newView:self.nextPageLeftView completion:^{
self.pageLeftView = self.nextPageLeftView;
self.nextPageLeftView = nil;
self.pageCommonLeftView.hidden = NO;
_processed = NO;
[self.delegate pageAnimationComplete];
if (pauseAudio && runInPresentation) {
[self presentationStart];
}
if (completion) {
completion();
}
}];
}];
}
} else {
if (self.pageLeftView) {
[self.pageLeftView removeFromSuperview];
}
if (self.pageRightView) {
[self.pageRightView removeFromSuperview];
}
if (self.nextPageLeftView) {
self.pageLeftView = self.nextPageLeftView;
self.nextPageLeftView = nil;
[self.bookPagesView addSubview:self.pageLeftView];
}
if (self.nextPageRightView) {
self.pageRightView = self.nextPageRightView;
self.nextPageRightView = nil;
[self.bookPagesView addSubview:self.pageRightView];
}
_pager.index = index;
[self hideCommonPages];
CGRect bookPagesFrame = self.bookPagesView.frame;
bookPagesFrame.origin.x = [self bookPagesViewOffset];
self.bookPagesView.frame = bookPagesFrame;
_processed = NO;
[self.delegate pageAnimationComplete];
if (completion) {
completion();
}
}
[self.delegate viewPageAtIndex:index];
}
- (void)viewNextPages
{
NSUInteger nextIndex = self.pager.index + 1;
if (nextIndex > (self.pager.indexes - 1)) {
return;
}
[self viewPagesAtIndex:nextIndex changeTo:BookViewPageChangeToRight animate:YES];
}
- (void)viewPrevPages
{
if (self.pager.index < 1) {
return;
}
NSUInteger prevIndex = self.pager.index - 1;
[self viewPagesAtIndex:prevIndex changeTo:BookViewPageChangeToLeft animate:YES];
}
#pragma mark -
#pragma mark Presentation
- (void)presentationStart
{
if (self.pager.indexes == self.pager.index + 1) {
// Not run on last page
return;
}
if (_processed) {
// Now processed. Not run
return;
}
if (nil == self.audio) {
NSURL *path = [[NSBundle mainBundle] URLForResource:self.book.audioFile withExtension:nil];
NSError *error = nil;
self.audio = [[AVAudioPlayer alloc] initWithContentsOfURL:path error:&error];
#ifdef DEBUG
if (error) {
NSLog(@"Error with loading mp3 file %@: %@", path, error);
}
#endif
[self.audio setVolume:0.7];
[self.audio setNumberOfLoops:0];
}
NSUInteger activeIndex = self.pager.index;
if (activeIndex == 0) {
[self.delegate presentationStart];
[self viewPagesAtIndex:1 changeTo:BookViewPageChangeToRight animate:YES completion:^{
self.audio.currentTime = 0;
[self.audio prepareToPlay];
[self.audio play];
[self performSelector:@selector(presentationTimerInitialize) withObject:self afterDelay:0.03f];
_presentation = YES;
} pauseAudio:NO];
} else if (activeIndex + 1 != self.pager.indexes) {
_presentation = YES;
[self presentationUpdate];
[self performSelector:@selector(presentationTimerInitialize) withObject:self afterDelay:0.03f];
}
}
- (void)presentationUpdate
{
if (!self.presentation) {
return;
}
[self.delegate presentationStart];
NSUInteger activeIndex = self.pager.index;
if (activeIndex == 0) {
[self presentationStop];
} else {
NSTimeInterval playFromTime;
if (self.presentationPauseOn > 0) {
playFromTime = self.presentationPauseOn;
self.presentationPauseOn = 0;
} else {
NSNumber *timeMap;
timeMap = [self.book.audioPageTimeMap objectAtIndex:activeIndex - 1];
if (!timeMap) {
[self presentationStop];
return;
}
playFromTime = [timeMap doubleValue];
}
self.audio.currentTime = playFromTime;
[self.audio prepareToPlay];
[self.audio play];
}
}
- (void)presentationPause
{
_presentation = NO;
[self presentationTimerDeinitialize];
[self.audio pause];
self.presentationPauseOn = self.audio.currentTime;
[self.delegate presentationStop];
}
- (void)presentationStop
{
_presentation = NO;
self.presentationPauseOn = 0;
if (self.audio && [self.audio isPlaying]) {
[self.audio stop];
}
// Clear presentation timer
[self presentationTimerDeinitialize];
[self.delegate presentationStop];
}
- (void)presentationTimerInitialize
{
if (nil == self.presentationTimer) {
self.presentationTimer = [NSTimer scheduledTimerWithTimeInterval:0.2f
target:self
selector:@selector(presentationTimerTick)
userInfo:nil
repeats:YES];
}
}
- (void)presentationTimerDeinitialize
{
if (self.presentationTimer && [self.presentationTimer isValid]) {
[self.presentationTimer invalidate];
self.presentationTimer = nil;
}
}
- (void)presentationTimerTick
{
if (self.processed) {
return;
}
int index = [self presentationIndexByTime];
if (![self.audio isPlaying]) {
[self presentationStop];
return;
}
if (index != -1 && index != self.pager.index) {
if (index + 1 <= self.pager.indexes) {
[self viewPagesAtIndex:index changeTo:BookViewPageChangeToRight animate:YES completion:nil pauseAudio:NO];
}
}
}
- (int)presentationIndexByTime
{
NSTimeInterval time = self.audio.currentTime;
for (int i = 0; i < [self.book.audioTimeMap count]; i++) {
NSNumber *lowMapElement = [self.book.audioTimeMap objectAtIndex:i];
NSTimeInterval low = [lowMapElement doubleValue];
if (i + 1 == [self.book.audioTimeMap count]) {
if (time > low) {
return i + 1;
}
} else {
NSNumber *hightMapElement = [self.book.audioTimeMap objectAtIndex:i + 1];
NSTimeInterval hight = [hightMapElement doubleValue];
if (time >= low && time < hight) {
return i + 1;
}
}
}
return -1;
}
#pragma mark -
#pragma mark Animate action
- (void)animatePagesViewOffset:(NSInteger)index
{
CGRect frame = self.bookPagesView.frame;
frame.origin.x = [self bookPagesViewOffset:index];
[UIView animateWithDuration:kBookViewPageChangeTimeout animations:^{
self.bookPagesView.frame = frame;
}];
}
- (void)animatePagesViewOffset
{
[self animatePagesViewOffset:self.pager.index];
}
- (void)animatePageWithMode:(BookViewPageAnimate)animate
oldView:(UIView *)oldView
newView:(UIView *)newView
completion:(void (^)(void))completion
{
CATransform3D hidesTransform, viewedTransform = CATransform3DIdentity;
float factor = M_PI / 180;
float m14 = 1.f / (2.5f * (self.pageSize.width * 2));
if (animate == BookViewPageAnimateLeftUp || animate == BookViewPageAnimateLeftDown) {
hidesTransform = CATransform3DMakeRotation(-(90 * factor), 0, 1, 0);
hidesTransform.m14 = -m14;
} else {
hidesTransform = CATransform3DMakeRotation(90 * factor, 0, 1, 0);
hidesTransform.m14 = m14;
}
if (animate == BookViewPageAnimateRightDown || animate == BookViewPageAnimateLeftDown) {
oldView.layer.zPosition = -1.f;
newView.layer.transform = hidesTransform;
newView.hidden = NO;
[UIView animateWithDuration:kBookViewPageChangeTimeout / 2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
newView.layer.transform = viewedTransform;
} completion:^(BOOL finished) {
[oldView removeFromSuperview];
completion();
}];
} else if (animate == BookViewPageAnimateRightUp || animate == BookViewPageAnimateLeftUp) {
oldView.layer.zPosition = 1.f;
newView.hidden = NO;
[UIView animateWithDuration:kBookViewPageChangeTimeout / 2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
oldView.layer.transform = hidesTransform;
} completion:^(BOOL finished) {
[oldView removeFromSuperview];
completion();
}];
}
#ifdef DEBUG
else {
NSString *reason = [NSString stringWithFormat:@"Invalid animate mode \"%d\".", animate];
@throw [NSException exceptionWithName:@"InvalidArgument" reason:reason userInfo:@{@"mode": [NSNumber numberWithInt:animate]}];
}
#endif
}
#pragma mark -
#pragma mark Touch events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
self.startLocation = [touch locationInView:self.window];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint startLocation, endLocation;
startLocation = self.startLocation;
endLocation = [touch locationInView:self.window];
// Attention: the app work with only landscape orientation, but we must use "y" os.
int diffWidth = 0;
BookViewTouchOperation operation = BookViewTouchOperationNone;
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
switch (orientation) {
case UIDeviceOrientationLandscapeLeft:
case UIDeviceOrientationLandscapeRight:
case UIDeviceOrientationPortrait:
case UIDeviceOrientationPortraitUpsideDown:
case UIDeviceOrientationFaceUp:
case UIDeviceOrientationFaceDown:
diffWidth = startLocation.x - endLocation.x;
break;
default:
break;
}
// Check for pager
if (abs(diffWidth) > 50) {
if (diffWidth > 0) {
operation = BookViewTouchOperationNextPage;
} else {
operation = BookViewTouchOperationPrevPage;
}
}
// Call method by operation
switch (operation) {
case BookViewTouchOperationPrevPage:
[self viewPrevPages];
break;
case BookViewTouchOperationNextPage:
[self viewNextPages];
break;
default:
break;
}
}
#pragma mark -
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment