Changing height of a sidemenu - swift

This is my actual view
I want that the sidemenu begins at the first grey line and not on the top of the view. I would be glad if I could get an answer how i can set the height of it but i am also happy if someone could suggest me a workaround like hiding it behind the searchbar and segmented control. Thank you in advance.
This is my ENSideMenu.swift implementation
import UIKit
#objc public protocol ENSideMenuDelegate {
optional func sideMenuWillOpen()
optional func sideMenuWillClose()
optional func sideMenuDidOpen()
optional func sideMenuDidClose()
optional func sideMenuShouldOpenSideMenu () -> Bool
}
#objc public protocol ENSideMenuProtocol {
var sideMenu : ENSideMenu? { get }
func setContentViewController(contentViewController: UIViewController)
}
public enum ENSideMenuAnimation : Int {
case None
case Default
}
/**
The position of the side view on the screen.
- Left: Left side of the screen
- Right: Right side of the screen
*/
public enum ENSideMenuPosition : Int {
case Left
case Right
}
public extension UIViewController {
/**
Changes current state of side menu view.
*/
public func toggleSideMenuView () {
sideMenuController()?.sideMenu?.toggleMenu()
}
/**
Hides the side menu view.
*/
public func hideSideMenuView () {
sideMenuController()?.sideMenu?.hideSideMenu()
}
/**
Shows the side menu view.
*/
public func showSideMenuView () {
sideMenuController()?.sideMenu?.showSideMenu()
}
/**
Returns a Boolean value indicating whether the side menu is showed.
:returns: BOOL value
*/
public func isSideMenuOpen () -> Bool {
let sieMenuOpen = self.sideMenuController()?.sideMenu?.isMenuOpen
return sieMenuOpen!
}
/**
* You must call this method from viewDidLayoutSubviews in your content view controlers so it fixes size and position of the side menu when the screen
* rotates.
* A convenient way to do it might be creating a subclass of UIViewController that does precisely that and then subclassing your view controllers from it.
*/
func fixSideMenuSize() {
if let navController = self.navigationController as? ENSideMenuNavigationController {
navController.sideMenu?.updateFrame()
}
}
/**
Returns a view controller containing a side menu
:returns: A `UIViewController`responding to `ENSideMenuProtocol` protocol
*/
public func sideMenuController () -> ENSideMenuProtocol? {
var iteration : UIViewController? = self.parentViewController
if (iteration == nil) {
return topMostController()
}
repeat {
if (iteration is ENSideMenuProtocol) {
return iteration as? ENSideMenuProtocol
} else if (iteration?.parentViewController != nil && iteration?.parentViewController != iteration) {
iteration = iteration!.parentViewController
} else {
iteration = nil
}
} while (iteration != nil)
return iteration as? ENSideMenuProtocol
}
internal func topMostController () -> ENSideMenuProtocol? {
var topController : UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController
if (topController is UITabBarController) {
topController = (topController as! UITabBarController).selectedViewController
}
while (topController?.presentedViewController is ENSideMenuProtocol) {
topController = topController?.presentedViewController
}
return topController as? ENSideMenuProtocol
}
}
public class ENSideMenu : NSObject, UIGestureRecognizerDelegate {
/// The width of the side menu view. The default value is 160.
public var menuWidth : CGFloat = 90.0 {
didSet {
needUpdateApperance = true
updateFrame()
}
}
private var menuPosition:ENSideMenuPosition = .Right
private var blurStyle: UIBlurEffectStyle = .Light
/// A Boolean value indicating whether the bouncing effect is enabled. The default value is TRUE.
public var bouncingEnabled :Bool = true
/// The duration of the slide animation. Used only when `bouncingEnabled` is FALSE.
public var animationDuration = 0.25
private let sideMenuContainerView = UIView()
private(set) var menuViewController : UIViewController!
private var animator : UIDynamicAnimator!
private var sourceView : UIView!
private var needUpdateApperance : Bool = false
/// The delegate of the side menu
public weak var delegate : ENSideMenuDelegate?
private(set) var isMenuOpen : Bool = false
/// A Boolean value indicating whether the left swipe is enabled.
public var allowLeftSwipe : Bool = true
/// A Boolean value indicating whether the right swipe is enabled.
public var allowRightSwipe : Bool = true
public var allowPanGesture : Bool = true
private var panRecognizer : UIPanGestureRecognizer?
/**
Initializes an instance of a `ENSideMenu` object.
:param: sourceView The parent view of the side menu view.
:param: menuPosition The position of the side menu view.
:returns: An initialized `ENSideMenu` object, added to the specified view.
*/
public init(sourceView: UIView, menuPosition: ENSideMenuPosition, blurStyle: UIBlurEffectStyle = .Light) {
super.init()
self.sourceView = sourceView
self.menuPosition = menuPosition
self.blurStyle = blurStyle
self.setupMenuView()
animator = UIDynamicAnimator(referenceView:sourceView)
animator.delegate = self
self.panRecognizer = UIPanGestureRecognizer(target: self, action: "handlePan:")
panRecognizer!.delegate = self
sourceView.addGestureRecognizer(panRecognizer!)
// Add right swipe gesture recognizer
let rightSwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleGesture:")
rightSwipeGestureRecognizer.delegate = self
rightSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Right
// Add left swipe gesture recognizer
let leftSwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleGesture:")
leftSwipeGestureRecognizer.delegate = self
leftSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Left
if (menuPosition == .Left) {
sourceView.addGestureRecognizer(rightSwipeGestureRecognizer)
sideMenuContainerView.addGestureRecognizer(leftSwipeGestureRecognizer)
}
else {
sideMenuContainerView.addGestureRecognizer(rightSwipeGestureRecognizer)
sourceView.addGestureRecognizer(leftSwipeGestureRecognizer)
}
}
/**
Initializes an instance of a `ENSideMenu` object.
:param: sourceView The parent view of the side menu view.
:param: menuViewController A menu view controller object which will be placed in the side menu view.
:param: menuPosition The position of the side menu view.
:returns: An initialized `ENSideMenu` object, added to the specified view, containing the specified menu view controller.
*/
public convenience init(sourceView: UIView, menuViewController: UIViewController, menuPosition: ENSideMenuPosition, blurStyle: UIBlurEffectStyle = .Light) {
self.init(sourceView: sourceView, menuPosition: menuPosition, blurStyle: blurStyle)
self.menuViewController = menuViewController
self.menuViewController.view.frame = sideMenuContainerView.bounds
self.menuViewController.view.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
sideMenuContainerView.addSubview(self.menuViewController.view)
}
/*
public convenience init(sourceView: UIView, view: UIView, menuPosition: ENSideMenuPosition) {
self.init(sourceView: sourceView, menuPosition: menuPosition)
view.frame = sideMenuContainerView.bounds
view.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
sideMenuContainerView.addSubview(view)
}
*/
/**
Updates the frame of the side menu view.
*/
func updateFrame() {
var width:CGFloat
var height:CGFloat
(width, height) = adjustFrameDimensions( sourceView.frame.size.width, height: sourceView.frame.size.height)
let menuFrame = CGRectMake(
(menuPosition == .Left) ?
isMenuOpen ? 0 : -menuWidth-1.0 :
isMenuOpen ? width - menuWidth : width+1.0,
sourceView.frame.origin.y,
menuWidth,
height
)
sideMenuContainerView.frame = menuFrame
}
private func adjustFrameDimensions( width: CGFloat, height: CGFloat ) -> (CGFloat,CGFloat) {
if floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1 &&
(UIApplication.sharedApplication().statusBarOrientation == UIInterfaceOrientation.LandscapeRight ||
UIApplication.sharedApplication().statusBarOrientation == UIInterfaceOrientation.LandscapeLeft) {
// iOS 7.1 or lower and landscape mode -> interchange width and height
return (height, width)
}
else {
return (width, height)
}
}
private func setupMenuView() {
// Configure side menu container
updateFrame()
sideMenuContainerView.backgroundColor = UIColor.clearColor()
sideMenuContainerView.clipsToBounds = false
sideMenuContainerView.layer.masksToBounds = false
sideMenuContainerView.layer.shadowOffset = (menuPosition == .Left) ? CGSizeMake(1.0, 1.0) : CGSizeMake(-1.0, -1.0)
sideMenuContainerView.layer.shadowRadius = 1.25
sideMenuContainerView.layer.shadowOpacity = 0.125
sideMenuContainerView.layer.shadowPath = UIBezierPath(rect: sideMenuContainerView.bounds).CGPath
sourceView.addSubview(sideMenuContainerView)
if (NSClassFromString("UIVisualEffectView") != nil) {
// Add blur view
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: blurStyle)) as UIVisualEffectView
visualEffectView.frame = sideMenuContainerView.bounds
visualEffectView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
sideMenuContainerView.addSubview(visualEffectView)
}
else {
// TODO: add blur for ios 7
}
}
private func toggleMenu (shouldOpen: Bool) {
if (shouldOpen && delegate?.sideMenuShouldOpenSideMenu?() == false) {
return
}
updateSideMenuApperanceIfNeeded()
isMenuOpen = shouldOpen
var width:CGFloat
var height:CGFloat
(width, height) = adjustFrameDimensions( sourceView.frame.size.width, height: sourceView.frame.size.height)
if (bouncingEnabled) {
animator.removeAllBehaviors()
var gravityDirectionX: CGFloat
var pushMagnitude: CGFloat
var boundaryPointX: CGFloat
var boundaryPointY: CGFloat
if (menuPosition == .Left) {
// Left side menu
gravityDirectionX = (shouldOpen) ? 1 : -1
pushMagnitude = (shouldOpen) ? 20 : -20
boundaryPointX = (shouldOpen) ? menuWidth : -menuWidth-2
boundaryPointY = 20
}
else {
// Right side menu
gravityDirectionX = (shouldOpen) ? -1 : 1
pushMagnitude = (shouldOpen) ? -20 : 20
boundaryPointX = (shouldOpen) ? width-menuWidth : width+menuWidth+2
boundaryPointY = -20
}
let gravityBehavior = UIGravityBehavior(items: [sideMenuContainerView])
gravityBehavior.gravityDirection = CGVectorMake(gravityDirectionX, 0)
animator.addBehavior(gravityBehavior)
let collisionBehavior = UICollisionBehavior(items: [sideMenuContainerView])
collisionBehavior.addBoundaryWithIdentifier("menuBoundary", fromPoint: CGPointMake(boundaryPointX, boundaryPointY),
toPoint: CGPointMake(boundaryPointX, height))
animator.addBehavior(collisionBehavior)
let pushBehavior = UIPushBehavior(items: [sideMenuContainerView], mode: UIPushBehaviorMode.Instantaneous)
pushBehavior.magnitude = pushMagnitude
animator.addBehavior(pushBehavior)
let menuViewBehavior = UIDynamicItemBehavior(items: [sideMenuContainerView])
menuViewBehavior.elasticity = 0.25
animator.addBehavior(menuViewBehavior)
}
else {
var destFrame :CGRect
if (menuPosition == .Left) {
destFrame = CGRectMake((shouldOpen) ? -2.0 : -menuWidth, 0, menuWidth, height)
}
else {
destFrame = CGRectMake((shouldOpen) ? width-menuWidth : width+2.0,
0,
menuWidth,
height)
}
UIView.animateWithDuration(
animationDuration,
animations: { () -> Void in
self.sideMenuContainerView.frame = destFrame
},
completion: { (Bool) -> Void in
if (self.isMenuOpen) {
self.delegate?.sideMenuDidOpen?()
} else {
self.delegate?.sideMenuDidClose?()
}
})
}
if (shouldOpen) {
delegate?.sideMenuWillOpen?()
} else {
delegate?.sideMenuWillClose?()
}
/*let outterView = UIView(frame: CGRectMake(sideMenuContainerView.frame.width, 0,
sourceView.frame.width - sideMenuContainerView.frame.width,
sourceView.frame.height))
outterView.backgroundColor = UIColor.clearColor()
let tapRecognizer = UITapGestureRecognizer(target: self, action: "hideSideMenu")
outterView.addGestureRecognizer(tapRecognizer)
outterView.userInteractionEnabled = false
sourceView.addSubview(outterView)
sourceView.layer.zPosition = 0
outterView.userInteractionEnabled = shouldOpen */
}
public func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UISwipeGestureRecognizer {
let swipeGestureRecognizer = gestureRecognizer as! UISwipeGestureRecognizer
if !self.allowLeftSwipe {
if swipeGestureRecognizer.direction == .Left {
return false
}
}
if !self.allowRightSwipe {
if swipeGestureRecognizer.direction == .Right {
return false
}
}
}
else if gestureRecognizer.isEqual(panRecognizer) {
if allowPanGesture == false {
return false
}
animator.removeAllBehaviors()
let touchPosition = gestureRecognizer.locationOfTouch(0, inView: sourceView)
if menuPosition == .Left {
if isMenuOpen {
if touchPosition.x < menuWidth {
return true
}
}
else {
if touchPosition.x < 25 {
return true
}
}
}
else {
if isMenuOpen {
if touchPosition.x > CGRectGetWidth(sourceView.frame) - menuWidth {
return true
}
}
else {
if touchPosition.x > CGRectGetWidth(sourceView.frame)-25 {
return true
}
}
}
return false
}
return true
}
internal func handleGesture(gesture: UISwipeGestureRecognizer) {
toggleMenu((self.menuPosition == .Right && gesture.direction == .Left)
|| (self.menuPosition == .Left && gesture.direction == .Right))
}
internal func handlePan(recognizer : UIPanGestureRecognizer){
let leftToRight = recognizer.velocityInView(recognizer.view).x > 0
switch recognizer.state {
case .Began:
break
case .Changed:
let translation = recognizer.translationInView(sourceView).x
let xPoint : CGFloat = sideMenuContainerView.center.x + translation + (menuPosition == .Left ? 1 : -1) * menuWidth / 2
if menuPosition == .Left {
if xPoint <= 0 || xPoint > CGRectGetWidth(self.sideMenuContainerView.frame) {
return
}
}else{
if xPoint <= sourceView.frame.size.width - menuWidth || xPoint >= sourceView.frame.size.width
{
return
}
}
sideMenuContainerView.center.x = sideMenuContainerView.center.x + translation
recognizer.setTranslation(CGPointZero, inView: sourceView)
default:
let shouldClose = menuPosition == .Left ? !leftToRight && CGRectGetMaxX(sideMenuContainerView.frame) < menuWidth : leftToRight && CGRectGetMinX(sideMenuContainerView.frame) > (sourceView.frame.size.width - menuWidth)
toggleMenu(!shouldClose)
}
}
private func updateSideMenuApperanceIfNeeded () {
if (needUpdateApperance) {
var frame = sideMenuContainerView.frame
frame.size.width = menuWidth
sideMenuContainerView.frame = frame
sideMenuContainerView.layer.shadowPath = UIBezierPath(rect: sideMenuContainerView.bounds).CGPath
needUpdateApperance = false
}
}
/**
Toggles the state of the side menu.
*/
public func toggleMenu () {
if (isMenuOpen) {
toggleMenu(false)
}
else {
updateSideMenuApperanceIfNeeded()
toggleMenu(true)
}
}
/**
Shows the side menu if the menu is hidden.
*/
public func showSideMenu () {
if (!isMenuOpen) {
toggleMenu(true)
}
}
/**
Hides the side menu if the menu is showed.
*/
public func hideSideMenu () {
if (isMenuOpen) {
toggleMenu(false)
}
}
}
extension ENSideMenu: UIDynamicAnimatorDelegate {
public func dynamicAnimatorDidPause(animator: UIDynamicAnimator) {
if (self.isMenuOpen) {
self.delegate?.sideMenuDidOpen?()
} else {
self.delegate?.sideMenuDidClose?()
}
}
public func dynamicAnimatorWillResume(animator: UIDynamicAnimator) {
print("resume")
}
}
This is my ENSideMenuNavigationController.swift
import UIKit
public class ENSideMenuNavigationController: UINavigationController, ENSideMenuProtocol {
public var sideMenu : ENSideMenu?
public var sideMenuAnimationType : ENSideMenuAnimation = .Default
// MARK: - Life cycle
public override func viewDidLoad() {
super.viewDidLoad()
}
public init( menuViewController: UIViewController, contentViewController: UIViewController?) {
super.init(nibName: nil, bundle: nil)
if (contentViewController != nil) {
self.viewControllers = [contentViewController!]
}
sideMenu = ENSideMenu(sourceView: self.view, menuViewController: menuViewController, menuPosition:.Right)
view.bringSubviewToFront(navigationBar)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
public override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
public func setContentViewController(contentViewController: UIViewController) {
self.sideMenu?.toggleMenu()
switch sideMenuAnimationType {
case .None:
self.viewControllers = [contentViewController]
break
default:
contentViewController.navigationItem.hidesBackButton = true
self.setViewControllers([contentViewController], animated: true)
break
}
}
}
This is my MyMenuTableViewController:
import UIKit
class MyMenuTableViewController: UITableViewController {
var selectedMenuItem : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Customize apperance of table view
tableView.contentInset = UIEdgeInsetsMake(116.0, 0, 0, 0) //
tableView.separatorStyle = .None
tableView.backgroundColor = UIColor.whiteColor()
tableView.scrollsToTop = false
tableView.allowsSelection = false
// Preserve selection between presentations
self.clearsSelectionOnViewWillAppear = false
tableView.selectRowAtIndexPath(NSIndexPath(forRow: selectedMenuItem, inSection: 0), animated: false, scrollPosition: .Middle)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CELL")
if (cell == nil) {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CELL")
cell!.backgroundColor = UIColor.clearColor()
cell!.textLabel?.textColor = UIColor.darkGrayColor()
let selectedBackgroundView = UIView(frame: CGRectMake(0, 0, cell!.frame.size.width, cell!.frame.size.height))
selectedBackgroundView.backgroundColor = UIColor.grayColor().colorWithAlphaComponent(0.2)
cell!.selectedBackgroundView = selectedBackgroundView
}
//cell!.textLabel?.text = "social Network #\(indexPath.row+1)"
cell!.imageView?.image = UIImage(named: "Facebook")
return cell!
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 45.0
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("did select row: \(indexPath.row)")
if (indexPath.row == selectedMenuItem) {
return
}
selectedMenuItem = indexPath.row
//Present new view controller
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main",bundle: nil)
var destViewController : UIViewController
switch (indexPath.row) {
case 0:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController1")
break
case 1:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController2")
break
case 2:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController3")
break
default:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController4")
break
}
sideMenuController()?.setContentViewController(destViewController)
}
}
This is my MyNavigationController.swift
import UIKit
class MyNavigationController: ENSideMenuNavigationController, ENSideMenuDelegate {
override func viewDidLoad() {
super.viewDidLoad()
sideMenu = ENSideMenu(sourceView: self.view, menuViewController: MyMenuTableViewController(), menuPosition:.Right)
//sideMenu?.delegate = self //optional
sideMenu?.menuWidth = 90.0 // optional, default is 160
// sideMenu?.bouncingEnabled = false
//sideMenu?.allowPanGesture = false
// make navigation bar showing over side menu
view.bringSubviewToFront(navigationBar)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - ENSideMenu Delegate
func sideMenuWillOpen() {
print("sideMenuWillOpen")
}
func sideMenuWillClose() {
print("sideMenuWillClose")
}
func sideMenuDidClose() {
print("sideMenuDidClose")
}
func sideMenuDidOpen() {
print("sideMenuDidOpen")
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

In your menu tableViewController you should implement
let MinHeight: CGFloat = 100.0
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let tHeight = tableView.bounds.height
let temp = tHeight/CGFloat(items.count) //Item size on your side menu
return temp > MinHeight ? temp : MinHeight
}

Related

How to change value of label from another UICollectionViewCell

What if the UILabel is in class A and the didTapRightutton that will animate it is in class B?
the percentDiscountLabel is in RandomizeDealsCollectionViewCell. This should animate into fade appear if I tap didTapRightutton which is in a different VC called RandomizeDealsViewController
How do I call the function that is inside RandomizeDealsCollectionViewCell to animate the percentDiscountLabel? Is there other way to do this?
class RandomizeDealsCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var percentDiscountLabel: UILabel!
func animatePercentDiscountLabel(deals: String) {
self.percentDiscountLabel.alpha = 0.6
self.percentDiscountLabel.isHidden = false
UIView.animate(withDuration: 0.6, delay: 0, options: .curveEaseInOut, animations: {
self.percentDiscountLabel.alpha = 1.0
}) { (isCompleted) in
}
percentDiscountLabel.text = deals
}
}
class RandomizeDealsViewController: UIViewController {
private var centeredCollectionViewFlowLayout: CenteredCollectionViewFlowLayout!
#IBAction func didTapRightButton(_ sender: Any) {
guard let indexCard = centeredCollectionViewFlowLayout.currentCenteredPage else { return }
if (indexCard > 0) {
centeredCollectionViewFlowLayout.scrollToPage(index: indexCard + 1, animated: true)
// should call the animation function here
}
}
}
If indexCard is indexPath of collectionViewCell which you want to animate,
You can call your cell like ->
in RandomizeDealsViewController
#IBAction func didTapRightButton(_ sender: Any) {
guard let indexCard = centeredCollectionViewFlowLayout.currentCenteredPage else { return }
if (indexCard > 0) {
centeredCollectionViewFlowLayout.scrollToPage(index: indexCard + 1, animated: true)
// should call the animation function here
let cell = collectionView!.cellForItemAtIndexPath(indexCard) as? RandomizeDealsCollectionViewCell
cell?.animatePercentDiscountLabel(deals: "deals")
}
}

NScrollView in NSPopover autolayout issue

I have an NSPopover which contains an NSViewController with a containing NSScrollView.
The Popover height has to be either the height of the NSScrollView content or the current window. Once it hits the bounds of the window it should scroll.
Using Snapkit
I have added the NSScrollView to the controller:
view.addSubview(scrollView)
scrollView.snp.makeConstraints { (make) in
make.edges.equalTo(view)
make.height.equalTo(mainView.content.snp.height)
}
This works fine until the content is greater than the window, then what happens is the NSScrollView will not scroll to the top of the content because the view has pushed itself upwards out of bounds.
I have gone down the route of removing the height constraint and in the viewDidLayout try to update the height but it doesn't work.
If more code examples are needed let me know.
Finally got to the bottom of the issue and found a sensible solution.
The app I am developing has a few popovers that are required at various stages, to ensure that they closed as required I created a service that manages every popover, here is an example:
class PopoverService: NSObject {
enum PopoverType {
case subscription, edit
}
//================================================================================
// MARK: - Properties
//================================================================================
private var dismissingPopover = false
private lazy var currentPopover: NSPopover = {
let popover = NSPopover()
popover.delegate = self
return popover
}()
private var nextPopoverType: PopoverType?
private var currentView: NSView!
public static var delegate: PopoverServiceDelegate?
//================================================================================
// MARK: - Singleton
//================================================================================
static let shared = PopoverService()
//================================================================================
// MARK: - Helpers
//================================================================================
public static func increaseHeight(_ height: CGFloat) {
shared.currentPopover.contentSize.height = height
}
public static func isDisplayingType(_ type: PopoverType) -> Bool {
switch type {
case .edit:
return shared.currentPopover.contentViewController is EditEntryController
case .language:
return shared.currentPopover.contentViewController is CodeTypeController
default:
return false
}
}
public static func displayPopover(type: PopoverType, fromView view: NSView) {
shared.nextPopoverType = type
shared.currentView = view
switch type {
case .subscription:
displaySubscriptionPopoverFrom(view)
// Create functions to display your popovers
}
}
static func dismissPopover(clearUpcoming: Bool = true) {
if clearUpcoming {
shared.nextPopoverType = nil
}
shared.currentPopover.performClose(nil)
if shared.currentPopover.contentViewController == nil {
shared.dismissingPopover = false; return
}
}
}
extension PopoverService: NSPopoverDelegate {
func popoverDidClose(_ notification: Notification) {
currentPopover.contentViewController = nil
dismissingPopover = false
guard let nextPopoverType = nextPopoverType else { return }
PopoverService.displayPopover(
type: nextPopoverType,
fromView: currentView,
entry: currentEntry
)
}
}
To update the current popover, there is a function increaseHeight which takes and CGFloat and will update the current popovers height.
In the NSViewController override the viewDidLayout():
override func viewDidLayout() {
super.viewDidLayout()
let windowFrameHeight = view.window?.frame.size.height ?? 0
let contentHeight = scrollView.content.frame.height
let adjustment = contentHeight > windowFrameHeight ? windowFrameHeight : contentHeight
PopoverService.increaseHeight(adjustment)
if contentHeight > 0 && firstLayout {
if let documentView = scrollView.documentView {
documentView.scroll(NSPoint(x: 0, y: documentView.bounds.size.height))
}
}
}
The scrollView will need to be forced to the top so there is a variable firstLayout which you can set to true in the viewDidAppear

How to make Images clickable in a UIPageViewController?

I am creating a UIPageController which swipes 4 pages. In each page there is an image from the array I created. Now I want to make each image from the swipe view clickable to present a new specific page. Each image from the swipe view leads to a different 10 levels (buttons) page.
the project file is here:
http://s000.tinyupload.com/?file_id=90198426971136689376
This is my code in ViewController:
private var pageViewController: UIPageViewController?
private let contentImages = ["Pack_1.png",
"Pack_2.png",
"Pack_3.png",
"nature_pic_4.png"];
override func viewDidLoad() {
super.viewDidLoad()
createPageViewController()
setupPageControl()
}
private func createPageViewController() {
let pageController = self.storyboard!.instantiateViewControllerWithIdentifier("PageController") as! UIPageViewController
pageController.dataSource = self
if contentImages.count > 0 {
let firstController = getItemController(0)!
let startingViewControllers: NSArray = [firstController]
pageController.setViewControllers(startingViewControllers as? [UIViewController], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
pageViewController = pageController
addChildViewController(pageViewController!)
self.view.addSubview(pageViewController!.view)
pageViewController!.didMoveToParentViewController(self)
}
private func setupPageControl() {
let appearance = UIPageControl.appearance()
appearance.pageIndicatorTintColor = UIColor.grayColor()
appearance.currentPageIndicatorTintColor = UIColor.whiteColor()
appearance.backgroundColor = UIColor.darkGrayColor()
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let itemController = viewController as! PageItemController
if itemController.itemIndex > 0 {
return getItemController(itemController.itemIndex-1)
}
return nil
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let itemController = viewController as! PageItemController
if itemController.itemIndex+1 < contentImages.count {
return getItemController(itemController.itemIndex+1)
}
return nil
}
private func getItemController(itemIndex: Int) -> PageItemController? {
if itemIndex < contentImages.count {
let pageItemController = self.storyboard!.instantiateViewControllerWithIdentifier("ItemController") as! PageItemController
pageItemController.itemIndex = itemIndex
pageItemController.imageName = contentImages[itemIndex]
return pageItemController
}
return nil
}
}
and this code is in my pageItemController:
var itemIndex: Int = 0
var imageName: String = "" {
didSet {
if let imageView = contentImageView {
imageView.image = UIImage(named: imageName)
}
}
}
#IBOutlet var contentImageView: UIImageView?
override func viewDidLoad() {
super.viewDidLoad()
contentImageView!.image = UIImage(named: imageName)
self.view.backgroundColor = UIColor (red: 100, green: 100, blue: 100, alpha: 0)
}
}
As per this version of the quesion:
"I'm creating a UIPageControllerView that shows 4 images. is there any way to make this images clickable? each image should present a dedicate page. this is my code in viewController:"
SOLUTION:
Use UIGestureRecognizer.
1) Click on your Main.Storyboard.
2) Select UIGestureRecognizer.
3) Drag it on your Image of choice.
3.5) Use Cmd+Alt+Enter to open the Assistant Editor
4) Create an IBAction by Ctrl-dragging from your UITapGestureRecogniser to the Assistant Editor.
5) Put this code in your ViewController.
class ViewController {
let itemIndex: Int!
func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
{
if (!completed)
{
return
}
self.pageControl.currentPageIndex = pageViewController.viewControllers!.first!.view.tag //Page Index
self.itemIndex = self.pageControl.currentPageIndex
}
#IBAction func presentDedicatedPage(sender: UIImageView) {
//pseudo-code here, for example:
switch self.itemIndex {
case 0:
// present these 10 levels
break
case 1:
//present these other 10 levels
break
case 2:
//present these other 10 levels
break
case 3:
//present these other 10 levels
break
}
}
On your ItemPageController:
var itemIndex:Int?
var imageName:String?
Add UITapGesture To ImageView.
override func viewDidLoad() {
super.viewDidLoad()
let tapGestureRecognizer = UITapGestureRecognizer(target:self, action:Selector("imageTapped:"))
targetImageView.userInteractionEnabled = true
targetImageView.addGestureRecognizer(tapGestureRecognizer)
targetImageView.image = UIImage(named: imageName!)
}
On its triggered method:
func imageTapped(img: AnyObject)
{
print(imageName)
print(itemIndex)
//Using a switch statement
let targetImageIndex = itemIndex! as Int
switch (targetImageIndex) {
case 0:
print("case 0")
break;
case 1:
print("case 1")
break;
case 2:
print("case 2")
break;
default:
break;
}
}

Swift2: TKSubmitTransitionButton. How do i stop a button from transition/ animating when user login/ signup are incorrect

I have tried a number of times and the best i get is there would be an animation which never cancels or stop regardless of the command i use.
After following #Mattias example, i updated my code and looks something like this:
// DESIGN ANIMATION... TKTRANSITIONSUBMITBUTTON
#IBOutlet weak var btnFromNib: TKTransitionSubmitButton!
#IBAction func onTapButton(sender: AnyObject) {
btnFromNib.startLoadingAnimation()
if let email = self.emailField.text where email != "", let password = self.passwordField.text where password != "" {
DataService.ds.REF_BASE.authUser(email, password: password, withCompletionBlock: { error, authData in
if error != nil {
self.btnFromNib.returnToOriginalState()
if error.code == STATUS_ACCOUNT_NONEXIST {
self.showErrorAlert("This User does not exist", msg: "Please Sign Up")
} else {
}
} else {
self.btnFromNib.startFinishAnimation(1, completion: {
let myTabbarController = self.storyboard?.instantiateViewControllerWithIdentifier("myTabbarController") as! UITabBarController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = myTabbarController
myTabbarController.transitioningDelegate = self
})
}
})
}
}
The button yet keeps spinning / animating without stopping. After checking the custom animation class the function inherits from :
public func startLoadingAnimation() {
self.cachedTitle = titleForState(.Normal)
self.setTitle("", forState: .Normal)
self.shrink()
NSTimer.schedule(delay: shrinkDuration - 0.25) { timer in
self.spiner.animation()
}
}
public func startFinishAnimation(delay: NSTimeInterval, completion:(()->())?) {
NSTimer.schedule(delay: delay) { timer in
self.didEndFinishAnimation = completion
self.expand()
self.spiner.stopAnimation()
}
}
public func animate(duration: NSTimeInterval, completion:(()->())?) {
startLoadingAnimation()
startFinishAnimation(duration, completion: completion)
}
public override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
let a = anim as! CABasicAnimation
if a.keyPath == "transform.scale" {
didEndFinishAnimation?()
NSTimer.schedule(delay: 1) { timer in
self.returnToOriginalState()
}
}
}
func returnToOriginalState() {
self.layer.removeAllAnimations()
self.setTitle(self.cachedTitle, forState: .Normal)
}
I noticed it had a public overide func animationDidStop(anim: CAAnimation, finished: Bool) to be the function to stop the animation. But when i use it, i get this error!
How do i rightfully get this to work? ...
Thanks in Advance
** UPDATED QUESTION **
I checked the code of TKTransitionSubmitButton and there are public methods called startLoadingAnimation(), returnToOriginalState() and startFinishAnimation().
I suggest:
Button tapped
startLoadingAnimation()
Check credentials
If wrong/error: returnToOriginalState()
If correct: startFinishAnimation()
Transition, from TKTransitionSubmitButton documentation:
btn.startFinishAnimation {
//Your Transition
let secondVC = SecondViewController()
secondVC.transitioningDelegate = self
self.presentViewController(secondVC, animated: true, completion: nil)
}
Edit: As far as I can see .animate() of the class calls both the start and finish animation, and that's why you can't cancel it.
EDIT2 This one works as intended for me (however I'm not sure about the static cornerRadius)
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var submitButton: TKTransitionSubmitButton!
override func viewDidLoad() {
super.viewDidLoad()
submitButton.layer.cornerRadius = 15
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonPressed(sender: AnyObject) {
submitButton.startLoadingAnimation()
delay(2, closure: {
self.checkCredentials()
})
}
func checkCredentials()
{
//FAKING WRONG CREDENTIALS
let userAndPasswordCorrect = false
if !userAndPasswordCorrect
{
submitButton.returnToOriginalState()
//Alert or whatever
}
}
//Faking network delay
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
}
I checked the code of TKTransitionSubmitButton.
I resolve this issue. please try to stop animation under DispatchQueue.main.async and working well.
'func apicallforLogin() {
let urlString = "http://"
guard let requestUrl = URL(string:urlString) else { return }
let request = URLRequest(url:requestUrl)
let task = URLSession.shared.dataTask(with: request) {
(data, response, error) in
if error == nil,let usableData = data {
DispatchQueue.main.async {
self.btnLogin.startFinishAnimation(0.1, completion: {
let HomeVC = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
HomeVC.transitioningDelegate = self
self.navigationController?.pushViewController(HomeVC, animated: false)
})
}
print(usableData)
}else{
DispatchQueue.main.async {
self.btnLogin.returnToOriginalState()
}
}
}
task.resume()'
Well you might have got the answer by now but just I would like to give my answer. You can just copy below code and everything will work fine. I have made the change and had created the pull request for this issue.
import Foundation
import UIKit
#IBDesignable
open class TKTransitionSubmitButton : UIButton, UIViewControllerTransitioningDelegate, CAAnimationDelegate {
lazy var spiner: SpinerLayer! = {
let s = SpinerLayer(frame: self.frame)
return s
}()
#IBInspectable open var spinnerColor: UIColor = UIColor.white {
didSet {
spiner.spinnerColor = spinnerColor
}
}
open var didEndFinishAnimation : (()->())? = nil
let springGoEase = CAMediaTimingFunction(controlPoints: 0.45, -0.36, 0.44, 0.92)
let shrinkCurve = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
let expandCurve = CAMediaTimingFunction(controlPoints: 0.95, 0.02, 1, 0.05)
let shrinkDuration: CFTimeInterval = 0.1
#IBInspectable open var normalCornerRadius:CGFloat = 0.0 {
didSet {
self.layer.cornerRadius = normalCornerRadius
}
}
var cachedTitle: String?
var isAnimating = false
public override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
public required init!(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.setup()
}
func setup() {
self.clipsToBounds = true
spiner.spinnerColor = spinnerColor
}
open func startLoadingAnimation() {
self.isAnimating = true
self.cachedTitle = title(for: UIControlState())
self.setTitle("", for: UIControlState())
self.layer.addSublayer(spiner)
// Animate
self.cornerRadius()
self.shrink()
_ = Timer.schedule(delay: self.shrinkDuration - 0.25) { timer in
self.spiner.animation()
}
}
open func startFinishAnimation(_ delay: TimeInterval,_ animation: CAMediaTimingFunction, completion:(()->())?) {
self.isAnimating = true
_ = Timer.schedule(delay: delay) { timer in
self.didEndFinishAnimation = completion
self.expand(animation)
self.spiner.stopAnimation()
}
}
open func animate(_ duration: TimeInterval,_ animation: CAMediaTimingFunction, completion:(()->())?) {
startLoadingAnimation()
startFinishAnimation(duration, animation, completion: completion)
}
open func setOriginalState() {
self.returnToOriginalState()
self.spiner.stopAnimation()
}
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
let a = anim as! CABasicAnimation
if a.keyPath == "transform.scale" {
didEndFinishAnimation?()
_ = Timer.schedule(delay: 1) { timer in
self.returnToOriginalState()
}
}
}
open func returnToOriginalState() {
self.spiner.removeFromSuperlayer()
self.layer.removeAllAnimations()
self.setTitle(self.cachedTitle, for: UIControlState())
self.spiner.stopAnimation()
self.isAnimating = false
}
func cornerRadius() {
let cornerRadiusAnim = CABasicAnimation(keyPath: "cornerRadius")
// cornerRadiusAnim.fromValue = frame.width
cornerRadiusAnim.toValue = frame.height/2
cornerRadiusAnim.duration = shrinkDuration
cornerRadiusAnim.timingFunction = shrinkCurve
cornerRadiusAnim.fillMode = kCAFillModeForwards
cornerRadiusAnim.isRemovedOnCompletion = false
layer.add(cornerRadiusAnim, forKey: cornerRadiusAnim.keyPath)
}
func shrink() {
let shrinkAnim = CABasicAnimation(keyPath: "bounds.size.width")
shrinkAnim.beginTime = CACurrentMediaTime() + 0.1
shrinkAnim.fromValue = frame.width
shrinkAnim.toValue = frame.height
shrinkAnim.duration = shrinkDuration
shrinkAnim.timingFunction = shrinkCurve
shrinkAnim.fillMode = kCAFillModeForwards
shrinkAnim.isRemovedOnCompletion = false
layer.add(shrinkAnim, forKey: shrinkAnim.keyPath)
}
func expand(_ animation: CAMediaTimingFunction) {
let expandAnim = CABasicAnimation(keyPath: "transform.scale")
expandAnim.fromValue = 1.0
expandAnim.toValue = 26.0
expandAnim.timingFunction = animation
expandAnim.duration = 0.3
expandAnim.delegate = self
expandAnim.fillMode = kCAFillModeForwards
expandAnim.isRemovedOnCompletion = false
layer.add(expandAnim, forKey: expandAnim.keyPath)
}
}

my VC has no initializers

When I had XCode 6.1 everything worked well. After having XCOde 6.3 I am having problem with delegate methods.
Before:
protocol MainPageLoaderViewControllerDelegate{
func changeCategoryOfSingelTopicViewController(category: Int!)
}
class MainPageLoaderViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIGestureRecognizerDelegate {
var delegate: MainPageLoaderViewControllerDelegate?
var categoryOfSingleTopic: Int! = 0 {
didSet{
delegate?.changeCategoryOfSingelTopicViewController(categoryOfSingleTopic!)
}
}
}
Now, Complier gives me error saying that MainPageLoaderViewController has no initializers. How should I declare delegate var?
The all code:
import UIKit
protocol MainPageLoaderViewControllerDelegate{
func changeCategoryOfSingelTopicViewController(category: Int!)
}
class MainPageLoaderViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIGestureRecognizerDelegate {
var delegate: MainPageLoaderViewControllerDelegate?
var categoryOfSingleTopic: Int! = 0{
didSet{
// put to the right column on pageviewcontroller
movePageContentToViewControllerAtIndex(1)
println("here is single topic \(categoryOfSingleTopic)")
delegate?.changeCategoryOfSingelTopicViewController(categoryOfSingleTopic!)
changeADVControleItemsName(categoryOfSingleTopic)
}
}
let gestureRecognizerOfMainPageController: UIPanGestureRecognizer!
#IBOutlet var scrollContentView: UIView!
#IBOutlet var segmentControl: ADVSegmentedControl!
let transtionManger = TransitionManger()
var pageIndexTest: Int!
#IBOutlet var scrollView: UIScrollView!
var mainPageViewController : UIPageViewController!
var tableViewControllers = [UITableViewController]()
var newsLenta: UITableViewController!
var mainPage: SingleTopicTableViewController!
var onlinetranslation: UITableViewController!
var identifiers:NSArray = ["MainPageContentViewController", "MainPageTableViewController", "SingleTopicTableViewController"]
var pageContentViewController: UITableViewController!
override func viewDidLoad() {
super.viewDidLoad()
// self.scrollView.scrollEnabled = false
self.transtionManger.sourceViewController = self
CommonFunctions.setBackgroundImageToNavBar(self.navigationItem)
println("view did load of page controller loaded")
segmentControl.thumbColor = Design.setColorGrey20()
createArrayOfControllers()
resetToMainPage(1)
segmentControl.items = ["Лента", "Главная", "Онлайн"]
segmentControl.font = UIFont(name: "Avenir-Black", size: 12)
segmentControl.borderColor = UIColor(white: 1.0, alpha: 0.3)
segmentControl.selectedIndex = 1
segmentControl.selectedLabelColor = UIColor.whiteColor()
setGestureRecognizerToTableView()
self.transtionManger.segmentToSetInteraction = segmentControl
scrollContentView.addGestureRecognizer(transtionManger.exitPanGesture)
segmentControl.addTarget(self, action: "selectPageIndexBySegmentControl", forControlEvents: UIControlEvents.ValueChanged)
}
func changeADVControleItemsName(category:Int){
switch category{
case 0: segmentControl.items[1] = "Главная" // main
case 100: segmentControl.items[1] = "Избранные" // saved
case 1: segmentControl.items[1] = "Экономика" // economy
case 2: segmentControl.items[1] = "Политика" // politics
case 4: segmentControl.items[1] = "Общество" // community
case 5: segmentControl.items[1] = "Спорт" // sport
case 6: segmentControl.items[1] = "Культура" // culture
case 8: segmentControl.items[1] = "Проишествия" // events
case 10: segmentControl.items[1] = "Авто" // auto
case 11: segmentControl.items[1] = "Фото" // photo
case 12: segmentControl.items[1] = "Видео" // video
default: break
}
}
func changeCategoryOfSingelTopicViewController(category: Int!){
}
func setGestureRecognizerToTableView(){
self.transtionManger.tableViewFromSourceView = self.viewControllerAtIndex(segmentControl.selectedIndex) // we do it in order to disable table view until the menu is opened
}
func movePageContentToViewControllerAtIndex(index: Int){
switch index {
case 0:
println("zero index were selected")
pageContentViewController = self.viewControllerAtIndex(index)
mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward , animated: true, completion: nil)
setGestureRecognizerToTableView()
setExitPaGestureAtViewControllerWithIndex(segmentControl.selectedIndex)
// segmentControl.selectedIndex = index
case 1:
println("first element were selected")
pageContentViewController = self.viewControllerAtIndex(index)
mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
setGestureRecognizerToTableView()
setExitPaGestureAtViewControllerWithIndex(segmentControl.selectedIndex)
segmentControl.selectedIndex = index
case 2:
println("second element were selected")
pageContentViewController = self.viewControllerAtIndex(index)
mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
setGestureRecognizerToTableView()
setExitPaGestureAtViewControllerWithIndex(segmentControl.selectedIndex)
default: break
}
}
func selectPageIndexBySegmentControl(){
switch segmentControl.selectedIndex {
case 0:
movePageContentToViewControllerAtIndex(0)
case 1:
movePageContentToViewControllerAtIndex(1)
case 2:
movePageContentToViewControllerAtIndex(2)
default:
break
}
}
#IBAction func showOrCloseMenu(sender: AnyObject) {
if transtionManger.isMenuVisible == true {
println("it is true")
transtionManger.isMenuVisible = false
transtionManger.menuViewController.performSegueWithIdentifier("dismisMenu", sender: nil)
}
else{
println("it is false")
performSegueWithIdentifier("showMenu", sender: nil)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let menu = segue.destinationViewController as! SideBarMenuTableViewController
if transtionManger.isMenuVisible == true {
transtionManger.presentingP = false
}
menu.transitioningDelegate = self.transtionManger
// add in order to set menuviewcontroller in transformerManager
self.transtionManger.menuViewController = menu
}
#IBAction func unwindSegueToMainScreen(segue:UIStoryboardSegue) {
// bug? exit segue doesn't dismiss so we do it manually...
self.dismissViewControllerAnimated(true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func createArrayOfControllers(){
newsLenta = self.storyboard?.instantiateViewControllerWithIdentifier("NewsLentaTableViewController")as! NewsLentaTableViewController
mainPage = self.storyboard?.instantiateViewControllerWithIdentifier("SingleTopicTableViewController") as! SingleTopicTableViewController
self.delegate = mainPage
onlinetranslation = self.storyboard?.instantiateViewControllerWithIdentifier("MainPageTableViewController") as! MainPageTableViewController
tableViewControllers = [newsLenta, mainPage, onlinetranslation]
}
func resetToMainPage(index: Int!) {
/* Getting the page View controller */
mainPageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("MainPageViewController") as! UIPageViewController
self.mainPageViewController.dataSource = self
self.mainPageViewController.delegate = self
pageContentViewController = self.viewControllerAtIndex(index)
// pageContentViewController.view.addGestureRecognizer(transtionManger.exitPanGesture3)
// self.transtionManger.sourceViewController = pageContentViewController // adding swipe to the pageContentViewControlle in order to close menu
//self.transtionManger.sourceViewController = mainPageViewController
self.mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
self.mainPageViewController.view.frame = CGRectMake(0, 102, self.view.frame.width, self.view.frame.height)
self.addChildViewController(mainPageViewController)
self.view.addSubview(mainPageViewController.view)
self.mainPageViewController.didMoveToParentViewController(self)
}
func viewControllerAtIndex(index : Int) -> UITableViewController? {
if index > 2 || index < 0 {
return nil
}
return tableViewControllers[index]
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
var index:Int!
if viewController.isKindOfClass(NewsLentaTableViewController) {
index = (viewController as! NewsLentaTableViewController).pageIndex
}else if viewController.isKindOfClass(MainPageTableViewController) {
index = (viewController as! MainPageTableViewController).pageIndex
}else if viewController.isKindOfClass(SingleTopicTableViewController) {
index = (viewController as! SingleTopicTableViewController).pageIndex
}else {return nil}
if index == 2 {
return nil
}
index = index + 1
return self.viewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
var index:Int!
if viewController.isKindOfClass(NewsLentaTableViewController) {
index = (viewController as! NewsLentaTableViewController).pageIndex
}else if viewController.isKindOfClass(MainPageTableViewController) {
index = (viewController as! MainPageTableViewController).pageIndex
}else if viewController.isKindOfClass(SingleTopicTableViewController) {
index = (viewController as! SingleTopicTableViewController).pageIndex
}else {return nil}
if index == 0 {
return nil
}
index = index - 1
return self.viewControllerAtIndex(index)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int
{
return 2
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int
{
return thePageIndex
}
func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [AnyObject], transitionCompleted completed: Bool) {
if completed && finished {
var index = previousViewControllers.startIndex
segmentControl.selectedIndex = thePageIndex
// add exit3 gesture recognizer to the current index
setExitPaGestureAtViewControllerWithIndex(segmentControl.selectedIndex)
setGestureRecognizerToTableView()
//selectedLabelFrame
//setContentOffSetOfUIScrollView()
}
}
override func viewDidAppear(animated: Bool) {
//setContentOffSetOfUIScrollView() // in the first load of view you need to set segment scroll
setExitPaGestureAtViewControllerWithIndex(segmentControl.selectedIndex)
}
func setExitPaGestureAtViewControllerWithIndex(index: Int!){
self.viewControllerAtIndex(index)?.tableView.addGestureRecognizer(transtionManger.exitPanGesture3)
}
func setContentOffSetOfUIScrollView(){
println(segmentControl.items.count - 1)
if thePageIndex == 0 {
scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
return
}else if thePageIndex == segmentControl.items.count - 1{
if selectedLabelFrame.frame.origin.x + selectedLabelFrame.frame.width > self.view.frame.width {
var sum = selectedLabelFrame.frame.origin.x + selectedLabelFrame.frame.width
var scroll = sum - self.view.frame.width
scrollView.setContentOffset(CGPointMake(scroll, 0), animated: true)
return
}else {
var sum = selectedLabelFrame.frame.origin.x + selectedLabelFrame.frame.width
var scroll = self.view.frame.width - sum
scrollView.setContentOffset(CGPointMake(scroll, 0), animated: true)
return
}
}
if selectedLabelFrame.frame.origin.x + selectedLabelFrame.frame.width > self.view.frame.width / 2 {
println(selectedLabelFrame.frame.origin.x)
println(selectedLabelFrame.frame.width)
println(self.view.frame.width)
println("more")
if thePageIndex == 1 {
var averageWidth = selectedLabelFrame.frame.width/2
var sum = selectedLabelFrame.frame.origin.x + averageWidth
var scroll = sum - self.view.frame.width/2
println("scroll is \(scroll)")
scrollView.setContentOffset(CGPointMake(scroll, 0), animated: true)
}
}else{
println(selectedLabelFrame.frame.origin.x)
println(selectedLabelFrame.frame.width)
println(self.view.frame.width)
println("less")
if thePageIndex == 1 {
var averageWidth = selectedLabelFrame.frame.width/2
var sum = selectedLabelFrame.frame.origin.x + averageWidth
var scroll = self.view.frame.width/2 - sum
println("scroll is \(scroll)")
scrollView.setContentOffset(CGPointMake(scroll, 0), animated: true)
}
}
}
}
In Swift, all instance variables have to be initialized at init (see the documentation) . Before you added the delegate, your superview's initializer was being called (because you hadn't overridden it) and you hadn't added any new instance variables, so this was fine. Now, however, your superview's implementation is being called but it is not initializing your variable, which is a compiler error.
Two options:
1) just initialize in your declaration: var delegate: MainPageLoaderViewControllerDelegate? = nil
2) override init and initialize your variable there.
I solved the problem but still dont understand how it is related to the problem "VC has not initilizers"
I changed the code:
var gestureRecognizerOfMainPageController: UIPanGestureRecognizer!
to
var gestureRecognizerOfMainPageController: UIPanGestureRecognizer?
You need to have a setter method for your variable
var delegate: MainPageLoaderViewControllerDelegate? {
didSet {
// Do whatever changes you wish to do
}
}
or have an init which instantiates the variable with an initial value, or initialize the variable with a value where you declare it.