Ramotion / animated-tab-bar

:octocat: RAMAnimatedTabBarController is a Swift UI module library for adding animation to iOS tabbar items and icons. iOS library made by @Ramotion
https://www.ramotion.com/animated-tab-bar-ios-app-development-ui-library/
MIT License
11.12k stars 1.33k forks source link

How to use this pod in an Obj-C project? #90

Closed foffux closed 7 years ago

foffux commented 8 years ago

Hello I need help to use this pod in an Obj-C project. I used CocoaPods to import it and it was fine. Then I was able to import RAMAnimatedTabBarController as a module simply typing

@import RAMAnimatedTabBarController;

But instead I was not able to import RAMBounceAnimation, for example. I want to use this pod by a Programatic approach, not Storyboard nor Nib. Can you help me with this? If you need some more information, please ask. Thanks a lot.

foffux commented 8 years ago

Hello This is my solution

RAMBounceAnimation *tabAnimation = [[RAMBounceAnimation alloc] init];
    tabAnimation.textSelectedColor = [UIColor redColor];
    tabAnimation.iconSelectedColor = [UIColor greenColor];

    RAMAnimatedTabBarItem *tabBarItem = [[RAMAnimatedTabBarItem alloc] initWithTitle:@"Example1" image:[UIImage imageNamed:@"Example1_OFF.png"] selectedImage:[UIImage imageNamed:@"Example1_ON.png"]];
    tabBarItem.textColor = [UIColor blackColor];
    tabBarItem.iconColor = [UIColor greenColor];
    tabBarItem.animation = tabAnimation;

    RMAMainViewController *exampleViewController = [[RMAMainViewController alloc] init];
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:exampleViewController];
    navigationController.tabBarItem = tabBarItem;
    navigationController.navigationBar.hidden = YES;

    RAMAnimatedTabBarController *mainTabBarController = [[RAMAnimatedTabBarController alloc] init];
    mainTabBarController.viewControllers = @[navigationController];

    self.window.rootViewController = mainTabBarController;

but it crashes here:

fatalError("add items in tabBar")

Any suggestion? Thank you.

muhasturk commented 8 years ago

Why do you insistence not use Swift in your project? It is future.

rafiki270 commented 8 years ago

@muhasturk that's not really an answer to the original question is it? I am getting the same error when doing this in swift programatically.

rafiki270 commented 8 years ago

+1 though!

ignasibm commented 7 years ago

@foffux did you solve the issue? I'm running into the same problem

foffux commented 7 years ago

Hello @ignasibm Yes I did. Here you are y solution (this is my AppDelegate class where I call RAMAnimatedTabBarController):

- (RMAInfoViewController *)configureMainViewController {

    //Main TabBar: allocation (need to be done as first thing)
    mainTabBarController = [[RAMAnimatedTabBarController alloc] init];
    CGSize tabBarSize = [[mainTabBarController tabBar] frame].size;

    //Animation
    RAMBounceAnimation *tabAnimation = [[RAMBounceAnimation alloc] init];
    tabAnimation.textSelectedColor = UIColorFromRGB(kTabBarItemInfoTextSelectedColor);
    tabAnimation.iconSelectedColor = UIColorFromRGB(kTabBarItemInfoIconSelectedColor);

    //Items
    NSString *tabBarItemInfoTitle = NSLocalizedString(@"Info", nil);
    RAMAnimatedTabBarItem *tabBarItemInfo = [[RAMAnimatedTabBarItem alloc] initWithTitle:[tabBarItemInfoTitle uppercaseString] image:[UIImage imageNamed:@"InfoTabBar.png"] tag:kInfoId];
    tabBarItemInfo.yOffSet = kTabBarItemYOffset;
    tabBarItemInfo.textColor = UIColorFromRGB(kTabBarItemInfoTextColor);
    tabBarItemInfo.iconColor = UIColorFromRGB(kTabBarItemInfoIconColor);
    tabBarItemInfo.textFont = [UIFont fontWithName:@"Oswald-Regular" size:kTabBarItemTextSize];
    tabBarItemInfo.animation = tabAnimation;

    NSString *tabBarItemScanTitle = NSLocalizedString(@"Scan", nil);
    RAMAnimatedTabBarItem *tabBarItemScan = [[RAMAnimatedTabBarItem alloc] initWithTitle:[tabBarItemScanTitle uppercaseString] image:[UIImage imageNamed:@"ScanTabBar.png"] tag:kScanId];
    tabBarItemScan.yOffSet = kTabBarItemYOffset;
    tabBarItemScan.textColor = UIColorFromRGB(kTabBarItemInfoTextColor);
    tabBarItemScan.iconColor = UIColorFromRGB(kTabBarItemInfoIconColor);
    tabBarItemScan.textFont = [UIFont fontWithName:@"Oswald-Regular" size:kTabBarItemTextSize];
    tabBarItemScan.animation = tabAnimation;

    NSString *tabBarItemToolsTitle = NSLocalizedString(@"Tools", nil);
    RAMAnimatedTabBarItem *tabBarItemTools = [[RAMAnimatedTabBarItem alloc] initWithTitle:[tabBarItemToolsTitle uppercaseString] image:[UIImage imageNamed:@"ToolsTabBar.png"] tag:kToolsId];
    tabBarItemTools.yOffSet = kTabBarItemYOffset;
    tabBarItemTools.textColor = UIColorFromRGB(kTabBarItemInfoTextColor);
    tabBarItemTools.iconColor = UIColorFromRGB(kTabBarItemInfoIconColor);
    tabBarItemTools.textFont = [UIFont fontWithName:@"Oswald-Regular" size:kTabBarItemTextSize];
    tabBarItemTools.animation = tabAnimation;

    //View Controllers
    RMAInfoViewController *infoViewController = [[RMAInfoViewController alloc] initWTabBarSize:tabBarSize];
    UINavigationController *infoNavigationController = [[UINavigationController alloc] initWithRootViewController:infoViewController];
    infoNavigationController.tabBarItem = tabBarItemInfo;
    infoNavigationController.navigationBar.hidden = YES;

    RMAScanViewController *scanViewController = [[RMAScanViewController alloc] initWTabBarSize:tabBarSize];
    UINavigationController *scanNavigationController = [[UINavigationController alloc] initWithRootViewController:scanViewController];
    scanNavigationController.tabBarItem = tabBarItemScan;
    scanNavigationController.navigationBar.hidden = YES;

    RMAToolsViewController *toolsViewController = [[RMAToolsViewController alloc] init];
    UINavigationController *toolsNavigationController = [[UINavigationController alloc] initWithRootViewController:toolsViewController];
    toolsNavigationController.tabBarItem = tabBarItemTools;
    toolsNavigationController.navigationBar.hidden = YES;

    //Main TabBar: configuration
    NSInteger numOfRuns = [[[NSUserDefaults standardUserDefaults] stringForKey:@"kRMANumOfRuns"] integerValue];
    if (numOfRuns == 1) {
        mainTabBarController.viewControllers = @[infoNavigationController, scanNavigationController, toolsNavigationController];
    } else if (numOfRuns > 1) {
        mainTabBarController.viewControllers = @[scanNavigationController, infoNavigationController, toolsNavigationController];

        [self setInfoIdParameter];
    }

    [mainTabBarController configureController];

    return infoViewController;
}

But I had to change also RAMAnimatedTabBarController.swift file too (locally on my project). Here you are what I did:

// MARK: Custom Badge

extension RAMAnimatedTabBarItem {

  /// The current badge value
  override public var badgeValue: String? {
    get {
      return badge?.text
    }
    set(newValue) {

      if newValue == nil {
        badge?.removeFromSuperview()
        badge = nil;
        return
      }

      if let iconView = iconView, let contanerView = iconView.icon.superview where badge == nil {
        badge = RAMBadge.badge()
        badge!.addBadgeOnView(contanerView)
      }

      badge?.text = newValue
    }
  }
}

/// UITabBarItem with animation
public class RAMAnimatedTabBarItem: UITabBarItem {

  @IBInspectable public var yOffSet: CGFloat = 0

  public override var enabled: Bool {
    didSet {
      iconView?.icon.alpha = enabled == true ? 1 : 0.5
      iconView?.textLabel.alpha = enabled == true ? 1 : 0.5
    }
  }

  /// animation for UITabBarItem. use RAMFumeAnimation, RAMBounceAnimation, RAMRotationAnimation, RAMFrameItemAnimation, RAMTransitionAnimation
  /// or create custom anmation inherit RAMItemAnimation
  @IBOutlet public var animation: RAMItemAnimation!

  /// The font used to render the UITabBarItem text.
  public var textFont: UIFont = UIFont.systemFontOfSize(10)

  /// The color of the UITabBarItem text.
  @IBInspectable public var textColor: UIColor = UIColor.blackColor()

  /// The tint color of the UITabBarItem icon.
  @IBInspectable public var iconColor: UIColor = UIColor.clearColor() // if alpha color is 0 color ignoring

  var bgDefaultColor: UIColor = UIColor.clearColor() // background color
  var bgSelectedColor: UIColor = UIColor.clearColor()

  //  The current badge value
  public var badge: RAMBadge? // use badgeValue to show badge

  // Container for icon and text in UITableItem. 
  public var iconView: (icon: UIImageView, textLabel: UILabel)?

  /**
   Start selected animation
   */
  public func playAnimation() {

    assert(animation != nil, "add animation in UITabBarItem")
    guard animation != nil && iconView != nil else  {
      return
    }
    animation.playAnimation(iconView!.icon, textLabel: iconView!.textLabel)
  }

  /**
   Start unselected animation
   */
  public func deselectAnimation() {

    guard animation != nil && iconView != nil else  {
      return
    }

    animation.deselectAnimation(
      iconView!.icon,
      textLabel: iconView!.textLabel,
      defaultTextColor: textColor,
      defaultIconColor: iconColor)
  }

  /**
   Set selected state without animation
   */
  public func selectedState() {
    guard animation != nil && iconView != nil else  {
      return
    }

    animation.selectedState(iconView!.icon, textLabel: iconView!.textLabel)
  }
}

extension  RAMAnimatedTabBarController {

  /**
   Change selected color for each UITabBarItem

   - parameter textSelectedColor: set new color for text
   - parameter iconSelectedColor: set new color for icon
   */
  public func changeSelectedColor(textSelectedColor:UIColor, iconSelectedColor:UIColor) {

    let items = tabBar.items as! [RAMAnimatedTabBarItem]
    for index in 0..<items.count {
      let item = items[index]

      item.animation.textSelectedColor = textSelectedColor
      item.animation.iconSelectedColor = iconSelectedColor

      if item == self.tabBar.selectedItem {
        item.selectedState()
      }
    }
  }

  /**
   Hide UITabBarController

    - parameter isHidden: A Boolean indicating whether the UITabBarController is displayed
   */
  public func animationTabBarHidden(isHidden:Bool) {
    guard let items = tabBar.items as? [RAMAnimatedTabBarItem] else {
      fatalError("items must inherit RAMAnimatedTabBarItem")
    }
    for item in items {
      if let iconView = item.iconView {
        iconView.icon.superview?.hidden = isHidden
      }
    }
    self.tabBar.hidden = isHidden;
  }

  /**
   Selected UITabBarItem with animaton

   - parameter from: Index for unselected animation
   - parameter to:   Index for selected animation
   */
  public func setSelectIndex(from from: Int, to: Int) {
    selectedIndex = to
    guard let items = tabBar.items as? [RAMAnimatedTabBarItem] else {
      fatalError("items must inherit RAMAnimatedTabBarItem")
    }

    let containerFrom = items[from].iconView?.icon.superview
    containerFrom?.backgroundColor = items[from].bgDefaultColor
    items[from].deselectAnimation()

    let containerTo = items[to].iconView?.icon.superview
    containerTo?.backgroundColor = items[to].bgSelectedColor
    items[to].playAnimation()
  }
}

/// UITabBarController with item animations
public class RAMAnimatedTabBarController: UITabBarController {

  private var didInit: Bool = false
  private var didLoadView: Bool = false

  // MARK: life circle

  /**
   Returns a newly initialized view controller with the nib file in the specified bundle.

   - parameter nibNameOrNil:   The name of the nib file to associate with the view controller. The nib file name should 
   not contain any leading path information. If you specify nil, the nibName property is set to nil.

   - parameter nibBundleOrNil: The bundle in which to search for the nib file. This method looks for the nib file in the
   bundle's language-specific project directories first, followed by the Resources directory. If this parameter is nil,
   the method uses the heuristics described below to locate the nib file.

   - returns: A newly initialized RAMAnimatedTabBarController object.
   */
  public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

    self.didInit = true
    self.initializeContainers()
  }

  /**
   Returns a newly initialized view controller with the nib file in the specified bundle.

   - parameter viewControllers: Sets the root view controllers of the tab bar controller.

   - returns: A newly initialized RAMAnimatedTabBarController object.
   */
  public init(viewControllers: [UIViewController]) {
    super.init(nibName: nil, bundle: nil)

    self.didInit = true

    // Set initial items
    self.setViewControllers(viewControllers, animated: false)

    self.initializeContainers()
  }

  /**
   Returns a newly initialized view controller with the nib file in the specified bundle.

   - parameter coder: An unarchiver object.

   - returns: A newly initialized RAMAnimatedTabBarController object.
   */
  required public init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    self.didInit = true
    self.initializeContainers()
  }

  override public func viewDidLoad() {
    super.viewDidLoad()

    self.didLoadView = true

    self.initializeContainers()
  }

  private func initializeContainers() {
    if !self.didInit || !self.didLoadView {
      return
    }
  }

  // MARK: create methods

  private func createCustomIcons(containers : NSDictionary) {

    guard let items = tabBar.items as? [RAMAnimatedTabBarItem] else {
      fatalError("items must inherit RAMAnimatedTabBarItem")
    }

    var index = 0
    for item in items {

      guard let itemImage = item.image else {
        fatalError("add image icon in UITabBarItem")
      }

      guard let container = containers["container\(items.count - 1 - index)"] as? UIView else {
        fatalError()
      }
      container.tag = index

      let renderMode = CGColorGetAlpha(item.iconColor.CGColor) == 0 ? UIImageRenderingMode.AlwaysOriginal :
        UIImageRenderingMode.AlwaysTemplate

      let icon = UIImageView(image: item.image?.imageWithRenderingMode(renderMode))
      icon.translatesAutoresizingMaskIntoConstraints = false
      icon.tintColor = item.iconColor

      // text
      let textLabel = UILabel()
      textLabel.text = item.title
      textLabel.backgroundColor = UIColor.clearColor()
      textLabel.textColor = item.textColor
      textLabel.font = item.textFont
      textLabel.textAlignment = NSTextAlignment.Center
      textLabel.translatesAutoresizingMaskIntoConstraints = false

      container.backgroundColor = (items as [RAMAnimatedTabBarItem])[index].bgDefaultColor

      container.addSubview(icon)
      createConstraints(icon, container: container, size: itemImage.size, yOffset: -5 - item.yOffSet)

      container.addSubview(textLabel)
      let textLabelWidth = tabBar.frame.size.width / CGFloat(items.count) - 5.0
      createConstraints(textLabel, container: container, size: CGSize(width: textLabelWidth , height: 10), yOffset: 18 - item.yOffSet)

      if item.enabled == false {
        icon.alpha      = 0.5
        textLabel.alpha = 0.5
      }
      item.iconView = (icon:icon, textLabel:textLabel)

      if 0 == index { // selected first elemet
        item.selectedState()
        container.backgroundColor = (items as [RAMAnimatedTabBarItem])[index].bgSelectedColor
      }

      item.image = nil
      item.title = ""
      index += 1
    }
  }

  private func createConstraints(view:UIView, container:UIView, size:CGSize, yOffset:CGFloat) {

    let constX = NSLayoutConstraint(item: view,
                                    attribute: NSLayoutAttribute.CenterX,
                                    relatedBy: NSLayoutRelation.Equal,
                                    toItem: container,
                                    attribute: NSLayoutAttribute.CenterX,
                                    multiplier: 1,
                                    constant: 0)
    container.addConstraint(constX)

    let constY = NSLayoutConstraint(item: view,
                                    attribute: NSLayoutAttribute.CenterY,
                                    relatedBy: NSLayoutRelation.Equal,
                                    toItem: container,
                                    attribute: NSLayoutAttribute.CenterY,
                                    multiplier: 1,
                                    constant: yOffset)
    container.addConstraint(constY)

    let constW = NSLayoutConstraint(item: view,
                                    attribute: NSLayoutAttribute.Width,
                                    relatedBy: NSLayoutRelation.Equal,
                                    toItem: nil,
                                    attribute: NSLayoutAttribute.NotAnAttribute,
                                    multiplier: 1,
                                    constant: size.width)
    view.addConstraint(constW)

    let constH = NSLayoutConstraint(item: view,
                                    attribute: NSLayoutAttribute.Height,
                                    relatedBy: NSLayoutRelation.Equal,
                                    toItem: nil,
                                    attribute: NSLayoutAttribute.NotAnAttribute,
                                    multiplier: 1,
                                    constant: size.height)
    view.addConstraint(constH)
  }

  private func createViewContainers() -> NSDictionary {

    guard let items = tabBar.items else {
      fatalError("add items in tabBar")
    }

    var containersDict = [String: AnyObject]()

    for index in 0..<items.count {
      let viewContainer = createViewContainer()
      containersDict["container\(index)"] = viewContainer
    }

    var formatString = "H:|-(0)-[container0]"
    for index in 1..<items.count {
      formatString += "-(0)-[container\(index)(==container0)]"
    }
    formatString += "-(0)-|"
    let  constranints = NSLayoutConstraint.constraintsWithVisualFormat(formatString,
                                                                       options:NSLayoutFormatOptions.DirectionRightToLeft,
                                                                       metrics: nil,
                                                                       views: (containersDict as [String : AnyObject]))
    view.addConstraints(constranints)

    return containersDict
  }

  private func createViewContainer() -> UIView {
    let viewContainer = UIView();
    viewContainer.backgroundColor = UIColor.clearColor() // for test
    viewContainer.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(viewContainer)

    // add gesture
    let tapGesture = UITapGestureRecognizer(target: self, action: "tapHandler:")
    tapGesture.numberOfTouchesRequired = 1
    viewContainer.addGestureRecognizer(tapGesture)

    // add constrains
    let constY = NSLayoutConstraint(item: viewContainer,
                                    attribute: NSLayoutAttribute.Bottom,
                                    relatedBy: NSLayoutRelation.Equal,
                                    toItem: view,
                                    attribute: NSLayoutAttribute.Bottom,
                                    multiplier: 1,
                                    constant: 0)

    view.addConstraint(constY)

    let constH = NSLayoutConstraint(item: viewContainer,
                                    attribute: NSLayoutAttribute.Height,
                                    relatedBy: NSLayoutRelation.Equal,
                                    toItem: nil,
                                    attribute: NSLayoutAttribute.NotAnAttribute,
                                    multiplier: 1,
                                    constant: tabBar.frame.size.height)
    viewContainer.addConstraint(constH)

    return viewContainer
  }

  // MARK: actions

  func tapHandler(gesture:UIGestureRecognizer) {

    guard let items = tabBar.items as? [RAMAnimatedTabBarItem],
      let gestureView = gesture.view else {
        fatalError("items must inherit RAMAnimatedTabBarItem")
    }

    let currentIndex = gestureView.tag

    if items[currentIndex].enabled == false { return }

    let controller = self.childViewControllers[currentIndex]

    if let shouldSelect = delegate?.tabBarController?(self, shouldSelectViewController: controller)
      where !shouldSelect {
      return
    }

    if selectedIndex != currentIndex {
      let animationItem : RAMAnimatedTabBarItem = items[currentIndex]
      animationItem.playAnimation()

      let deselectItem = items[selectedIndex]

      let containerPrevious : UIView = deselectItem.iconView!.icon.superview!
      containerPrevious.backgroundColor = items[currentIndex].bgDefaultColor

      deselectItem.deselectAnimation()

      let container : UIView = animationItem.iconView!.icon.superview!
      container.backgroundColor = items[currentIndex].bgSelectedColor

      selectedIndex = gestureView.tag
      delegate?.tabBarController?(self, didSelectViewController: controller)

    } else if selectedIndex == currentIndex {

      if let navVC = self.viewControllers![selectedIndex] as? UINavigationController {
        navVC.popToRootViewControllerAnimated(true)
      }
    }
  }

    // MARK: configure
    public func configureController() {

        let containers = createViewContainers()

        createCustomIcons(containers)
    }
}

Hope this helps you. Bye.

ignasibm commented 7 years ago

@foffux it works, thank you!!