diff --git a/AlertOnboarding.podspec b/AlertOnboarding.podspec new file mode 100644 index 0000000..22d290b --- /dev/null +++ b/AlertOnboarding.podspec @@ -0,0 +1,16 @@ +Pod::Spec.new do |s| +s.name = "AlertOnboarding" +s.version = "1.0" +s.summary = "AlertOnboarding" +s.description = "A simple and handsome AlertView for onboard your users in your amazing world." +s.homepage = "https://github.com/PhilippeBoisney/AlertOnboarding" +s.license = 'MIT' +s.author = { "PhilippeBoisney" => "phil.boisney@gmail.com" } +s.source = { :git => "https://github.com/PhilippeBoisney/AlertOnboarding.git", :tag => s.version.to_s } +s.platform = :ios, '8.0' +s.requires_arc = true + +# If more than one source file: https://guides.cocoapods.org/syntax/podspec.html#source_files +spec.source_files = 'AlertOnboarding/AlertChildPageViewController.swift', 'AlertOnboarding/AlertOnboarding.swift', 'AlertOnboarding/AlertChildPageViewController.xib', 'AlertOnboarding/AlertPageViewController.swift' + +end diff --git a/AlertOnboarding.xcodeproj/project.pbxproj b/AlertOnboarding.xcodeproj/project.pbxproj index 41d8fad..5f86723 100644 --- a/AlertOnboarding.xcodeproj/project.pbxproj +++ b/AlertOnboarding.xcodeproj/project.pbxproj @@ -266,6 +266,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = AlertOnboarding/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.cookminute.AlertOnboarding; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -277,6 +278,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = AlertOnboarding/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.cookminute.AlertOnboarding; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/AlertOnboarding.xcodeproj/project.xcworkspace/xcuserdata/Phil.xcuserdatad/UserInterfaceState.xcuserstate b/AlertOnboarding.xcodeproj/project.xcworkspace/xcuserdata/Phil.xcuserdatad/UserInterfaceState.xcuserstate index 369237d..9894cd8 100644 Binary files a/AlertOnboarding.xcodeproj/project.xcworkspace/xcuserdata/Phil.xcuserdatad/UserInterfaceState.xcuserstate and b/AlertOnboarding.xcodeproj/project.xcworkspace/xcuserdata/Phil.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Classes/AlertChildPageViewController.swift b/Classes/AlertChildPageViewController.swift new file mode 100644 index 0000000..1bcebdc --- /dev/null +++ b/Classes/AlertChildPageViewController.swift @@ -0,0 +1,26 @@ +// +// AlertChildPageViewController.swift +// AlertOnboarding +// +// Created by Philippe Boisney on 24/03/2016. +// Copyright © 2016 Philippe Boisney. All rights reserved. +// + +import UIKit + +class AlertChildPageViewController: UIViewController { + + var pageIndex: Int! + + @IBOutlet weak var image: UIImageView! + @IBOutlet weak var labelMainTitle: UILabel! + @IBOutlet weak var labelDescription: UILabel! + + override func viewDidLoad() { + super.viewDidLoad() + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + } +} diff --git a/Classes/AlertChildPageViewController.xib b/Classes/AlertChildPageViewController.xib new file mode 100644 index 0000000..9ec3919 --- /dev/null +++ b/Classes/AlertChildPageViewController.xib @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/AlertOnboarding.swift b/Classes/AlertOnboarding.swift new file mode 100644 index 0000000..96d8aff --- /dev/null +++ b/Classes/AlertOnboarding.swift @@ -0,0 +1,212 @@ +// +// AlertOnboarding.swift +// AlertOnboarding +// +// Created by Philippe Boisney on 23/03/2016. +// Copyright © 2016 Philippe Boisney. All rights reserved. +// + + +import UIKit + +public class AlertOnboarding: UIView { + + //FOR DATA ------------------------ + private var arrayOfImage = [String]() + private var arrayOfTitle = [String]() + private var arrayOfDescription = [String]() + + //FOR DESIGN ------------------------ + public var buttonBottom: UIButton! + private var container: AlertPageViewController! + + + //PUBLIC VARS ------------------------ + public var colorForAlertViewBackground: UIColor = UIColor.whiteColor() + + public var colorButtonBottomBackground: UIColor = UIColor(red: 226/255, green: 237/255, blue: 248/255, alpha: 1.0) + public var colorButtonText: UIColor = UIColor(red: 118/255, green: 125/255, blue: 152/255, alpha: 1.0) + + public var colorTitleLabel: UIColor = UIColor(red: 171/255, green: 177/255, blue: 196/255, alpha: 1.0) + public var colorDescriptionLabel: UIColor = UIColor(red: 171/255, green: 177/255, blue: 196/255, alpha: 1.0) + + public var colorPageIndicator = UIColor(red: 171/255, green: 177/255, blue: 196/255, alpha: 1.0) + public var colorCurrentPageIndicator = UIColor(red: 118/255, green: 125/255, blue: 152/255, alpha: 1.0) + + public var heightForAlertView: CGFloat! + public var widthForAlertView: CGFloat! + + public var purcentageRatioHeight: CGFloat = 0.8 + public var purcentageRatioWidth: CGFloat = 0.8 + + public var titleSkipButton = "SKIP" + public var titleGotItButton = "GOT IT !" + + + public init (arrayOfImage: [String], arrayOfTitle: [String], arrayOfDescription: [String]) { + super.init(frame: CGRectMake(0,0,0,0)) + self.configure(arrayOfImage, arrayOfTitle: arrayOfTitle, arrayOfDescription: arrayOfDescription) + self.arrayOfImage = arrayOfImage + self.arrayOfTitle = arrayOfTitle + self.arrayOfDescription = arrayOfDescription + + self.interceptOrientationChange() + } + + override public init(frame: CGRect) { + super.init(frame: frame) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override public func layoutSubviews() { + super.layoutSubviews() + } + + //----------------------------------------------------------------------------------------- + // MARK: PUBLIC FUNCTIONS -------------------------------------------------------------- + //----------------------------------------------------------------------------------------- + + public func show() { + + //Update Color + self.buttonBottom.backgroundColor = colorButtonBottomBackground + self.backgroundColor = colorForAlertViewBackground + self.buttonBottom.setTitleColor(colorButtonText, forState: .Normal) + self.buttonBottom.setTitle(self.titleSkipButton, forState: .Normal) + + self.container = AlertPageViewController(arrayOfImage: arrayOfImage, arrayOfTitle: arrayOfTitle, arrayOfDescription: arrayOfDescription, alertView: self) + self.insertSubview(self.container.view, aboveSubview: self) + self.insertSubview(self.buttonBottom, aboveSubview: self) + + // Only show once + if self.superview != nil { + return + } + + // Find current stop viewcontroller + if let topController = getTopViewController() { + let superView: UIView = topController.view + superView.addSubview(self) + self.configureConstraints(topController.view) + self.animateForOpening() + } + } + + //Start the animation + public func hide(){ + dispatch_async(dispatch_get_main_queue()) { + () -> Void in + self.animateForEnding() + } + } + + + //------------------------------------------------------------------------------------------ + // MARK: PRIVATE FUNCTIONS -------------------------------------------------------------- + //------------------------------------------------------------------------------------------ + + + //MARK: FOR CONFIGURATION -------------------------------------- + private func configure(arrayOfImage: [String], arrayOfTitle: [String], arrayOfDescription: [String]) { + + self.buttonBottom = UIButton(frame: CGRectMake(0,0, 0, 0)) + self.buttonBottom.titleLabel?.font = UIFont(name: "Avenir-Black", size: 15) + self.buttonBottom.addTarget(self, action: Selector("onClick"), forControlEvents: .TouchUpInside) + + self.clipsToBounds = true + self.layer.cornerRadius = 10 + } + + + private func configureConstraints(superView: UIView) { + + self.translatesAutoresizingMaskIntoConstraints = false + self.buttonBottom.translatesAutoresizingMaskIntoConstraints = false + self.container.view.translatesAutoresizingMaskIntoConstraints = false + + self.removeConstraints(self.constraints) + self.buttonBottom.removeConstraints(self.buttonBottom.constraints) + self.container.view.removeConstraints(self.container.view.constraints) + + heightForAlertView = UIScreen.mainScreen().bounds.height*purcentageRatioHeight + widthForAlertView = UIScreen.mainScreen().bounds.width*purcentageRatioWidth + + //Constraints for alertview + let horizontalContraintsAlertView = NSLayoutConstraint(item: self, attribute: .CenterXWithinMargins, relatedBy: .Equal, toItem: superView, attribute: .CenterXWithinMargins, multiplier: 1.0, constant: 0) + let verticalContraintsAlertView = NSLayoutConstraint(item: self, attribute:.CenterYWithinMargins, relatedBy: .Equal, toItem: superView, attribute: .CenterYWithinMargins, multiplier: 1.0, constant: 0) + let heightConstraintForAlertView = NSLayoutConstraint.init(item: self, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: heightForAlertView) + let widthConstraintForAlertView = NSLayoutConstraint.init(item: self, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: widthForAlertView) + + //Constraints for button + let verticalContraintsButtonBottom = NSLayoutConstraint(item: self.buttonBottom, attribute:.CenterXWithinMargins, relatedBy: .Equal, toItem: self, attribute: .CenterXWithinMargins, multiplier: 1.0, constant: 0) + let heightConstraintForButtonBottom = NSLayoutConstraint.init(item: self.buttonBottom, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: heightForAlertView*0.1) + let widthConstraintForButtonBottom = NSLayoutConstraint.init(item: self.buttonBottom, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: widthForAlertView) + let pinContraintsButtonBottom = NSLayoutConstraint(item: self.buttonBottom, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: 0) + + //Constraints for container + let verticalContraintsForContainer = NSLayoutConstraint(item: self.container.view, attribute:.CenterXWithinMargins, relatedBy: .Equal, toItem: self, attribute: .CenterXWithinMargins, multiplier: 1.0, constant: 0) + let heightConstraintForContainer = NSLayoutConstraint.init(item: self.container.view, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: heightForAlertView*0.9) + let widthConstraintForContainer = NSLayoutConstraint.init(item: self.container.view, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: widthForAlertView) + let pinContraintsForContainer = NSLayoutConstraint(item: self.container.view, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0) + + + NSLayoutConstraint.activateConstraints([horizontalContraintsAlertView, verticalContraintsAlertView,heightConstraintForAlertView, widthConstraintForAlertView, + verticalContraintsButtonBottom, heightConstraintForButtonBottom, widthConstraintForButtonBottom, pinContraintsButtonBottom, + verticalContraintsForContainer, heightConstraintForContainer, widthConstraintForContainer, pinContraintsForContainer]) + } + + //MARK: FOR ANIMATIONS --------------------------------- + private func animateForOpening(){ + self.alpha = 1.0 + self.transform = CGAffineTransformMakeScale(0.3, 0.3) + UIView.animateWithDuration(1, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: [], animations: { + self.transform = CGAffineTransformMakeScale(1, 1) + }, completion: nil) + } + + private func animateForEnding(){ + UIView.animateWithDuration(0.2, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { + self.alpha = 0.0 + }, completion: { + (finished: Bool) -> Void in + // On main thread + dispatch_async(dispatch_get_main_queue()) { + () -> Void in + self.removeFromSuperview() + self.container.removeFromParentViewController() + self.container.view.removeFromSuperview() + } + }) + } + + //MARK: BUTTON ACTIONS --------------------------------- + + func onClick(){ + self.hide() + } + + //MARK: OTHERS -------------------------------------- + private func getTopViewController() -> UIViewController? { + var topController: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController + while topController?.presentedViewController != nil { + topController = topController?.presentedViewController + } + return topController + } + + private func interceptOrientationChange(){ + UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications() + NSNotificationCenter.defaultCenter().addObserver(self, selector: "onOrientationChange", name: UIDeviceOrientationDidChangeNotification, object: nil) + } + + func onOrientationChange(){ + if let superview = self.superview { + self.configureConstraints(superview) + self.container.configureConstraintsForPageControl() + } + } + +} diff --git a/Classes/AlertPageViewController.swift b/Classes/AlertPageViewController.swift new file mode 100644 index 0000000..2fbade7 --- /dev/null +++ b/Classes/AlertPageViewController.swift @@ -0,0 +1,155 @@ +// +// AlertPageViewController.swift +// AlertOnboarding +// +// Created by Philippe Boisney on 24/03/2016. +// Copyright © 2016 Philippe Boisney. All rights reserved. +// + +import UIKit + +class AlertPageViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate { + + //FOR DESIGN + var pageController: UIPageViewController! + var pageControl: UIPageControl! + var alertview: AlertOnboarding! + + //FOR DATA + var arrayOfImage: [String]! + var arrayOfTitle: [String]! + var arrayOfDescription: [String]! + var viewControllers = [UIViewController]() + + + init (arrayOfImage: [String], arrayOfTitle: [String], arrayOfDescription: [String], alertView: AlertOnboarding) { + super.init(nibName: nil, bundle: nil) + self.arrayOfImage = arrayOfImage + self.arrayOfTitle = arrayOfTitle + self.arrayOfDescription = arrayOfDescription + self.alertview = alertView + } + + required init(coder: NSCoder) { + fatalError("NSCoding not supported") + } + + override func viewDidLoad() { + super.viewDidLoad() + + self.configurePageViewController() + self.configurePageControl() + + self.view.backgroundColor = UIColor.clearColor() + self.view.addSubview(self.pageController.view) + self.view.addSubview(self.pageControl) + self.pageController.didMoveToParentViewController(self) + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(animated) + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + } + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + } + + + func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? { + + var index = (viewController as! AlertChildPageViewController).pageIndex! + + if(index == 0){ + return nil + } + + index-- + return self.viewControllerAtIndex(index) + } + + func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? { + + var index = (viewController as! AlertChildPageViewController).pageIndex! + + index++ + + if(index == arrayOfImage.count){ + return nil + } + + return self.viewControllerAtIndex(index) + } + + + func viewControllerAtIndex(index : Int) -> UIViewController? { + let pageContentViewController = UINib(nibName: "AlertChildPageViewController", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! AlertChildPageViewController + pageContentViewController.pageIndex = index // 0 + + let realIndex = arrayOfImage.count - index - 1 + + pageContentViewController.image.image = UIImage(named: arrayOfImage[realIndex]) + pageContentViewController.labelMainTitle.text = arrayOfTitle[realIndex] + pageContentViewController.labelMainTitle.textColor = alertview.colorTitleLabel + pageContentViewController.labelDescription.text = arrayOfDescription[realIndex] + pageContentViewController.labelDescription.textColor = alertview.colorDescriptionLabel + + return pageContentViewController + } + + func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { + let pageContentViewController = pageViewController.viewControllers![0] as! AlertChildPageViewController + let index = pageContentViewController.pageIndex + if pageControl != nil { + pageControl.currentPage = arrayOfImage.count - index - 1 + if pageControl.currentPage == arrayOfImage.count - 1 { + self.alertview.buttonBottom.setTitle(alertview.titleGotItButton, forState: .Normal) + } else { + self.alertview.buttonBottom.setTitle(alertview.titleSkipButton, forState: .Normal) + } + } + } + + + func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int { + return arrayOfImage.count + } + + func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int { + return 0 + } + + //MARK: CONFIGURATION --------------------------------------------------------------------------------- + private func configurePageControl() { + self.pageControl = UIPageControl(frame: CGRectMake(0,0,0,0)) + self.pageControl.backgroundColor = alertview.colorForAlertViewBackground + self.pageControl.pageIndicatorTintColor = alertview.colorPageIndicator + self.pageControl.currentPageIndicatorTintColor = alertview.colorCurrentPageIndicator + self.pageControl.numberOfPages = arrayOfImage.count + self.pageControl.currentPage = 0 + self.pageControl.enabled = false + + self.configureConstraintsForPageControl() + } + + private func configurePageViewController(){ + self.pageController = UIPageViewController(transitionStyle: UIPageViewControllerTransitionStyle.Scroll, navigationOrientation: UIPageViewControllerNavigationOrientation.Horizontal, options: nil) + self.pageController.view.backgroundColor = UIColor.clearColor() + self.pageController.dataSource = self + self.pageController.delegate = self + + let initialViewController = self.viewControllerAtIndex(arrayOfImage.count-1) + self.viewControllers = [initialViewController!] + self.pageController.setViewControllers(viewControllers, direction: .Forward, animated: false, completion: nil) + + self.addChildViewController(self.pageController) + } + + func configureConstraintsForPageControl() { + let alertViewSizeHeight = UIScreen.mainScreen().bounds.height*0.8 + let positionX = alertViewSizeHeight - (alertViewSizeHeight * 0.1) - 50 + self.pageControl.frame = CGRectMake(0, positionX, self.view.bounds.width, 50) + } +}