Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 52174249fa | |||
| 2ea00f8238 | |||
| 50d0c1feaa | |||
| 445857fd92 | |||
| 76d074df03 | |||
| 3665d14c7a | |||
| 1bce9a939c | |||
| e546c49294 | |||
| 205354aa41 | |||
| 9687519cee | |||
| 0c07d6d8ed | |||
| 800567befc | |||
| e909d06015 | |||
| f5c9a9e444 | |||
| dd12ebf6a1 | |||
| 1799b007d7 | |||
| 85683d5870 | |||
| eccd00bc32 | |||
| 749c4a2be2 | |||
| ab650eda04 | |||
| 22f66aef17 | |||
| 2f54635f3a | |||
| 3fc716a0a6 | |||
| ba3c230eae | |||
| 607c2fa353 | |||
| f6723b656b |
@@ -0,0 +1,43 @@
|
||||
// swift-tools-version:5.1
|
||||
//
|
||||
// Package.swift
|
||||
//
|
||||
// Copyright (c) Ramotion Inc. (https://www.ramotion.com/)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import PackageDescription
|
||||
|
||||
|
||||
let package = Package(
|
||||
name: "RAMAnimatedTabBarController",
|
||||
platforms: [
|
||||
.iOS(.v9)
|
||||
],
|
||||
products: [
|
||||
.library(name: "RAMAnimatedTabBarController",
|
||||
targets: ["RAMAnimatedTabBarController"]),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "RAMAnimatedTabBarController",
|
||||
path: "RAMAnimatedTabBarController")
|
||||
],
|
||||
swiftLanguageVersions: [.v5]
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'RAMAnimatedTabBarController'
|
||||
s.version = '5.0.1'
|
||||
s.version = '5.2.0'
|
||||
s.license = 'MIT'
|
||||
s.summary = 'RAMAnimatedTabBarController is a Swift module for adding animation to tabbar items.'
|
||||
s.homepage = 'https://github.com/Ramotion/animated-tab-bar'
|
||||
|
||||
@@ -24,20 +24,18 @@ import UIKit
|
||||
extension RAMAnimatedTabBarController {
|
||||
|
||||
func createBottomLine() {
|
||||
guard let currentItem = (containers.filter { $0.value.tag == 0 }).first?.value else { return }
|
||||
|
||||
let lineHeight: CGFloat = 2
|
||||
guard let currentItem = containers.first else { return }
|
||||
|
||||
let container = UIView()
|
||||
container.backgroundColor = .clear
|
||||
container.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
|
||||
view.addSubview(container)
|
||||
|
||||
container.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
|
||||
container.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
|
||||
container.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
||||
container.heightAnchor.constraint(equalToConstant: lineHeight).isActive = true
|
||||
container.heightAnchor.constraint(equalToConstant: bottomLineHeight).isActive = true
|
||||
|
||||
|
||||
let line = UIView()
|
||||
@@ -48,10 +46,12 @@ extension RAMAnimatedTabBarController {
|
||||
|
||||
lineLeadingConstraint = bottomLine?.leadingAnchor.constraint(equalTo: currentItem.leadingAnchor)
|
||||
lineLeadingConstraint?.isActive = true
|
||||
|
||||
|
||||
lineHeightConstraint = bottomLine?.heightAnchor.constraint(equalToConstant: bottomLineHeight)
|
||||
lineHeightConstraint?.isActive = true
|
||||
|
||||
// add constraints
|
||||
bottomLine?.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
|
||||
bottomLine?.heightAnchor.constraint(equalToConstant: lineHeight).isActive = true
|
||||
bottomLine?.widthAnchor.constraint(equalTo: currentItem.widthAnchor).isActive = true
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ extension RAMAnimatedTabBarController {
|
||||
|
||||
func setBottomLinePosition(index: Int, animated: Bool = true) {
|
||||
guard let itemsCount = tabBar.items?.count, itemsCount > index,
|
||||
let currentItem = (containers.filter { $0.value.tag == index}).first?.value else { return }
|
||||
let currentItem = containers.at(index) else { return }
|
||||
|
||||
lineLeadingConstraint?.isActive = false
|
||||
|
||||
@@ -79,4 +79,11 @@ extension RAMAnimatedTabBarController {
|
||||
self.bottomLine?.superview?.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
func updateBottomLineHeight(to height: CGFloat) {
|
||||
lineHeightConstraint?.isActive = false
|
||||
|
||||
lineHeightConstraint = bottomLine?.heightAnchor.constraint(equalToConstant: height)
|
||||
lineHeightConstraint?.isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// AnimationTabBarController.swift
|
||||
// RAMAnimatedTabBarController.swift
|
||||
//
|
||||
// Copyright (c) 11/10/14 Ramotion Inc. (http://ramotion.com)
|
||||
//
|
||||
@@ -22,180 +22,6 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
// MARK: Custom Badge
|
||||
|
||||
extension RAMAnimatedTabBarItem {
|
||||
|
||||
/// The current badge value
|
||||
open override 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, badge == nil {
|
||||
badge = RAMBadge.badge()
|
||||
badge?.addBadgeOnView(contanerView)
|
||||
}
|
||||
|
||||
badge?.text = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// UITabBarItem with animation
|
||||
open class RAMAnimatedTabBarItem: UITabBarItem {
|
||||
|
||||
@IBInspectable open var yOffSet: CGFloat = 0
|
||||
|
||||
open override var isEnabled: Bool {
|
||||
didSet {
|
||||
iconView?.icon.alpha = isEnabled == true ? 1 : 0.5
|
||||
iconView?.textLabel.alpha = isEnabled == true ? 1 : 0.5
|
||||
}
|
||||
}
|
||||
|
||||
/// Animation for UITabBarItem. Use RAMFumeAnimation, RAMBounceAnimation, RAMRotationAnimation, RAMFrameItemAnimation, RAMTransitionAnimation
|
||||
/// Also posible create custom anmation inherit from the RAMItemAnimation look for https://github.com/Ramotion/animated-tab-bar#creating-custom-animations
|
||||
@IBOutlet open var animation: RAMItemAnimation!
|
||||
|
||||
/// The font used to render the UITabBarItem text.
|
||||
@IBInspectable open var textFontSize: CGFloat = 10
|
||||
|
||||
/// The color of the UITabBarItem text.
|
||||
@IBInspectable open var textColor: UIColor = UIColor.black
|
||||
|
||||
/// The tint color of the UITabBarItem icon.
|
||||
@IBInspectable open var iconColor: UIColor = UIColor.clear // if alpha color is 0 color ignoring
|
||||
|
||||
open var bgDefaultColor: UIColor = UIColor.clear // background color
|
||||
open var bgSelectedColor: UIColor = UIColor.clear
|
||||
|
||||
// The current badge value
|
||||
open var badge: RAMBadge? // use badgeValue to show badge
|
||||
|
||||
// Container for icon and text in UITableItem.
|
||||
open var iconView: (icon: UIImageView, textLabel: UILabel)?
|
||||
|
||||
/**
|
||||
Start selected animation
|
||||
*/
|
||||
open 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
|
||||
*/
|
||||
open 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
|
||||
*/
|
||||
open func selectedState() {
|
||||
guard animation != nil && iconView != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
animation.selectedState(iconView!.icon, textLabel: iconView!.textLabel)
|
||||
}
|
||||
|
||||
/**
|
||||
Set deselected state without animation
|
||||
*/
|
||||
open func deselectedState() {
|
||||
guard animation != nil && iconView != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
animation.deselectedState(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
|
||||
*/
|
||||
open 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 == tabBar.selectedItem {
|
||||
item.selectedState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Hide UITabBarController
|
||||
|
||||
- parameter isHidden: A Boolean indicating whether the UITabBarController is displayed
|
||||
*/
|
||||
open 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?.isHidden = isHidden
|
||||
}
|
||||
}
|
||||
tabBar.isHidden = isHidden
|
||||
}
|
||||
|
||||
/**
|
||||
Selected UITabBarItem with animaton
|
||||
|
||||
- parameter from: Index for unselected animation
|
||||
- parameter to: Index for selected animation
|
||||
*/
|
||||
open func setSelectIndex(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
|
||||
open class RAMAnimatedTabBarController: UITabBarController {
|
||||
|
||||
@@ -229,12 +55,23 @@ open class RAMAnimatedTabBarController: UITabBarController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Bottom line height
|
||||
**/
|
||||
open var bottomLineHeight: CGFloat = 2 {
|
||||
didSet {
|
||||
if bottomLineHeight > 0 {
|
||||
updateBottomLineHeight(to: bottomLineHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Bottom line time of animations duration
|
||||
**/
|
||||
open var bottomLineMoveDuration: TimeInterval = 0.3
|
||||
|
||||
var containers: [String: UIView] = [:]
|
||||
private(set) var containers: [UIView] = []
|
||||
|
||||
open override var viewControllers: [UIViewController]? {
|
||||
didSet {
|
||||
@@ -253,10 +90,29 @@ open class RAMAnimatedTabBarController: UITabBarController {
|
||||
}
|
||||
}
|
||||
|
||||
open override var selectedViewController: UIViewController? {
|
||||
willSet {
|
||||
guard let vc = newValue,
|
||||
let index = viewControllers?.firstIndex(of: vc) else { return }
|
||||
handleSelection(index: index)
|
||||
}
|
||||
}
|
||||
|
||||
var lineHeightConstraint: NSLayoutConstraint?
|
||||
var lineLeadingConstraint: NSLayoutConstraint?
|
||||
var bottomLine: UIView?
|
||||
var arrBottomAnchor:[NSLayoutConstraint] = []
|
||||
var arrViews:[UIView] = []
|
||||
var arrViews: [UIView] = []
|
||||
|
||||
/**
|
||||
Hide UITabBar
|
||||
|
||||
- parameter isHidden: A Boolean indicating whether the UITabBarController is displayed
|
||||
*/
|
||||
@available(*, deprecated, message: "Now you can use UITabBar isHidden")
|
||||
open func animationTabBarHidden(_ isHidden: Bool) {
|
||||
tabBar.isHidden = isHidden
|
||||
}
|
||||
|
||||
// MARK: life circle
|
||||
|
||||
@@ -265,37 +121,9 @@ open class RAMAnimatedTabBarController: UITabBarController {
|
||||
initializeContainers()
|
||||
}
|
||||
|
||||
fileprivate func initializeContainers() {
|
||||
containers.values.forEach { $0.removeFromSuperview() }
|
||||
containers = createViewContainers()
|
||||
|
||||
if !containers.isEmpty {
|
||||
createCustomIcons(containers)
|
||||
}
|
||||
}
|
||||
|
||||
override open func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
coordinator.animate(alongsideTransition: { (transitionCoordinatorContext) -> Void in
|
||||
let orient = UIApplication.shared.statusBarOrientation
|
||||
|
||||
for (index, var layoutAnchor) in self.arrBottomAnchor.enumerated() {
|
||||
|
||||
layoutAnchor.isActive = false
|
||||
|
||||
switch orient {
|
||||
case .portrait:
|
||||
layoutAnchor = self.arrViews[index].bottomAnchor.constraint(equalTo: self.bottomLayoutGuide.topAnchor)
|
||||
case .landscapeLeft,.landscapeRight :
|
||||
layoutAnchor = self.arrViews[index].bottomAnchor.constraint(equalTo: self.bottomLayoutGuide.bottomAnchor)
|
||||
default:
|
||||
print("Anything But Portrait")
|
||||
}
|
||||
|
||||
self.arrBottomAnchor[index] = layoutAnchor
|
||||
self.arrBottomAnchor[index].isActive = true
|
||||
}
|
||||
self.view.updateConstraints()
|
||||
|
||||
self.layoutContainers()
|
||||
}, completion: { (transitionCoordinatorContext) -> Void in
|
||||
//refresh view once rotation is completed not in will transition as it returns incorrect frame size.Refresh here
|
||||
})
|
||||
@@ -303,33 +131,73 @@ open class RAMAnimatedTabBarController: UITabBarController {
|
||||
}
|
||||
|
||||
// MARK: create methods
|
||||
|
||||
fileprivate func createCustomIcons(_ containers: [String: UIView]) {
|
||||
|
||||
if let items = tabBar.items, items.count > 5 { fatalError("More button not supported") }
|
||||
|
||||
private func initializeContainers() {
|
||||
containers.forEach { $0.removeFromSuperview() }
|
||||
containers.removeAll()
|
||||
|
||||
guard let items = tabBar.items else { return }
|
||||
guard items.count <= 5 else { fatalError("More button not supported") }
|
||||
|
||||
for index in 0 ..< items.count {
|
||||
let viewContainer = UIView()
|
||||
viewContainer.isExclusiveTouch = true
|
||||
viewContainer.tag = index
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(itemTap))
|
||||
viewContainer.addGestureRecognizer(tapGesture)
|
||||
tabBar.addSubview(viewContainer)
|
||||
containers.append(viewContainer)
|
||||
}
|
||||
|
||||
if !containers.isEmpty {
|
||||
createCustomIcons(containers: containers)
|
||||
}
|
||||
|
||||
layoutContainers()
|
||||
}
|
||||
|
||||
private func layoutContainers() {
|
||||
let itemWidth = tabBar.bounds.width / CGFloat(containers.count)
|
||||
let isRTL = tabBar.userInterfaceLayoutDirection == .rightToLeft
|
||||
|
||||
for (index, container) in containers.enumerated() {
|
||||
let i = isRTL ? (containers.count - 1 - index) : index
|
||||
let frame = CGRect(x: itemWidth * CGFloat(i), y: 0, width: itemWidth, height: Theme.tabBarHeight)
|
||||
container.frame = frame
|
||||
|
||||
if let item = tabBar.items?.at(index) as? RAMAnimatedTabBarItem {
|
||||
let iconView = item.iconView?.icon
|
||||
let iconSize = iconView?.image?.size ?? CGSize(width: 30, height: 30)
|
||||
let iconX = (container.frame.width - iconSize.width) / 2 + item.titlePositionAdjustment.horizontal
|
||||
let iconY = (container.frame.height - iconSize.height) / 2 + Theme.defaultIconVerticalOffset + item.titlePositionAdjustment.vertical
|
||||
iconView?.frame = CGRect(x: iconX, y: iconY, width: iconSize.width, height: iconSize.height)
|
||||
|
||||
let label = item.iconView?.textLabel
|
||||
let labelSize = label?.sizeThatFits(CGSize.zero) ?? CGSize(width: tabBar.frame.size.width / CGFloat(containers.count), height: 20)
|
||||
let labelX = (container.frame.width - labelSize.width) / 2 + item.titlePositionAdjustment.horizontal
|
||||
let labelY = (container.frame.height) / 2 + Theme.defaultTitleVerticalOffset + item.titlePositionAdjustment.vertical
|
||||
label?.frame = CGRect(x: labelX, y: labelY, width: labelSize.width, height: labelSize.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func createCustomIcons(containers: [UIView]) {
|
||||
guard let items = tabBar.items as? [RAMAnimatedTabBarItem] else {
|
||||
fatalError("items must inherit RAMAnimatedTabBarItem")
|
||||
}
|
||||
|
||||
var index = 0
|
||||
for item in items {
|
||||
|
||||
guard let container = containers["container\(items.count - 1 - index)"] else {
|
||||
fatalError()
|
||||
}
|
||||
container.tag = index
|
||||
|
||||
for (index, item) in items.enumerated() {
|
||||
let container = containers[index]
|
||||
let renderMode = item.iconColor.cgColor.alpha == 0 ? UIImage.RenderingMode.alwaysOriginal :
|
||||
UIImage.RenderingMode.alwaysTemplate
|
||||
|
||||
|
||||
let iconImage = item.image ?? item.iconView?.icon.image
|
||||
let icon = UIImageView(image: iconImage?.withRenderingMode(renderMode))
|
||||
icon.translatesAutoresizingMaskIntoConstraints = false
|
||||
icon.tintColor = item.iconColor
|
||||
icon.highlightedImage = item.selectedImage?.withRenderingMode(renderMode)
|
||||
container.addSubview(icon)
|
||||
|
||||
// text
|
||||
|
||||
let textLabel = UILabel()
|
||||
if let title = item.title, !title.isEmpty {
|
||||
textLabel.text = title
|
||||
@@ -340,18 +208,10 @@ open class RAMAnimatedTabBarController: UITabBarController {
|
||||
textLabel.textColor = item.textColor
|
||||
textLabel.font = UIFont.systemFont(ofSize: item.textFontSize)
|
||||
textLabel.textAlignment = NSTextAlignment.center
|
||||
textLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
container.backgroundColor = (items as [RAMAnimatedTabBarItem])[index].bgDefaultColor
|
||||
|
||||
container.addSubview(icon)
|
||||
let itemSize = item.image?.size ?? CGSize(width: 30, height: 30)
|
||||
createConstraints(icon, container: container, size: itemSize, yOffset: -5 - item.yOffSet)
|
||||
|
||||
container.addSubview(textLabel)
|
||||
let textLabelWidth = tabBar.frame.size.width / CGFloat(items.count) - 5.0
|
||||
createConstraints(textLabel, container: container, width: textLabelWidth, yOffset: 16 - item.yOffSet, heightRelation: .greaterThanOrEqual)
|
||||
|
||||
|
||||
|
||||
container.backgroundColor = (items as [RAMAnimatedTabBarItem])[index].bgDefaultColor
|
||||
if item.isEnabled == false {
|
||||
icon.alpha = 0.5
|
||||
textLabel.alpha = 0.5
|
||||
@@ -368,137 +228,18 @@ open class RAMAnimatedTabBarController: UITabBarController {
|
||||
|
||||
item.image = nil
|
||||
item.title = ""
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func createConstraints(_ view: UIView, container: UIView, size: CGSize, yOffset: CGFloat) {
|
||||
createConstraints(view, container: container, width: size.width, height: size.height, yOffset: yOffset)
|
||||
}
|
||||
|
||||
fileprivate func createConstraints(_ view: UIView, container: UIView, width: CGFloat? = nil, height: CGFloat? = nil, yOffset: CGFloat, heightRelation: NSLayoutConstraint.Relation = .equal) {
|
||||
|
||||
let constX = NSLayoutConstraint(item: view,
|
||||
attribute: NSLayoutConstraint.Attribute.centerX,
|
||||
relatedBy: NSLayoutConstraint.Relation.equal,
|
||||
toItem: container,
|
||||
attribute: NSLayoutConstraint.Attribute.centerX,
|
||||
multiplier: 1,
|
||||
constant: 0)
|
||||
container.addConstraint(constX)
|
||||
|
||||
let constY = NSLayoutConstraint(item: view,
|
||||
attribute: NSLayoutConstraint.Attribute.centerY,
|
||||
relatedBy: NSLayoutConstraint.Relation.equal,
|
||||
toItem: container,
|
||||
attribute: NSLayoutConstraint.Attribute.centerY,
|
||||
multiplier: 1,
|
||||
constant: yOffset)
|
||||
container.addConstraint(constY)
|
||||
|
||||
if let width = width {
|
||||
let constW = NSLayoutConstraint(item: view,
|
||||
attribute: NSLayoutConstraint.Attribute.width,
|
||||
relatedBy: NSLayoutConstraint.Relation.equal,
|
||||
toItem: nil,
|
||||
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
|
||||
multiplier: 1,
|
||||
constant: width)
|
||||
view.addConstraint(constW)
|
||||
}
|
||||
|
||||
if let height = height {
|
||||
let constH = NSLayoutConstraint(item: view,
|
||||
attribute: NSLayoutConstraint.Attribute.height,
|
||||
relatedBy: heightRelation,
|
||||
toItem: nil,
|
||||
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
|
||||
multiplier: 1,
|
||||
constant: height)
|
||||
view.addConstraint(constH)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func createViewContainers() -> [String: UIView] {
|
||||
|
||||
guard let items = tabBar.items, items.count > 0 else { return [:] }
|
||||
|
||||
var containersDict: [String: UIView] = [:]
|
||||
|
||||
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)-|"
|
||||
|
||||
var constranints:[NSLayoutConstraint]!
|
||||
|
||||
if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft{
|
||||
constranints = NSLayoutConstraint.constraints(withVisualFormat: formatString,
|
||||
options: NSLayoutConstraint.FormatOptions.directionLeftToRight,
|
||||
metrics: nil,
|
||||
views: (containersDict as [String: AnyObject]))
|
||||
} else {
|
||||
constranints = NSLayoutConstraint.constraints(withVisualFormat: formatString,
|
||||
options: NSLayoutConstraint.FormatOptions.directionRightToLeft,
|
||||
metrics: nil,
|
||||
views: (containersDict as [String: AnyObject]))
|
||||
}
|
||||
view.addConstraints(constranints)
|
||||
|
||||
return containersDict
|
||||
}
|
||||
|
||||
fileprivate func createViewContainer() -> UIView {
|
||||
let viewContainer = UIView()
|
||||
viewContainer.translatesAutoresizingMaskIntoConstraints = false
|
||||
viewContainer.isExclusiveTouch = true
|
||||
view.addSubview(viewContainer)
|
||||
|
||||
// add gesture
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(RAMAnimatedTabBarController.tapHandler(_:)))
|
||||
tapGesture.numberOfTouchesRequired = 1
|
||||
viewContainer.addGestureRecognizer(tapGesture)
|
||||
arrViews.append(viewContainer)
|
||||
|
||||
// add constrains
|
||||
if UIDevice.current.orientation.isLandscape {
|
||||
let bottomAnchor = viewContainer.bottomAnchor.constraint(equalTo: bottomLayoutGuide.bottomAnchor)
|
||||
self.arrBottomAnchor.append(bottomAnchor)
|
||||
bottomAnchor.isActive = true
|
||||
} else {
|
||||
let bottomAnchor = viewContainer.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor)
|
||||
self.arrBottomAnchor.append(bottomAnchor)
|
||||
bottomAnchor.isActive = true
|
||||
}
|
||||
|
||||
let constH = NSLayoutConstraint(item: viewContainer,
|
||||
attribute: NSLayoutConstraint.Attribute.height,
|
||||
relatedBy: NSLayoutConstraint.Relation.equal,
|
||||
toItem: nil,
|
||||
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
|
||||
multiplier: 1,
|
||||
constant: 49)
|
||||
viewContainer.addConstraint(constH)
|
||||
|
||||
return viewContainer
|
||||
}
|
||||
|
||||
|
||||
// MARK: actions
|
||||
|
||||
@objc open 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
|
||||
@objc private func itemTap(gesture: UITapGestureRecognizer) {
|
||||
guard let index = gesture.view?.tag else { return }
|
||||
handleSelection(index: index)
|
||||
}
|
||||
|
||||
private func handleSelection(index: Int) {
|
||||
guard let items = tabBar.items as? [RAMAnimatedTabBarItem] else { return }
|
||||
let currentIndex = index
|
||||
|
||||
if items[currentIndex].isEnabled == false { return }
|
||||
|
||||
@@ -510,27 +251,84 @@ open class RAMAnimatedTabBarController: UITabBarController {
|
||||
}
|
||||
|
||||
if selectedIndex != currentIndex {
|
||||
let animationItem: RAMAnimatedTabBarItem = items[currentIndex]
|
||||
animationItem.playAnimation()
|
||||
let previousItem = items.at(selectedIndex)
|
||||
let previousContainer: UIView? = previousItem?.iconView?.icon.superview
|
||||
previousContainer?.backgroundColor = items[selectedIndex].bgDefaultColor
|
||||
previousItem?.deselectAnimation()
|
||||
|
||||
let deselectItem = items[selectedIndex]
|
||||
let currentItem: RAMAnimatedTabBarItem = items[currentIndex]
|
||||
currentItem.playAnimation()
|
||||
let currentContainer: UIView? = currentItem.iconView?.icon.superview
|
||||
currentContainer?.backgroundColor = items[currentIndex].bgSelectedColor
|
||||
|
||||
let containerPrevious: UIView = deselectItem.iconView!.icon.superview!
|
||||
containerPrevious.backgroundColor = items[selectedIndex].bgDefaultColor
|
||||
|
||||
deselectItem.deselectAnimation()
|
||||
|
||||
let container: UIView = animationItem.iconView!.icon.superview!
|
||||
container.backgroundColor = items[currentIndex].bgSelectedColor
|
||||
|
||||
selectedIndex = gestureView.tag
|
||||
|
||||
} else if selectedIndex == currentIndex {
|
||||
|
||||
if let navVC = self.viewControllers![selectedIndex] as? UINavigationController {
|
||||
selectedIndex = index
|
||||
} else {
|
||||
if let navVC = viewControllers?[selectedIndex] as? UINavigationController {
|
||||
navVC.popToRootViewController(animated: true)
|
||||
}
|
||||
}
|
||||
delegate?.tabBarController?(self, didSelect: controller)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension RAMAnimatedTabBarController {
|
||||
|
||||
/**
|
||||
Change selected color for each UITabBarItem
|
||||
|
||||
- parameter textSelectedColor: set new color for text
|
||||
- parameter iconSelectedColor: set new color for icon
|
||||
*/
|
||||
open 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 == tabBar.selectedItem {
|
||||
item.selectedState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Selected UITabBarItem with animaton
|
||||
|
||||
- parameter from: Index for unselected animation
|
||||
- parameter to: Index for selected animation
|
||||
*/
|
||||
open func setSelectIndex(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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension RAMAnimatedTabBarController {
|
||||
enum Theme {
|
||||
public static let tabBarHeight: CGFloat = 49
|
||||
public static let defaultTitleVerticalOffset: CGFloat = 10
|
||||
public static let defaultIconVerticalOffset: CGFloat = -5
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension UIView {
|
||||
var userInterfaceLayoutDirection: UIUserInterfaceLayoutDirection {
|
||||
return UIView.userInterfaceLayoutDirection(for: self.semanticContentAttribute)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// RAMAnimatedTabBarItem.swift
|
||||
//
|
||||
// Copyright (c) 11/10/14 Ramotion Inc. (http://ramotion.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/// UITabBarItem with animation
|
||||
open class RAMAnimatedTabBarItem: UITabBarItem {
|
||||
|
||||
open override var isEnabled: Bool {
|
||||
didSet {
|
||||
iconView?.icon.alpha = isEnabled == true ? 1 : 0.5
|
||||
iconView?.textLabel.alpha = isEnabled == true ? 1 : 0.5
|
||||
}
|
||||
}
|
||||
|
||||
/// Animation for UITabBarItem. Use RAMFumeAnimation, RAMBounceAnimation, RAMRotationAnimation, RAMFrameItemAnimation, RAMTransitionAnimation
|
||||
/// Also posible create custom anmation inherit from the RAMItemAnimation look for https://github.com/Ramotion/animated-tab-bar#creating-custom-animations
|
||||
@IBOutlet open var animation: RAMItemAnimation!
|
||||
|
||||
/// The font used to render the UITabBarItem text.
|
||||
@IBInspectable open var textFontSize: CGFloat = 10
|
||||
|
||||
/// The color of the UITabBarItem text.
|
||||
@IBInspectable open var textColor: UIColor = #colorLiteral(red: 0.5079551811, green: 0.5472556715, blue: 0.6011400746, alpha: 1)
|
||||
|
||||
/// The tint color of the UITabBarItem icon.
|
||||
@IBInspectable open var iconColor: UIColor = UIColor.clear // if alpha color is 0 color ignoring
|
||||
|
||||
open var bgDefaultColor: UIColor = UIColor.clear // background color
|
||||
open var bgSelectedColor: UIColor = UIColor.clear
|
||||
|
||||
// The current badge value
|
||||
open var badge: RAMBadge? // use badgeValue to show badge
|
||||
|
||||
// Container for icon and text in UITableItem.
|
||||
open var iconView: (icon: UIImageView, textLabel: UILabel)?
|
||||
|
||||
/**
|
||||
Start selected animation
|
||||
*/
|
||||
open func playAnimation() {
|
||||
|
||||
assert(animation != nil, "add animation in UITabBarItem")
|
||||
guard animation != nil, let iconView = iconView else {
|
||||
return
|
||||
}
|
||||
animation.playAnimation(iconView.icon, textLabel: iconView.textLabel)
|
||||
}
|
||||
|
||||
/**
|
||||
Start unselected animation
|
||||
*/
|
||||
open 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
|
||||
*/
|
||||
open func selectedState() {
|
||||
guard animation != nil, let iconView = iconView else {
|
||||
return
|
||||
}
|
||||
|
||||
animation.selectedState(iconView.icon, textLabel: iconView.textLabel)
|
||||
}
|
||||
|
||||
/**
|
||||
Set deselected state without animation
|
||||
*/
|
||||
open func deselectedState() {
|
||||
guard animation != nil && iconView != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
animation.deselectedState(iconView!.icon, textLabel: iconView!.textLabel)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Custom Badge
|
||||
extension RAMAnimatedTabBarItem {
|
||||
|
||||
/// The current badge value
|
||||
open override 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, badge == nil {
|
||||
badge = RAMBadge.badge()
|
||||
badge?.addBadgeOnView(contanerView)
|
||||
}
|
||||
|
||||
badge?.text = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Collection+Extensions.swift
|
||||
//
|
||||
// Copyright (c) 11/10/14 Ramotion Inc. (http://ramotion.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Collection where Self.Index == Self.Indices.Iterator.Element {
|
||||
/**
|
||||
Returns an optional element. If the `index` does not exist in the collection, the subscript returns nil.
|
||||
|
||||
- parameter safe: The index of the element to return, if it exists.
|
||||
|
||||
- returns: An optional element from the collection at the specified index.
|
||||
*/
|
||||
public subscript(safe i: Index) -> Self.Iterator.Element? {
|
||||
return at(i)
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an optional element. If the `index` does not exist in the collection, the function returns nil.
|
||||
|
||||
- parameter index: The index of the element to return, if it exists.
|
||||
|
||||
- returns: An optional element from the collection at the specified index.
|
||||
*/
|
||||
public func at(_ i: Index) -> Self.Iterator.Element? {
|
||||
return indices.contains(i) ? self[i] : nil
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,10 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3950EDD82354950E0072BAAD /* RAMAnimatedTabBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3950EDD72354950E0072BAAD /* RAMAnimatedTabBarItem.swift */; };
|
||||
3950EDD9235496AF0072BAAD /* RAMAnimatedTabBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3950EDD72354950E0072BAAD /* RAMAnimatedTabBarItem.swift */; };
|
||||
3950EDDC235497650072BAAD /* Collection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3950EDDB235497650072BAAD /* Collection+Extensions.swift */; };
|
||||
3950EDDD235497910072BAAD /* Collection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3950EDDB235497650072BAAD /* Collection+Extensions.swift */; };
|
||||
5A1F33BC2126AA3D004B8735 /* AnimatedTabBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1F33BB2126AA3D004B8735 /* AnimatedTabBarTests.swift */; };
|
||||
5A5D3FF021B91D0700304986 /* RAMBadgeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A5D3FEF21B91D0700304986 /* RAMBadgeTests.swift */; };
|
||||
5ADAB94A209B0FA8006CCD85 /* RAMAnimatedTabBarController+BottomLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADAB949209B0FA8006CCD85 /* RAMAnimatedTabBarController+BottomLine.swift */; };
|
||||
@@ -70,6 +74,8 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3950EDD72354950E0072BAAD /* RAMAnimatedTabBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RAMAnimatedTabBarItem.swift; sourceTree = "<group>"; };
|
||||
3950EDDB235497650072BAAD /* Collection+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Extensions.swift"; sourceTree = "<group>"; };
|
||||
5A1F33B92126AA3D004B8735 /* AnimatedTabBarTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AnimatedTabBarTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5A1F33BB2126AA3D004B8735 /* AnimatedTabBarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedTabBarTests.swift; sourceTree = "<group>"; };
|
||||
5A1F33BD2126AA3D004B8735 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@@ -122,6 +128,14 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
3950EDDA2354974D0072BAAD /* Utilities */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3950EDDB235497650072BAAD /* Collection+Extensions.swift */,
|
||||
);
|
||||
path = Utilities;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5A1F33BA2126AA3D004B8735 /* AnimatedTabBarTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -203,9 +217,11 @@
|
||||
CE4146971A1B94170037F03C /* RAMAnimatedTabBarControlller */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3950EDDA2354974D0072BAAD /* Utilities */,
|
||||
5AC42AE5210AFA110009889F /* BottomLine */,
|
||||
84BC64201C22E41F00B89B79 /* RAMBadge */,
|
||||
CE90A83F1A1C7C14002D8931 /* RAMAnimatedTabBarController.swift */,
|
||||
3950EDD72354950E0072BAAD /* RAMAnimatedTabBarItem.swift */,
|
||||
CE4146981A1B944D0037F03C /* Animations */,
|
||||
CE41469D1A1B944D0037F03C /* RAMItemAnimationProtocol.swift */,
|
||||
);
|
||||
@@ -434,7 +450,9 @@
|
||||
84D4B7A91DB0D37700EE38C6 /* RAMBadge.swift in Sources */,
|
||||
84D4B7AF1DB0D38B00EE38C6 /* RAMTransitionItemAnimations.swift in Sources */,
|
||||
5ADAB94B209B51E5006CCD85 /* RAMAnimatedTabBarController+BottomLine.swift in Sources */,
|
||||
3950EDDD235497910072BAAD /* Collection+Extensions.swift in Sources */,
|
||||
84D4B7B01DB0D38F00EE38C6 /* RAMItemAnimationProtocol.swift in Sources */,
|
||||
3950EDD9235496AF0072BAAD /* RAMAnimatedTabBarItem.swift in Sources */,
|
||||
84D4B7AB1DB0D37F00EE38C6 /* RAMFumeAnimation.swift in Sources */,
|
||||
84D4B7AA1DB0D37B00EE38C6 /* RAMAnimatedTabBarController.swift in Sources */,
|
||||
84D4B7AC1DB0D38100EE38C6 /* RAMBounceAnimation.swift in Sources */,
|
||||
@@ -454,7 +472,9 @@
|
||||
CE90A8431A1C8DD3002D8931 /* RAMRotationAnimation.swift in Sources */,
|
||||
F3E056BE1A2DD57600F33DDA /* RAMFumeAnimation.swift in Sources */,
|
||||
CE41469F1A1B944D0037F03C /* RAMTransitionItemAnimations.swift in Sources */,
|
||||
3950EDDC235497650072BAAD /* Collection+Extensions.swift in Sources */,
|
||||
84BC64221C22E4C800B89B79 /* RAMBadge.swift in Sources */,
|
||||
3950EDD82354950E0072BAAD /* RAMAnimatedTabBarItem.swift in Sources */,
|
||||
CE4146A01A1B944D0037F03C /* RAMItemAnimationProtocol.swift in Sources */,
|
||||
CE4146781A1B923D0037F03C /* AppDelegate.swift in Sources */,
|
||||
CE90A8791A1CE200002D8931 /* RAMBounceAnimation.swift in Sources */,
|
||||
@@ -552,7 +572,7 @@
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
@@ -581,7 +601,7 @@
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="QjJ-1j-Kct">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="QjJ-1j-Kct">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@@ -34,11 +31,6 @@
|
||||
<viewLayoutGuide key="safeArea" id="cbk-oV-z7H"/>
|
||||
</view>
|
||||
<tabBarItem key="tabBarItem" title="Item" image="drop" id="tS2-0E-St8" customClass="RAMAnimatedTabBarItem" customModule="Animated_Tab_Bar" customModuleProvider="target">
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="textColor">
|
||||
<color key="value" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="animation" destination="Lky-Hp-l9U" id="r67-ap-cxK"/>
|
||||
</connections>
|
||||
@@ -78,11 +70,6 @@
|
||||
<viewLayoutGuide key="safeArea" id="8ec-QI-6Cw"/>
|
||||
</view>
|
||||
<tabBarItem key="tabBarItem" title="Item1" image="icon_pin" id="lUH-JS-dWf" customClass="RAMAnimatedTabBarItem" customModule="Animated_Tab_Bar" customModuleProvider="target">
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="textColor">
|
||||
<color key="value" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="animation" destination="CzN-js-aQV" id="gvH-Rf-Hp8"/>
|
||||
</connections>
|
||||
@@ -125,11 +112,6 @@
|
||||
<viewLayoutGuide key="safeArea" id="VaI-Rh-DC9"/>
|
||||
</view>
|
||||
<tabBarItem key="tabBarItem" title="Item2" image="icon_user" id="z5N-yh-KHH" customClass="RAMAnimatedTabBarItem" customModule="Animated_Tab_Bar" customModuleProvider="target">
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="textColor">
|
||||
<color key="value" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="animation" destination="SMy-mk-LC7" id="MkP-KN-27u"/>
|
||||
</connections>
|
||||
@@ -212,11 +194,6 @@
|
||||
<viewLayoutGuide key="safeArea" id="kSB-yj-LRJ"/>
|
||||
</view>
|
||||
<tabBarItem key="tabBarItem" title="Item4" image="Settings" id="EiX-sv-bUZ" customClass="RAMAnimatedTabBarItem" customModule="Animated_Tab_Bar" customModuleProvider="target">
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="textColor">
|
||||
<color key="value" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="animation" destination="BSW-Za-y3b" id="Q93-Wg-KJV"/>
|
||||
</connections>
|
||||
@@ -259,11 +236,6 @@
|
||||
<viewLayoutGuide key="safeArea" id="oai-od-5ae"/>
|
||||
</view>
|
||||
<tabBarItem key="tabBarItem" title="Item3" image="Tools_00028" id="c38-iL-qNf" customClass="RAMAnimatedTabBarItem" customModule="Animated_Tab_Bar" customModuleProvider="target">
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="color" keyPath="textColor">
|
||||
<color key="value" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
<connections>
|
||||
<outlet property="animation" destination="Ojd-WY-9Yd" id="Ogs-bO-YG5"/>
|
||||
</connections>
|
||||
|
||||
@@ -1,98 +1,119 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-60.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-58.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-87.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-80.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-120.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-120.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-180.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-20.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-29.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-58.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-40.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-80.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-76.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-152.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-167.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Ramotion1024.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"pre-rendered" : true
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 464 B |
|
After Width: | Height: | Size: 618 B |
|
After Width: | Height: | Size: 834 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -1,4 +1,4 @@
|
||||
<a href="https://dev.ramotion.com?utm_source=gthb&utm_medium=repo&utm_campaign=animated-tab-bar"><img src="https://github.com/Ramotion/animated-tab-bar/blob/master/header.png"></a>
|
||||
<a href="https://www.ramotion.com/agency/app-development/?utm_source=gthb&utm_medium=repo&utm_campaign=animated-tab-bar"><img src="https://github.com/Ramotion/animated-tab-bar/blob/master/header.png"></a>
|
||||
|
||||
<a href="https://github.com/Ramotion/animated-tab-bar">
|
||||
<img align="left" src="https://github.com/Ramotion/animated-tab-bar/blob/master/Screenshots/animatedTabBar.gif" width="480" height="360" /></a>
|
||||
@@ -13,13 +13,12 @@ ___
|
||||
|
||||
|
||||
<p><h6>We specialize in the designing and coding of custom UI for Mobile Apps and Websites.</h6>
|
||||
<a href="https://dev.ramotion.com?utm_source=gthb&utm_medium=repo&utm_campaign=animated-tab-bar">
|
||||
<a href="https://www.ramotion.com/agency/app-development/?utm_source=gthb&utm_medium=repo&utm_campaign=animated-tab-bar">
|
||||
<img src="https://github.com/ramotion/gliding-collection/raw/master/contact_our_team@2x.png" width="187" height="34"></a>
|
||||
</p>
|
||||
<p><h6>Stay tuned for the latest updates:</h6>
|
||||
<a href="https://goo.gl/rPFpid" >
|
||||
<img src="https://i.imgur.com/ziSqeSo.png/" width="156" height="28"></a></p>
|
||||
<h6><a href="https://store.ramotion.com/product/iphone-x-clay-mockups?utm_source=gthb&utm_medium=special&utm_campaign=animated-tab-bar#demo">Get Free Mockup For your project →</a></h6>
|
||||
|
||||
</br>
|
||||
|
||||
@@ -48,9 +47,10 @@ pod 'RAMAnimatedTabBarController'
|
||||
or [Carthage](https://github.com/Carthage/Carthage) users can simply add to their `Cartfile`:
|
||||
```
|
||||
github "Ramotion/animated-tab-bar"
|
||||
|
||||
```
|
||||
|
||||
or [Swift Package Manager](https://swift.org/package-manager/)
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -157,7 +157,7 @@ Try this UI component and more like this in our iOS app. Contact us if intereste
|
||||
<a href="https://itunes.apple.com/app/apple-store/id1182360240?pt=550053&ct=animated-tab-bar&mt=8" >
|
||||
<img src="https://github.com/ramotion/gliding-collection/raw/master/app_store@2x.png" width="117" height="34"></a>
|
||||
|
||||
<a href="https://dev.ramotion.com?utm_source=gthb&utm_medium=repo&utm_campaign=animated-tab-bar">
|
||||
<a href="https://www.ramotion.com/agency/app-development/?utm_source=gthb&utm_medium=repo&utm_campaign=animated-tab-bar">
|
||||
<img src="https://github.com/ramotion/gliding-collection/raw/master/contact_our_team@2x.png" width="187" height="34"></a>
|
||||
<br>
|
||||
<br>
|
||||
|
||||