diff --git a/Onboard.podspec b/Onboard.podspec index 2474df6..cd6e136 100644 --- a/Onboard.podspec +++ b/Onboard.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |s| s.name = "Onboard" - s.version = "2.3.1" + s.version = "2.3.3" s.summary = "Create a beautiful and engaging onboarding experience with only a few lines of code." s.homepage = "https://github.com/mamaral/Onboard" s.license = "MIT" s.author = { "Mike Amaral" => "mike.amaral36@gmail.com" } s.social_media_url = "http://twitter.com/MikeAmaral" s.platform = :ios - s.source = { :git => "https://github.com/mamaral/Onboard.git", :tag => "v2.3.1" } + s.source = { :git => "https://github.com/mamaral/Onboard.git", :tag => "v2.3.3" } s.source_files = "Source/OnboardingViewController.{h,m}", "Source/OnboardingContentViewController.{h,m}" s.requires_arc = true s.ios.deployment_target = '8.0' diff --git a/Source/OnboardingContentViewController.m b/Source/OnboardingContentViewController.m index 1e9272d..d12f952 100644 --- a/Source/OnboardingContentViewController.m +++ b/Source/OnboardingContentViewController.m @@ -265,7 +265,12 @@ - (void)viewWillLayoutSubviews { if (self.videoURL) { self.moviePlayerController.view.frame = self.view.frame; } - + + CGFloat safedUnderPageControlPadding = self.underPageControlPadding; + if (@available(iOS 11.0, *)) { + safedUnderPageControlPadding += [self.view safeAreaInsets].bottom; + } + CGFloat viewWidth = CGRectGetWidth(self.view.frame); CGFloat contentWidth = viewWidth * kContentWidthMultiplier; CGFloat xPadding = (viewWidth - contentWidth) / 2.0; @@ -284,7 +289,7 @@ - (void)viewWillLayoutSubviews { [self.bodyLabel sizeToFit]; self.bodyLabel.frame = CGRectMake(xPadding, bodyYOrigin, contentWidth, CGRectGetHeight(self.bodyLabel.frame)); - self.actionButton.frame = CGRectMake((CGRectGetMaxX(self.view.frame) / 2) - (contentWidth / 2), CGRectGetMaxY(self.view.frame) - self.underPageControlPadding - kMainPageControlHeight - kActionButtonHeight - self.bottomPadding, contentWidth, kActionButtonHeight); + self.actionButton.frame = CGRectMake((CGRectGetMaxX(self.view.frame) / 2) - (contentWidth / 2), CGRectGetMaxY(self.view.frame) - safedUnderPageControlPadding - kMainPageControlHeight - kActionButtonHeight - self.bottomPadding, contentWidth, kActionButtonHeight); } diff --git a/Source/OnboardingViewController.m b/Source/OnboardingViewController.m index 1c50a98..9e03a1e 100644 --- a/Source/OnboardingViewController.m +++ b/Source/OnboardingViewController.m @@ -13,7 +13,7 @@ static CGFloat const kPageControlHeight = 35; static CGFloat const kSkipButtonWidth = 100; -static CGFloat const kSkipButtonHeight = 44; +static CGFloat const kSkipButtonHeight = 35; static CGFloat const kBackgroundMaskAlpha = 0.6; static CGFloat const kDefaultBlurRadius = 20; static CGFloat const kDefaultSaturationDeltaFactor = 1.8; @@ -53,7 +53,7 @@ - (instancetype)initWithBackgroundImage:(UIImage *)backgroundImage contents:(NSA } self.backgroundImage = backgroundImage; - + return self; } @@ -72,7 +72,7 @@ - (instancetype)initWithBackgroundVideoURL:(NSURL *)backgroundVideoURL contents: } self.videoURL = backgroundVideoURL; - + return self; } @@ -85,10 +85,10 @@ - (instancetype)initWithContents:(NSArray *)contents { if (!self) { return nil; } - + // Store the passed in view controllers array self.viewControllers = contents; - + // Set the default properties self.shouldMaskBackground = YES; self.shouldBlurBackground = NO; @@ -96,10 +96,10 @@ - (instancetype)initWithContents:(NSArray *)contents { self.fadePageControlOnLastPage = NO; self.fadeSkipButtonOnLastPage = NO; self.swipingEnabled = YES; - + self.allowSkipping = NO; self.skipHandler = ^{}; - + // Create the initial exposed components so they can be customized self.pageControl = [UIPageControl new]; self.pageControl.numberOfPages = self.viewControllers.count; @@ -109,7 +109,7 @@ - (instancetype)initWithContents:(NSArray *)contents { [self.skipButton setTitle:kSkipButtonText forState:UIControlStateNormal]; [self.skipButton addTarget:self action:@selector(handleSkipButtonPressed) forControlEvents:UIControlEventTouchUpInside]; self.skipButton.titleLabel.adjustsFontSizeToFitWidth = YES; - + return self; } @@ -120,14 +120,14 @@ - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppEnteredForeground) name:UIApplicationDidBecomeActiveNotification object:nil]; - + // now that the view has loaded, we can generate the content [self generateView]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - + // if we have a video URL, start playing if (self.videoURL) { [self.player play]; @@ -145,10 +145,15 @@ - (void)viewWillDisappear:(BOOL)animated { - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; + CGFloat safedUnderPageControlPadding = self.underPageControlPadding; + if (@available(iOS 11.0, *)) { + safedUnderPageControlPadding += [self.view safeAreaInsets].bottom; + } + self.pageVC.view.frame = self.view.frame; self.moviePlayerController.view.frame = self.view.frame; - self.skipButton.frame = CGRectMake(CGRectGetMaxX(self.view.frame) - kSkipButtonWidth, CGRectGetMaxY(self.view.frame) - self.underPageControlPadding - kSkipButtonHeight, kSkipButtonWidth, kSkipButtonHeight); - self.pageControl.frame = CGRectMake(0, CGRectGetMaxY(self.view.frame) - self.underPageControlPadding - kPageControlHeight, self.view.frame.size.width, kPageControlHeight); + self.skipButton.frame = CGRectMake(CGRectGetMaxX(self.view.frame) - kSkipButtonWidth, CGRectGetMaxY(self.view.frame) - safedUnderPageControlPadding - kSkipButtonHeight, kSkipButtonWidth, kSkipButtonHeight); + self.pageControl.frame = CGRectMake(0, CGRectGetMaxY(self.view.frame) - safedUnderPageControlPadding - kPageControlHeight, self.view.frame.size.width, kPageControlHeight); } - (void)generateView { @@ -157,13 +162,13 @@ - (void)generateView { self.pageVC.view.backgroundColor = [UIColor whiteColor]; self.pageVC.delegate = self; self.pageVC.dataSource = self.swipingEnabled ? self : nil; - + if (self.shouldBlurBackground) { [self blurBackground]; } - + UIImageView *backgroundImageView; - + // create the background image view and set it to aspect fill so it isn't skewed if (self.backgroundImage) { backgroundImageView = [[UIImageView alloc] initWithFrame:self.view.bounds]; @@ -172,7 +177,7 @@ - (void)generateView { [backgroundImageView setImage:self.backgroundImage]; [self.view addSubview:backgroundImageView]; } - + // as long as the shouldMaskBackground setting hasn't been set to NO, we want to // create a partially opaque view and add it on top of the image view, so that it // darkens it a bit for better contrast @@ -191,7 +196,7 @@ - (void)generateView { // set the initial current page as the first page provided _currentPage = [self.viewControllers firstObject]; - + // more page controller setup [self.pageVC setViewControllers:@[self.currentPage] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; self.pageVC.view.backgroundColor = [UIColor clearColor]; @@ -199,12 +204,12 @@ - (void)generateView { [self.view addSubview:self.pageVC.view]; [self.pageVC didMoveToParentViewController:self]; [self.pageVC.view sendSubviewToBack:backgroundMaskView]; - + // send the background image view to the back if we have one if (backgroundImageView) { [self.pageVC.view sendSubviewToBack:backgroundImageView]; } - + // otherwise send the video view to the back if we have one else if (self.videoURL) { self.player = [[AVPlayer alloc] initWithURL:self.videoURL]; @@ -212,19 +217,19 @@ - (void)generateView { self.moviePlayerController = [AVPlayerViewController new]; self.moviePlayerController.player = self.player; self.moviePlayerController.showsPlaybackControls = NO; - + [self.pageVC.view addSubview:self.moviePlayerController.view]; [self.pageVC.view sendSubviewToBack:self.moviePlayerController.view]; } - + // create the page control [self.view addSubview:self.pageControl]; - + // if we allow skipping, setup the skip button if (self.allowSkipping) { [self.view addSubview:self.skipButton]; } - + // if we want to fade the transitions, we need to tap into the underlying scrollview // so we can set ourself as the delegate, this is sort of hackish but the only current // solution I am aware of using a page view controller @@ -295,7 +300,7 @@ - (void)pageViewController:(UIPageViewController *)pageViewController didFinishA if (!completed) { return; } - + // get the view controller we are moving towards, then get the index, then set it as the current page // for the page control dots UIViewController *viewController = [pageViewController.viewControllers lastObject]; @@ -305,7 +310,7 @@ - (void)pageViewController:(UIPageViewController *)pageViewController didFinishA - (void)moveNextPage { NSUInteger indexOfNextPage = [self.viewControllers indexOfObject:_currentPage] + 1; - + if (indexOfNextPage < self.viewControllers.count) { [self.pageVC setViewControllers:@[self.viewControllers[indexOfNextPage]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; [self.pageControl setCurrentPage:indexOfNextPage]; @@ -331,7 +336,7 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // scrollview's offset and the width of the screen CGFloat percentComplete = fabs(scrollView.contentOffset.x - self.view.frame.size.width) / self.view.frame.size.width; CGFloat percentCompleteInverse = 1.0 - percentComplete; - + // these cases have some funky results given the way this method is called, like stuff // just disappearing, so we want to do nothing in these cases if (percentComplete == 0) { @@ -341,7 +346,7 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // set the next page's alpha to be the percent complete, so if we're 90% of the way // scrolling towards the next page, its content's alpha should be 90% [_upcomingPage updateAlphas:percentComplete]; - + // set the current page's alpha to the difference between 100% and this percent value, // so we're 90% scrolling towards the next page, the current content's alpha sshould be 10% [_currentPage updateAlphas:percentCompleteInverse]; @@ -349,7 +354,7 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { // determine if we're transitioning to or from our last page BOOL transitioningToLastPage = (_currentPage != self.viewControllers.lastObject && _upcomingPage == self.viewControllers.lastObject); BOOL transitioningFromLastPage = (_currentPage == self.viewControllers.lastObject) && (_upcomingPage == self.viewControllers[self.viewControllers.count - 2]); - + // fade the page control to and from the last page if (self.fadePageControlOnLastPage) { if (transitioningToLastPage) { @@ -386,13 +391,13 @@ - (void)blurBackground { NSLog (@"*** error: image must be backed by a CGImage: %@", self.backgroundImage); return; } - + UIColor *tintColor = [UIColor colorWithWhite:0.7 alpha:0.3]; CGFloat blurRadius = kDefaultBlurRadius; CGFloat saturationDeltaFactor = kDefaultSaturationDeltaFactor; CGRect imageRect = { CGPointZero, self.backgroundImage.size }; UIImage *effectImage = self.backgroundImage; - + BOOL hasBlur = blurRadius > __FLT_EPSILON__; BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; if (hasBlur || hasSaturationChange) { @@ -401,13 +406,13 @@ - (void)blurBackground { CGContextScaleCTM(effectInContext, 1.0, -1.0); CGContextTranslateCTM(effectInContext, 0, -self.backgroundImage.size.height); CGContextDrawImage(effectInContext, imageRect, self.backgroundImage.CGImage); - + vImage_Buffer effectInBuffer; effectInBuffer.data = CGBitmapContextGetData(effectInContext); effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); - + UIGraphicsBeginImageContextWithOptions(self.backgroundImage.size, NO, [[UIScreen mainScreen] scale]); CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); vImage_Buffer effectOutBuffer; @@ -415,7 +420,7 @@ - (void)blurBackground { effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); - + if (hasBlur) { // A description of how to compute the box kernel width from the Gaussian // radius (aka standard deviation) appears in the SVG spec: @@ -464,28 +469,28 @@ - (void)blurBackground { if (!effectImageBuffersAreSwapped) effectImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - + if (effectImageBuffersAreSwapped) effectImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); } - + // Set up output context. UIGraphicsBeginImageContextWithOptions(self.backgroundImage.size, NO, [[UIScreen mainScreen] scale]); CGContextRef outputContext = UIGraphicsGetCurrentContext(); CGContextScaleCTM(outputContext, 1.0, -1.0); CGContextTranslateCTM(outputContext, 0, -self.backgroundImage.size.height); - + // Draw base image. CGContextDrawImage(outputContext, imageRect, self.backgroundImage.CGImage); - + // Draw effect image. if (hasBlur) { CGContextSaveGState(outputContext); CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); CGContextRestoreGState(outputContext); } - + // Add in color tint. if (tintColor) { CGContextSaveGState(outputContext); @@ -493,11 +498,11 @@ - (void)blurBackground { CGContextFillRect(outputContext, imageRect); CGContextRestoreGState(outputContext); } - + // Output image is ready. UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - + self.backgroundImage = outputImage; }