Commit 61c59ba7 by Daniel Dahan

Merge branch 'temp' into development

parents f7cb0246 9b69558f
## 2.15.0
* [issue-1057](https://github.com/CosmicMind/Material/issues/1057): Added image states for TabItems used in TabBar and TabsController
## 2.14.0 ## 2.14.0
* [issue-995](https://github.com/CosmicMind/Material/issues/995): Updated iOS 11 layout margins for NavigationBar. * [issue-995](https://github.com/CosmicMind/Material/issues/995): Updated iOS 11 layout margins for NavigationBar.
......
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'Material' s.name = 'Material'
s.version = '2.14.0' s.version = '2.15.0'
s.swift_version = '4.0'
s.license = 'BSD-3-Clause' s.license = 'BSD-3-Clause'
s.summary = 'A UI/UX framework for creating beautiful applications.' s.summary = 'A UI/UX framework for creating beautiful applications.'
s.homepage = 'http://cosmicmind.com' s.homepage = 'http://cosmicmind.com'
......
...@@ -273,7 +273,7 @@ ...@@ -273,7 +273,7 @@
96BCB7971CB40DC500C806FE /* NavigationDrawerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationDrawerController.swift; sourceTree = "<group>"; }; 96BCB7971CB40DC500C806FE /* NavigationDrawerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationDrawerController.swift; sourceTree = "<group>"; };
96BCB7981CB40DC500C806FE /* Bar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bar.swift; sourceTree = "<group>"; }; 96BCB7981CB40DC500C806FE /* Bar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bar.swift; sourceTree = "<group>"; };
96BCB7991CB40DC500C806FE /* TransitionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionController.swift; sourceTree = "<group>"; }; 96BCB7991CB40DC500C806FE /* TransitionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionController.swift; sourceTree = "<group>"; };
96BCB79A1CB40DC500C806FE /* TabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = "<group>"; tabWidth = 4; }; 96BCB79A1CB40DC500C806FE /* TabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = "<group>"; tabWidth = 2; };
96BCB79C1CB40DC500C806FE /* TextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; }; 96BCB79C1CB40DC500C806FE /* TextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
96BCB79D1CB40DC500C806FE /* TextStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextStorage.swift; sourceTree = "<group>"; }; 96BCB79D1CB40DC500C806FE /* TextStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextStorage.swift; sourceTree = "<group>"; };
96BCB79E1CB40DC500C806FE /* TextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = "<group>"; }; 96BCB79E1CB40DC500C806FE /* TextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = "<group>"; };
...@@ -878,7 +878,7 @@ ...@@ -878,7 +878,7 @@
attributes = { attributes = {
LastSwiftMigration = 0710; LastSwiftMigration = 0710;
LastSwiftUpdateCheck = 0730; LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0900; LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "CosmicMind, Inc."; ORGANIZATIONNAME = "CosmicMind, Inc.";
TargetAttributes = { TargetAttributes = {
963832351B88DFD80015F710 = { 963832351B88DFD80015F710 = {
...@@ -1056,12 +1056,14 @@ ...@@ -1056,12 +1056,14 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES; CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
...@@ -1117,12 +1119,14 @@ ...@@ -1117,12 +1119,14 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES; CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0920" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
...@@ -56,7 +55,6 @@ ...@@ -56,7 +55,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
......
Subproject commit 654928d706213db2cd9f71281361960177ad0c1d Subproject commit b3595d023fdd3b64dede8c30bcaa08ee366cf249
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.13.7</string> <string>2.15.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
......
...@@ -31,536 +31,603 @@ ...@@ -31,536 +31,603 @@
import UIKit import UIKit
open class TabItem: FlatButton { open class TabItem: FlatButton {
open override func prepare() { /// A dictionary of TabItemStates to UIColors for states.
super.prepare() fileprivate var colorForState = [TabItemState: UIColor]()
pulseAnimation = .none
} /// A dictionary of TabItemStates to UIImages for states.
fileprivate var imageForState = [TabItemState: UIImage]()
/// Sets the normal and highlighted image for the button.
open override var image: UIImage? {
didSet {
setTabItemImage(image, for: .normal)
setTabItemImage(image, for: .selected)
setTabItemImage(image, for: .highlighted)
super.image = image
}
}
open override func prepare() {
super.prepare()
pulseAnimation = .none
prepareImages()
prepareColors()
updateColors()
}
}
fileprivate extension TabItem {
/// Prepares the tabsItems images.
func prepareImages() {
imageForState[.normal] = image
imageForState[.selected] = image
imageForState[.highlighted] = image
}
/// Prepares the tabsItems colors.
func prepareColors() {
colorForState[.normal] = Color.grey.base
colorForState[.selected] = Color.blue.base
colorForState[.highlighted] = Color.blue.base
}
}
fileprivate extension TabItem {
/// Updates the tabItems colors.
func updateColors() {
let normalColor = colorForState[.normal]!
let selectedColor = colorForState[.selected]!
let highlightedColor = colorForState[.highlighted]!
setTitleColor(normalColor, for: .normal)
setImage(imageForState[.normal]?.tint(with: normalColor), for: .normal)
setTitleColor(selectedColor, for: .selected)
setImage(imageForState[.selected]?.tint(with: selectedColor), for: .selected)
setTitleColor(highlightedColor, for: .highlighted)
setImage(imageForState[.highlighted]?.tint(with: highlightedColor), for: .highlighted)
}
}
extension TabItem {
/**
Retrieves the tabItem color for a given state.
- Parameter for state: A TabItemState.
- Returns: A UIColor.
*/
open func getTabItemColor(for state: TabItemState) -> UIColor {
return colorForState[state]!
}
/**
Sets the color for the tabItem given a TabItemState.
- Parameter _ color: A UIColor.
- Parameter for state: A TabItemState.
*/
open func setTabItemColor(_ color: UIColor, for state: TabItemState) {
colorForState[state] = color
updateColors()
}
/**
Retrieves the tabItem image for a given state.
- Parameter for state: A TabItemState.
- Returns: An optional UIImage.
*/
open func getTabItemImage(for state: TabItemState) -> UIImage? {
return imageForState[state]
}
/**
Sets the image for the tabItem given a TabItemState.
- Parameter _ image: An optional UIImage.
- Parameter for state: A TabItemState.
*/
open func setTabItemImage(_ image: UIImage?, for state: TabItemState) {
imageForState[state] = image
updateColors()
}
} }
@objc(TabItemState) @objc(TabItemState)
public enum TabItemState: Int { public enum TabItemState: Int {
case normal case normal
case highlighted case highlighted
case selected case selected
} }
@objc(TabItemLineState) @objc(TabItemLineState)
public enum TabItemLineState: Int { public enum TabItemLineState: Int {
case selected case selected
} }
@objc(TabBarLineAlignment) @objc(TabBarLineAlignment)
public enum TabBarLineAlignment: Int { public enum TabBarLineAlignment: Int {
case top case top
case bottom case bottom
} }
@objc(TabBarDelegate) @objc(TabBarDelegate)
public protocol TabBarDelegate { public protocol TabBarDelegate {
/** /**
A delegation method that is executed to determine if the TabBar should A delegation method that is executed to determine if the TabBar should
transition to the next tab. transition to the next tab.
- Parameter tabBar: A TabBar. - Parameter tabBar: A TabBar.
- Parameter tabItem: A TabItem. - Parameter tabItem: A TabItem.
- Returns: A Boolean. - Returns: A Boolean.
*/ */
@objc @objc
optional func tabBar(tabBar: TabBar, shouldSelect tabItem: TabItem) -> Bool optional func tabBar(tabBar: TabBar, shouldSelect tabItem: TabItem) -> Bool
/** /**
A delegation method that is executed when the tabItem will trigger the A delegation method that is executed when the tabItem will trigger the
animation to the next tab. animation to the next tab.
- Parameter tabBar: A TabBar. - Parameter tabBar: A TabBar.
- Parameter tabItem: A TabItem. - Parameter tabItem: A TabItem.
*/ */
@objc @objc
optional func tabBar(tabBar: TabBar, willSelect tabItem: TabItem) optional func tabBar(tabBar: TabBar, willSelect tabItem: TabItem)
/** /**
A delegation method that is executed when the tabItem did complete the A delegation method that is executed when the tabItem did complete the
animation to the next tab. animation to the next tab.
- Parameter tabBar: A TabBar. - Parameter tabBar: A TabBar.
- Parameter tabItem: A TabItem. - Parameter tabItem: A TabItem.
*/ */
@objc @objc
optional func tabBar(tabBar: TabBar, didSelect tabItem: TabItem) optional func tabBar(tabBar: TabBar, didSelect tabItem: TabItem)
} }
@objc(_TabBarDelegate) @objc(_TabBarDelegate)
internal protocol _TabBarDelegate { internal protocol _TabBarDelegate {
/** /**
A delegation method that is executed when the tabItem will trigger the A delegation method that is executed when the tabItem will trigger the
animation to the next tab. animation to the next tab.
- Parameter tabBar: A TabBar. - Parameter tabBar: A TabBar.
- Parameter tabItem: A TabItem. - Parameter tabItem: A TabItem.
*/ */
@objc @objc
optional func _tabBar(tabBar: TabBar, willSelect tabItem: TabItem) optional func _tabBar(tabBar: TabBar, willSelect tabItem: TabItem)
} }
@objc(TabBarStyle) @objc(TabBarStyle)
public enum TabBarStyle: Int { public enum TabBarStyle: Int {
case auto case auto
case nonScrollable case nonScrollable
case scrollable case scrollable
} }
open class TabBar: Bar { open class TabBar: Bar {
/// Only for inital load to get the line animation correct. /// A dictionary of TabItemLineStates to UIColors for the line.
fileprivate var shouldNotAnimateLineView = false fileprivate var lineColorForState = [TabItemLineState: UIColor]()
/// The total width of the tabItems. /// Only for inital load to get the line animation correct.
fileprivate var tabItemsTotalWidth: CGFloat { fileprivate var shouldNotAnimateLineView = false
var w: CGFloat = 0
let q = 2 * tabItemsInterimSpace /// The total width of the tabItems.
let p = q + tabItemsInterimSpace fileprivate var tabItemsTotalWidth: CGFloat {
var w: CGFloat = 0
for v in tabItems { let q = 2 * tabItemsInterimSpace
let x = v.sizeThatFits(CGSize(width: .greatestFiniteMagnitude, height: scrollView.bounds.height)).width let p = q + tabItemsInterimSpace
w += x
w += p for v in tabItems {
} let x = v.sizeThatFits(CGSize(width: .greatestFiniteMagnitude, height: scrollView.bounds.height)).width
w += x
w -= tabItemsInterimSpace w += p
}
return w
} w -= tabItemsInterimSpace
/// A dictionary of TabItemStates to UIColors for tabItems. return w
fileprivate var tabItemsColorForState = [TabItemState: UIColor]() }
/// A dictionary of TabItemLineStates to UIColors for the line. /// An enum that determines the tab bar style.
fileprivate var lineColorForState = [TabItemLineState: UIColor]() open var tabBarStyle = TabBarStyle.auto {
didSet {
/// An enum that determines the tab bar style. layoutSubviews()
open var tabBarStyle = TabBarStyle.auto { }
didSet { }
layoutSubviews()
} /// A reference to the scroll view when the tab bar style is scrollable.
} open let scrollView = UIScrollView()
/// A reference to the scroll view when the tab bar style is scrollable. /// Enables and disables bouncing when swiping.
open let scrollView = UIScrollView() open var isScrollBounceEnabled: Bool {
get {
/// Enables and disables bouncing when swiping. return scrollView.bounces
open var isScrollBounceEnabled: Bool { }
get { set(value) {
return scrollView.bounces scrollView.bounces = value
} }
set(value) { }
scrollView.bounces = value
} /// A delegation reference.
} open weak var delegate: TabBarDelegate?
internal weak var _delegate: _TabBarDelegate?
/// A delegation reference.
open weak var delegate: TabBarDelegate? /// The currently selected tabItem.
internal weak var _delegate: _TabBarDelegate? open internal(set) var selectedTabItem: TabItem? {
willSet {
/// The currently selected tabItem. selectedTabItem?.isSelected = false
open internal(set) var selectedTabItem: TabItem? { }
willSet { didSet {
selectedTabItem?.isSelected = false selectedTabItem?.isSelected = true
} }
didSet { }
selectedTabItem?.isSelected = true
} /// A preset wrapper around tabItems contentEdgeInsets.
} open var tabItemsContentEdgeInsetsPreset: EdgeInsetsPreset {
get {
/// A preset wrapper around tabItems contentEdgeInsets. return contentView.grid.contentEdgeInsetsPreset
open var tabItemsContentEdgeInsetsPreset: EdgeInsetsPreset { }
get { set(value) {
return contentView.grid.contentEdgeInsetsPreset contentView.grid.contentEdgeInsetsPreset = value
} }
set(value) { }
contentView.grid.contentEdgeInsetsPreset = value
} /// A reference to EdgeInsets.
} @IBInspectable
open var tabItemsContentEdgeInsets: EdgeInsets {
/// A reference to EdgeInsets. get {
@IBInspectable return contentView.grid.contentEdgeInsets
open var tabItemsContentEdgeInsets: EdgeInsets { }
get { set(value) {
return contentView.grid.contentEdgeInsets contentView.grid.contentEdgeInsets = value
} }
set(value) { }
contentView.grid.contentEdgeInsets = value
} /// A preset wrapper around tabItems interimSpace.
} open var tabItemsInterimSpacePreset: InterimSpacePreset {
get {
/// A preset wrapper around tabItems interimSpace. return contentView.grid.interimSpacePreset
open var tabItemsInterimSpacePreset: InterimSpacePreset { }
get { set(value) {
return contentView.grid.interimSpacePreset contentView.grid.interimSpacePreset = value
} }
set(value) { }
contentView.grid.interimSpacePreset = value
} /// A wrapper around tabItems interimSpace.
} @IBInspectable
open var tabItemsInterimSpace: InterimSpace {
/// A wrapper around tabItems interimSpace. get {
@IBInspectable return contentView.grid.interimSpace
open var tabItemsInterimSpace: InterimSpace { }
get { set(value) {
return contentView.grid.interimSpace contentView.grid.interimSpace = value
} }
set(value) { }
contentView.grid.interimSpace = value
} /// TabItems.
} @objc
open var tabItems = [TabItem]() {
/// TabItems. didSet {
@objc oldValue.forEach {
open var tabItems = [TabItem]() { $0.removeFromSuperview()
didSet { }
oldValue.forEach {
$0.removeFromSuperview() prepareTabItems()
} layoutSubviews()
}
prepareTabItems() }
layoutSubviews()
} /// A reference to the line UIView.
} open let line = UIView()
/// A reference to the line UIView. /// A value for the line alignment.
open let line = UIView() @objc
open var lineAlignment = TabBarLineAlignment.bottom {
/// A value for the line alignment. didSet {
@objc layoutSubviews()
open var lineAlignment = TabBarLineAlignment.bottom { }
didSet { }
layoutSubviews()
} /// The line height.
} @objc
open var lineHeight: CGFloat {
/// The line height. get {
@objc return line.bounds.height
open var lineHeight: CGFloat { }
get { set(value) {
return line.bounds.height line.frame.size.height = value
} }
set(value) { }
line.frame.size.height = value
} /// The line color.
} @objc
open var lineColor: UIColor {
/// The line color. get {
@objc return lineColorForState[.selected]!
open var lineColor: UIColor { }
get { set(value) {
return lineColorForState[.selected]! setLineColor(value, for: .selected)
} }
set(value) { }
setLineColor(value, for: .selected)
} open override func layoutSubviews() {
} super.layoutSubviews()
guard willLayout else {
open override func layoutSubviews() { return
super.layoutSubviews() }
guard willLayout else {
return layoutScrollView()
} layoutLine()
layoutScrollView() updateScrollView()
layoutLine() }
updateScrollView() open override func prepare() {
} super.prepare()
contentEdgeInsetsPreset = .none
open override func prepare() { interimSpacePreset = .interimSpace6
super.prepare() tabItemsInterimSpacePreset = .interimSpace4
contentEdgeInsetsPreset = .none
interimSpacePreset = .interimSpace6 prepareContentView()
tabItemsInterimSpacePreset = .interimSpace4 prepareScrollView()
prepareDivider()
prepareContentView() prepareLine()
prepareScrollView() prepareLineColor()
prepareDivider()
prepareLine() updateLineColors()
prepareTabItemsColor() }
prepareLineColor()
updateTabItemColors()
updateLineColors()
}
} }
fileprivate extension TabBar { fileprivate extension TabBar {
// Prepares the line. // Prepares the line.
func prepareLine() { func prepareLine() {
line.layer.zPosition = 10000 line.layer.zPosition = 10000
lineHeight = 3 lineHeight = 3
scrollView.addSubview(line) scrollView.addSubview(line)
} }
/// Prepares the divider. /// Prepares the divider.
func prepareDivider() { func prepareDivider() {
dividerColor = Color.grey.lighten2 dividerColor = Color.grey.lighten2
dividerAlignment = .top dividerAlignment = .top
} }
/// Prepares the tabItems. /// Prepares the tabItems.
func prepareTabItems() { func prepareTabItems() {
shouldNotAnimateLineView = true shouldNotAnimateLineView = true
for v in tabItems { for v in tabItems {
v.grid.columns = 0 v.grid.columns = 0
v.contentEdgeInsets = .zero v.contentEdgeInsets = .zero
prepareTabItemHandler(tabItem: v) prepareTabItemHandler(tabItem: v)
} }
selectedTabItem = tabItems.first selectedTabItem = tabItems.first
} }
/// Prepares the tabsItems colors. /// Prepares the line colors.
func prepareTabItemsColor() { func prepareLineColor() {
tabItemsColorForState[.normal] = Color.grey.base lineColorForState[.selected] = Color.blue.base
tabItemsColorForState[.selected] = Color.blue.base }
tabItemsColorForState[.highlighted] = Color.blue.base
} /**
Prepares the tabItem animation handler.
/// Prepares the line colors. - Parameter tabItem: A TabItem.
func prepareLineColor() { */
lineColorForState[.selected] = Color.blue.base func prepareTabItemHandler(tabItem: TabItem) {
} removeTabItemHandler(tabItem: tabItem)
/** tabItem.addTarget(self, action: #selector(handleTabItemsChange(tabItem:)), for: .touchUpInside)
Prepares the tabItem animation handler. }
- Parameter tabItem: A TabItem.
*/ /// Prepares the contentView.
func prepareTabItemHandler(tabItem: TabItem) { func prepareContentView() {
removeTabItemHandler(tabItem: tabItem) contentView.layer.zPosition = 6000
}
tabItem.addTarget(self, action: #selector(handleTabItemsChange(tabItem:)), for: .touchUpInside)
} /// Prepares the scroll view.
func prepareScrollView() {
/// Prepares the contentView. scrollView.showsVerticalScrollIndicator = false
func prepareContentView() { scrollView.showsHorizontalScrollIndicator = false
contentView.layer.zPosition = 6000 centerViews = [scrollView]
} }
/// Prepares the scroll view.
func prepareScrollView() {
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
centerViews = [scrollView]
}
} }
fileprivate extension TabBar { fileprivate extension TabBar {
/// Layout the scrollView. /// Layout the scrollView.
func layoutScrollView() { func layoutScrollView() {
contentView.grid.reload() contentView.grid.reload()
if .scrollable == tabBarStyle || (.auto == tabBarStyle && tabItemsTotalWidth > scrollView.bounds.width) { if .scrollable == tabBarStyle || (.auto == tabBarStyle && tabItemsTotalWidth > scrollView.bounds.width) {
var w: CGFloat = 0 var w: CGFloat = 0
let q = 2 * tabItemsInterimSpace let q = 2 * tabItemsInterimSpace
let p = q + tabItemsInterimSpace let p = q + tabItemsInterimSpace
for v in tabItems { for v in tabItems {
v.sizeToFit() v.sizeToFit()
let x = v.sizeThatFits(CGSize(width: .greatestFiniteMagnitude, height: scrollView.bounds.height)).width let x = v.sizeThatFits(CGSize(width: .greatestFiniteMagnitude, height: scrollView.bounds.height)).width
v.frame.size.height = scrollView.bounds.height v.frame.size.height = scrollView.bounds.height
v.frame.size.width = x + q v.frame.size.width = x + q
v.frame.origin.x = w v.frame.origin.x = w
w += x w += x
w += p w += p
if scrollView != v.superview {
scrollView.addSubview(v)
}
}
w -= tabItemsInterimSpace
scrollView.contentSize = CGSize(width: w, height: scrollView.bounds.height)
} else {
scrollView.grid.begin()
scrollView.grid.views = tabItems
scrollView.grid.axis.columns = tabItems.count
scrollView.grid.contentEdgeInsets = tabItemsContentEdgeInsets
scrollView.grid.interimSpace = tabItemsInterimSpace
scrollView.grid.commit()
scrollView.contentSize = scrollView.frame.size
}
}
/// Layout the line view.
func layoutLine() {
guard let v = selectedTabItem else {
return
}
guard shouldNotAnimateLineView else { if scrollView != v.superview {
line.animate(.duration(0), scrollView.addSubview(v)
.size(width: v.bounds.width, height: lineHeight),
.position(x: v.center.x, y: .bottom == lineAlignment ? scrollView.bounds.height - lineHeight / 2 : lineHeight / 2))
return
} }
}
line.frame = CGRect(x: v.frame.origin.x, y: .bottom == lineAlignment ? scrollView.bounds.height - lineHeight : 0, width: v.bounds.width, height: lineHeight)
w -= tabItemsInterimSpace
shouldNotAnimateLineView = false
} scrollView.contentSize = CGSize(width: w, height: scrollView.bounds.height)
} else {
scrollView.grid.begin()
scrollView.grid.views = tabItems
scrollView.grid.axis.columns = tabItems.count
scrollView.grid.contentEdgeInsets = tabItemsContentEdgeInsets
scrollView.grid.interimSpace = tabItemsInterimSpace
scrollView.grid.commit()
scrollView.contentSize = scrollView.frame.size
}
}
/// Layout the line view.
func layoutLine() {
guard let v = selectedTabItem else {
return
}
guard shouldNotAnimateLineView else {
line.animate(.duration(0),
.size(width: v.bounds.width, height: lineHeight),
.position(x: v.center.x, y: .bottom == lineAlignment ? scrollView.bounds.height - lineHeight / 2 : lineHeight / 2))
return
}
line.frame = CGRect(x: v.frame.origin.x, y: .bottom == lineAlignment ? scrollView.bounds.height - lineHeight : 0, width: v.bounds.width, height: lineHeight)
shouldNotAnimateLineView = false
}
} }
fileprivate extension TabBar { extension TabBar {
/** /**
Removes the tabItem animation handler. Retrieves the tabItem color for a given state.
- Parameter tabItem: A TabItem. - Parameter for state: A TabItemState.
*/ - Returns: A optional UIColor.
func removeTabItemHandler(tabItem: TabItem) { */
tabItem.removeTarget(self, action: #selector(handleTabItemsChange(tabItem:)), for: .touchUpInside) open func getTabItemColor(for state: TabItemState) -> UIColor? {
} return tabItems.first?.getTabItemColor(for: state)
}
/**
Sets the color for the tabItem given a TabItemState.
- Parameter _ color: A UIColor.
- Parameter for state: A TabItemState.
*/
open func setTabItemsColor(_ color: UIColor, for state: TabItemState) {
for v in tabItems {
v.setTabItemColor(color, for: state)
}
}
/**
Retrieves the line color for a given state.
- Parameter for state: A TabItemLineState.
- Returns: A UIColor.
*/
open func getLineColor(for state: TabItemLineState) -> UIColor {
return lineColorForState[state]!
}
/**
Sets the color for the line given a TabItemLineState.
- Parameter _ color: A UIColor.
- Parameter for state: A TabItemLineState.
*/
open func setLineColor(_ color: UIColor, for state: TabItemLineState) {
lineColorForState[state] = color
updateLineColors()
}
} }
fileprivate extension TabBar { fileprivate extension TabBar {
/// Handles the tabItem touch event. /**
@objc Removes the tabItem animation handler.
func handleTabItemsChange(tabItem: TabItem) { - Parameter tabItem: A TabItem.
guard !(false == delegate?.tabBar?(tabBar: self, shouldSelect: tabItem)) else { */
return func removeTabItemHandler(tabItem: TabItem) {
} tabItem.removeTarget(self, action: #selector(handleTabItemsChange(tabItem:)), for: .touchUpInside)
}
animate(to: tabItem, isTriggeredByUserInteraction: true)
}
} }
extension TabBar { fileprivate extension TabBar {
/** /// Handles the tabItem touch event.
Selects a given index from the tabItems array. @objc
- Parameter at index: An Int. func handleTabItemsChange(tabItem: TabItem) {
- Paramater completion: An optional completion block. guard !(false == delegate?.tabBar?(tabBar: self, shouldSelect: tabItem)) else {
*/ return
@objc
open func select(at index: Int, completion: ((TabItem) -> Void)? = nil) {
guard -1 < index, index < tabItems.count else {
return
}
animate(to: tabItems[index], isTriggeredByUserInteraction: false, completion: completion)
} }
/** animate(to: tabItem, isTriggeredByUserInteraction: true)
Animates to a given tabItem. }
- Parameter to tabItem: A TabItem.
- Parameter completion: An optional completion block.
*/
open func animate(to tabItem: TabItem, completion: ((TabItem) -> Void)? = nil) {
animate(to: tabItem, isTriggeredByUserInteraction: false, completion: completion)
}
} }
extension TabBar { extension TabBar {
/** /**
Retrieves the tabItem color for a given state. Selects a given index from the tabItems array.
- Parameter for state: A TabItemState. - Parameter at index: An Int.
- Returns: A UIColor. - Paramater completion: An optional completion block.
*/ */
open func getTabItemColor(for state: TabItemState) -> UIColor { @objc
return tabItemsColorForState[state]! open func select(at index: Int, completion: ((TabItem) -> Void)? = nil) {
} guard -1 < index, index < tabItems.count else {
return
/** }
Sets the color for the tabItems given a TabItemState.
- Parameter _ color: A UIColor. animate(to: tabItems[index], isTriggeredByUserInteraction: false, completion: completion)
- Parameter for state: A TabItemState. }
*/
open func setTabItemsColor(_ color: UIColor, for state: TabItemState) { /**
tabItemsColorForState[state] = color Animates to a given tabItem.
updateTabItemColors() - Parameter to tabItem: A TabItem.
} - Parameter completion: An optional completion block.
*/
/** open func animate(to tabItem: TabItem, completion: ((TabItem) -> Void)? = nil) {
Retrieves the line color for a given state. animate(to: tabItem, isTriggeredByUserInteraction: false, completion: completion)
- Parameter for state: A TabItemLineState. }
- Returns: A UIColor.
*/
open func getLineColor(for state: TabItemLineState) -> UIColor {
return lineColorForState[state]!
}
/**
Sets the color for the line given a TabItemLineState.
- Parameter _ color: A UIColor.
- Parameter for state: A TabItemLineState.
*/
open func setLineColor(_ color: UIColor, for state: TabItemLineState) {
lineColorForState[state] = color
updateLineColors()
}
} }
fileprivate extension TabBar { fileprivate extension TabBar {
/// Updates the tabItems colors. /// Updates the line colors.
func updateTabItemColors() { func updateLineColors() {
let normalColor = tabItemsColorForState[.normal]! line.backgroundColor = lineColorForState[.selected]
let selectedColor = tabItemsColorForState[.selected]! }
let highlightedColor = tabItemsColorForState[.highlighted]!
for v in tabItems {
v.setTitleColor(normalColor, for: .normal)
v.setImage(v.image?.tint(with: normalColor), for: .normal)
v.setTitleColor(selectedColor, for: .selected)
v.setImage(v.image?.tint(with: selectedColor), for: .selected)
v.setTitleColor(highlightedColor, for: .highlighted)
v.setImage(v.image?.tint(with: highlightedColor), for: .highlighted)
}
}
/// Updates the line colors.
func updateLineColors() {
line.backgroundColor = lineColorForState[.selected]
}
} }
fileprivate extension TabBar { fileprivate extension TabBar {
/** /**
Animates to a given tabItem. Animates to a given tabItem.
- Parameter to tabItem: A TabItem. - Parameter to tabItem: A TabItem.
- Parameter isTriggeredByUserInteraction: A boolean indicating whether the - Parameter isTriggeredByUserInteraction: A boolean indicating whether the
state was changed by a user interaction, true if yes, false otherwise. state was changed by a user interaction, true if yes, false otherwise.
- Parameter completion: An optional completion block. - Parameter completion: An optional completion block.
*/ */
func animate(to tabItem: TabItem, isTriggeredByUserInteraction: Bool, completion: ((TabItem) -> Void)? = nil) { func animate(to tabItem: TabItem, isTriggeredByUserInteraction: Bool, completion: ((TabItem) -> Void)? = nil) {
if isTriggeredByUserInteraction { if isTriggeredByUserInteraction {
_delegate?._tabBar?(tabBar: self, willSelect: tabItem) _delegate?._tabBar?(tabBar: self, willSelect: tabItem)
delegate?.tabBar?(tabBar: self, willSelect: tabItem) delegate?.tabBar?(tabBar: self, willSelect: tabItem)
} }
selectedTabItem = tabItem selectedTabItem = tabItem
line.animate(.duration(0.25), line.animate(.duration(0.25),
.size(width: tabItem.bounds.width, height: lineHeight), .size(width: tabItem.bounds.width, height: lineHeight),
.position(x: tabItem.center.x, y: .bottom == lineAlignment ? scrollView.bounds.height - lineHeight / 2 : lineHeight / 2), .position(x: tabItem.center.x, y: .bottom == lineAlignment ? scrollView.bounds.height - lineHeight / 2 : lineHeight / 2),
.completion({ [weak self, isTriggeredByUserInteraction = isTriggeredByUserInteraction, tabItem = tabItem, completion = completion] in .completion({ [weak self, isTriggeredByUserInteraction = isTriggeredByUserInteraction, tabItem = tabItem, completion = completion] in
guard let s = self else { guard let s = self else {
return return
} }
if isTriggeredByUserInteraction { if isTriggeredByUserInteraction {
s.delegate?.tabBar?(tabBar: s, didSelect: tabItem) s.delegate?.tabBar?(tabBar: s, didSelect: tabItem)
} }
completion?(tabItem) completion?(tabItem)
})) }))
updateScrollView() updateScrollView()
} }
} }
fileprivate extension TabBar { fileprivate extension TabBar {
/// Updates the scrollView. /// Updates the scrollView.
func updateScrollView() { func updateScrollView() {
guard let v = selectedTabItem else { guard let v = selectedTabItem else {
return return
} }
if !scrollView.bounds.contains(v.frame) { if !scrollView.bounds.contains(v.frame) {
let contentOffsetX = (v.frame.origin.x < scrollView.bounds.minX) ? v.frame.origin.x : v.frame.maxX - scrollView.bounds.width let contentOffsetX = (v.frame.origin.x < scrollView.bounds.minX) ? v.frame.origin.x : v.frame.maxX - scrollView.bounds.width
let normalizedOffsetX = min(max(contentOffsetX, 0), scrollView.contentSize.width - scrollView.bounds.width) let normalizedOffsetX = min(max(contentOffsetX, 0), scrollView.contentSize.width - scrollView.bounds.width)
scrollView.setContentOffset(CGPoint(x: normalizedOffsetX, y: 0), animated: true) scrollView.setContentOffset(CGPoint(x: normalizedOffsetX, y: 0), animated: true)
}
} }
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment