Commit 6f688295 by Daniel Dahan

Merge branch 'development' into editor

parents 689434d3 d8ec48b9
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'Material' s.name = 'Material'
s.version = '2.3.2' s.version = '2.3.4'
s.license = 'BSD-3-Clause' s.license = 'BSD-3-Clause'
s.summary = 'Material is an animation and graphics framework that is used to create beautiful applications.' s.summary = 'Material is an animation and graphics framework that is used to create beautiful applications.'
s.homepage = 'http://materialswift.com' s.homepage = 'http://materialswift.com'
......
...@@ -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.3.2</string> <string>2.3.4</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
......
...@@ -35,8 +35,8 @@ open class ErrorTextField: TextField { ...@@ -35,8 +35,8 @@ open class ErrorTextField: TextField {
@IBInspectable @IBInspectable
open var isErrorRevealed = false { open var isErrorRevealed = false {
didSet { didSet {
layoutDetailLabel()
detailLabel.isHidden = !isErrorRevealed detailLabel.isHidden = !isErrorRevealed
layoutSubviews()
} }
} }
......
...@@ -37,70 +37,40 @@ public enum GridAxisDirection: Int { ...@@ -37,70 +37,40 @@ public enum GridAxisDirection: Int {
case vertical case vertical
} }
public class GridAxis { public struct GridAxis {
/// Grid reference.
unowned var grid: Grid
/// The direction the grid lays its views out. /// The direction the grid lays its views out.
open var direction: GridAxisDirection = .horizontal { var direction = GridAxisDirection.horizontal
didSet {
grid.reload()
}
}
/// The rows size. /// The rows size.
public var rows: Int { public var rows: Int
didSet {
grid.reload()
}
}
/// The columns size. /// The columns size.
public var columns: Int { public var columns: Int
didSet {
grid.reload()
}
}
/** /**
Initializer. Initializer.
- Parameter grid: The Grid reference used for offset values.
- Parameter rows: The number of rows, vertical axis the grid will use. - Parameter rows: The number of rows, vertical axis the grid will use.
- Parameter columns: The number of columns, horizontal axis the grid will use. - Parameter columns: The number of columns, horizontal axis the grid will use.
*/ */
public init(grid: Grid, rows: Int = 12, columns: Int = 12) { public init(rows: Int = 12, columns: Int = 12) {
self.grid = grid
self.rows = rows self.rows = rows
self.columns = columns self.columns = columns
} }
} }
public class GridOffset { public struct GridOffset {
/// Grid reference.
unowned var grid: Grid
/// The rows size. /// The rows size.
public var rows: Int { public var rows: Int
didSet {
grid.reload()
}
}
/// The columns size. /// The columns size.
public var columns: Int { public var columns: Int
didSet {
grid.reload()
}
}
/** /**
Initializer. Initializer.
- Parameter grid: The Grid reference used for offset values.
- Parameter rows: The number of rows, vertical axis the grid will use. - Parameter rows: The number of rows, vertical axis the grid will use.
- Parameter columns: The number of columns, horizontal axis the grid will use. - Parameter columns: The number of columns, horizontal axis the grid will use.
*/ */
public init(grid: Grid, rows: Int = 0, columns: Int = 0) { public init(rows: Int = 0, columns: Int = 0) {
self.grid = grid
self.rows = rows self.rows = rows
self.columns = columns self.columns = columns
} }
...@@ -128,10 +98,18 @@ public class Grid { ...@@ -128,10 +98,18 @@ public class Grid {
} }
/// Offsets for rows and columns. /// Offsets for rows and columns.
public private(set) var offset: GridOffset! public var offset = GridOffset() {
didSet {
reload()
}
}
/// The axis in which the Grid is laying out its views. /// The axis in which the Grid is laying out its views.
public private(set) var axis: GridAxis! public var axis = GridAxis() {
didSet {
reload()
}
}
/// Preset inset value for grid. /// Preset inset value for grid.
public var layoutEdgeInsetsPreset = EdgeInsetsPreset.none { public var layoutEdgeInsetsPreset = EdgeInsetsPreset.none {
...@@ -178,6 +156,9 @@ public class Grid { ...@@ -178,6 +156,9 @@ public class Grid {
/// An Array of UIButtons. /// An Array of UIButtons.
public var views = [UIView]() { public var views = [UIView]() {
didSet { didSet {
for v in oldValue {
v.removeFromSuperview()
}
reload() reload()
} }
} }
...@@ -193,8 +174,6 @@ public class Grid { ...@@ -193,8 +174,6 @@ public class Grid {
self.rows = rows self.rows = rows
self.columns = columns self.columns = columns
self.interimSpace = interimSpace self.interimSpace = interimSpace
offset = GridOffset(grid: self)
axis = GridAxis(grid: self)
} }
/// Begins a deferred block. /// Begins a deferred block.
...@@ -214,6 +193,14 @@ public class Grid { ...@@ -214,6 +193,14 @@ public class Grid {
return return
} }
guard let canvas = context else {
return
}
guard 0 < canvas.width && 0 < canvas.height else {
return
}
let count = views.count let count = views.count
guard 0 < count else { guard 0 < count else {
...@@ -224,14 +211,6 @@ public class Grid { ...@@ -224,14 +211,6 @@ public class Grid {
var i = 0 var i = 0
for v in views { for v in views {
guard let canvas = context else {
return
}
guard 0 < canvas.width && 0 < canvas.height else {
return
}
if canvas != v.superview { if canvas != v.superview {
v.removeFromSuperview() v.removeFromSuperview()
canvas.addSubview(v) canvas.addSubview(v)
......
...@@ -36,11 +36,11 @@ ...@@ -36,11 +36,11 @@
- Returns: The associated reference for the initializer object. - Returns: The associated reference for the initializer object.
*/ */
internal func AssociatedObject<T: Any>(base: Any, key: UnsafePointer<UInt8>, initializer: () -> T) -> T { internal func AssociatedObject<T: Any>(base: Any, key: UnsafePointer<UInt8>, initializer: () -> T) -> T {
if let v: T = objc_getAssociatedObject(base, key) as? T { if let v = objc_getAssociatedObject(base, key) as? T {
return v return v
} }
let v: T = initializer() let v = initializer()
objc_setAssociatedObject(base, key, v, .OBJC_ASSOCIATION_RETAIN) objc_setAssociatedObject(base, key, v, .OBJC_ASSOCIATION_RETAIN)
return v return v
} }
......
...@@ -103,7 +103,7 @@ open class PageTabBarController: RootController { ...@@ -103,7 +103,7 @@ open class PageTabBarController: RootController {
/// Reference to the PageTabBar. /// Reference to the PageTabBar.
open private(set) lazy var pageTabBar: PageTabBar = PageTabBar() open private(set) lazy var pageTabBar: PageTabBar = PageTabBar()
/// A boolean that indicates whether bounds is enabled. /// A boolean that indicates whether bounce is enabled.
open var isBounceEnabled: Bool { open var isBounceEnabled: Bool {
didSet { didSet {
scrollView?.bounces = isBounceEnabled scrollView?.bounces = isBounceEnabled
......
...@@ -103,12 +103,28 @@ open class TextField: UITextField { ...@@ -103,12 +103,28 @@ open class TextField: UITextField {
/// Divider normal height. /// Divider normal height.
@IBInspectable @IBInspectable
open var dividerNormalHeight: CGFloat = 1 open var dividerNormalHeight: CGFloat = 1 {
didSet {
guard !isEditing else {
return
}
dividerThickness = dividerNormalHeight
}
}
/// Divider active height. /// Divider active height.
@IBInspectable @IBInspectable
open var dividerActiveHeight: CGFloat = 2 open var dividerActiveHeight: CGFloat = 2 {
didSet {
guard isEditing else {
return
}
dividerThickness = dividerActiveHeight
}
}
/// Divider normal color. /// Divider normal color.
@IBInspectable @IBInspectable
...@@ -142,22 +158,6 @@ open class TextField: UITextField { ...@@ -142,22 +158,6 @@ open class TextField: UITextField {
} }
} }
/// TextField's text property observer.
@IBInspectable
open override var text: String? {
didSet {
guard isEmpty else {
return
}
guard !isFirstResponder else {
return
}
placeholderEditingDidEndAnimation()
}
}
/// The placeholderLabel text value. /// The placeholderLabel text value.
@IBInspectable @IBInspectable
open override var placeholder: String? { open override var placeholder: String? {
...@@ -387,56 +387,6 @@ open class TextField: UITextField { ...@@ -387,56 +387,6 @@ open class TextField: UITextField {
layoutShape() layoutShape()
} }
/// Handles the text editing did begin state.
@objc
open func handleEditingDidBegin() {
placeholderEditingDidBeginAnimation()
dividerEditingDidBeginAnimation()
}
// Live updates the textField text.
@objc
internal func handleEditingChanged(textField: UITextField) {
(delegate as? TextFieldDelegate)?.textField?(textField: self, didChange: textField.text)
}
/// Handles the text editing did end state.
@objc
open func handleEditingDidEnd() {
placeholderEditingDidEndAnimation()
dividerEditingDidEndAnimation()
}
/// Handles the clearIconButton TouchUpInside event.
@objc
open func handleClearIconButton() {
guard nil == delegate?.textFieldShouldClear || true == delegate?.textFieldShouldClear?(self) else {
return
}
let t = text
(delegate as? TextFieldDelegate)?.textField?(textField: self, willClear: t)
text = nil
(delegate as? TextFieldDelegate)?.textField?(textField: self, didClear: t)
}
/// Handles the visibilityIconButton TouchUpInside event.
@objc
open func handleVisibilityIconButton() {
isSecureTextEntry = !isSecureTextEntry
if !isSecureTextEntry {
super.font = nil
font = placeholderLabel.font
}
visibilityIconButton?.tintColor = visibilityIconButton?.tintColor.withAlphaComponent(isSecureTextEntry ? 0.38 : 0.54)
}
/** /**
Prepares the view instance when intialized. When subclassing, Prepares the view instance when intialized. When subclassing,
...@@ -450,7 +400,8 @@ open class TextField: UITextField { ...@@ -450,7 +400,8 @@ open class TextField: UITextField {
borderStyle = .none borderStyle = .none
backgroundColor = nil backgroundColor = nil
contentScaleFactor = Device.scale contentScaleFactor = Device.scale
prepareDivider()
prepareDivider()
preparePlaceholderLabel() preparePlaceholderLabel()
prepareDetailLabel() prepareDetailLabel()
prepareTargetHandlers() prepareTargetHandlers()
...@@ -459,11 +410,7 @@ open class TextField: UITextField { ...@@ -459,11 +410,7 @@ open class TextField: UITextField {
/// Ensures that the components are sized correctly. /// Ensures that the components are sized correctly.
open func reload() { open func reload() {
guard willLayout else { guard willLayout && !isAnimating else {
return
}
guard !isAnimating else {
return return
} }
...@@ -474,9 +421,62 @@ open class TextField: UITextField { ...@@ -474,9 +421,62 @@ open class TextField: UITextField {
layoutDivider() layoutDivider()
layoutLeftView() layoutLeftView()
} }
}
/// Layout the placeholderLabel.
open func layoutPlaceholderLabel() { extension TextField {
/// Prepares the divider.
fileprivate func prepareDivider() {
dividerColor = dividerNormalColor
}
/// Prepares the placeholderLabel.
fileprivate func preparePlaceholderLabel() {
font = RobotoFont.regular(with: 16)
placeholderNormalColor = Color.darkText.others
addSubview(placeholderLabel)
addObserver(self, forKeyPath: "placeholderLabel.text", options: [], context: &TextFieldContext)
}
/// Prepares the detailLabel.
fileprivate func prepareDetailLabel() {
detailLabel.font = RobotoFont.regular(with: 12)
detailLabel.numberOfLines = 0
detailColor = Color.darkText.others
addSubview(detailLabel)
addObserver(self, forKeyPath: "detailLabel.text", options: [], context: &TextFieldContext)
}
/// Prepares the leftView.
fileprivate func prepareLeftView() {
leftView?.contentMode = .left
}
/// Prepares the target handlers.
fileprivate func prepareTargetHandlers() {
addTarget(self, action: #selector(handleEditingDidBegin), for: .editingDidBegin)
addTarget(self, action: #selector(handleEditingChanged), for: .editingChanged)
addTarget(self, action: #selector(handleEditingDidEnd), for: .editingDidEnd)
}
/// Prepares the textAlignment.
fileprivate func prepareTextAlignment() {
textAlignment = .rightToLeft == UIApplication.shared.userInterfaceLayoutDirection ? .right : .left
}
/// Updates the placeholderLabel attributedText.
fileprivate func updatePlaceholderLabelColor() {
placeholderLabel.textColor = isEditing ? placeholderActiveColor : placeholderNormalColor
}
/// Updates the detailLabel attributedText.
fileprivate func updateDetailLabelColor() {
detailLabel.textColor = detailColor
}
}
extension TextField {
/// Layout the placeholderLabel.
fileprivate func layoutPlaceholderLabel() {
let w = leftViewWidth let w = leftViewWidth
let h = 0 == height ? intrinsicContentSize.height : height let h = 0 == height ? intrinsicContentSize.height : height
...@@ -498,33 +498,33 @@ open class TextField: UITextField { ...@@ -498,33 +498,33 @@ open class TextField: UITextField {
} }
placeholderLabel.y = -placeholderLabel.height + placeholderVerticalOffset placeholderLabel.y = -placeholderLabel.height + placeholderVerticalOffset
} }
/// Layout the detailLabel. /// Layout the detailLabel.
open func layoutDetailLabel() { fileprivate func layoutDetailLabel() {
let c = dividerContentEdgeInsets let c = dividerContentEdgeInsets
detailLabel.sizeToFit() detailLabel.sizeToFit()
detailLabel.x = c.left detailLabel.x = c.left
detailLabel.y = height + detailVerticalOffset detailLabel.y = height + detailVerticalOffset
detailLabel.width = width - c.left - c.right detailLabel.width = width - c.left - c.right
} }
/// Layout the a button. /// Layout the a button.
open func layoutButton(button: UIButton?) { fileprivate func layoutButton(button: UIButton?) {
guard 0 < width && 0 < height else { guard 0 < width && 0 < height else {
return return
} }
button?.frame = CGRect(x: width - height, y: 0, width: height, height: height) button?.frame = CGRect(x: width - height, y: 0, width: height, height: height)
} }
/// Layout the divider. /// Layout the divider.
open func layoutDivider() { fileprivate func layoutDivider() {
divider.reload() divider.reload()
} }
/// Layout the leftView. /// Layout the leftView.
open func layoutLeftView() { fileprivate func layoutLeftView() {
guard let v = leftView else { guard let v = leftView else {
return return
} }
...@@ -533,21 +533,77 @@ open class TextField: UITextField { ...@@ -533,21 +533,77 @@ open class TextField: UITextField {
v.frame = CGRect(x: 0, y: 0, width: w, height: height) v.frame = CGRect(x: 0, y: 0, width: w, height: height)
dividerContentEdgeInsets.left = w dividerContentEdgeInsets.left = w
} }
}
/// The animation for the divider when editing begins.
open func dividerEditingDidBeginAnimation() { extension TextField {
dividerThickness = dividerActiveHeight /// Handles the text editing did begin state.
dividerColor = dividerActiveColor @objc
fileprivate func handleEditingDidBegin() {
placeholderEditingDidBeginAnimation()
dividerEditingDidBeginAnimation()
} }
/// The animation for the divider when editing ends. // Live updates the textField text.
open func dividerEditingDidEndAnimation() { @objc
dividerThickness = dividerNormalHeight fileprivate func handleEditingChanged(textField: UITextField) {
dividerColor = dividerNormalColor (delegate as? TextFieldDelegate)?.textField?(textField: self, didChange: textField.text)
} }
/// The animation for the placeholder when editing begins. /// Handles the text editing did end state.
open func placeholderEditingDidBeginAnimation() { @objc
fileprivate func handleEditingDidEnd() {
placeholderEditingDidEndAnimation()
dividerEditingDidEndAnimation()
}
/// Handles the clearIconButton TouchUpInside event.
@objc
fileprivate func handleClearIconButton() {
guard nil == delegate?.textFieldShouldClear || true == delegate?.textFieldShouldClear?(self) else {
return
}
let t = text
(delegate as? TextFieldDelegate)?.textField?(textField: self, willClear: t)
text = nil
(delegate as? TextFieldDelegate)?.textField?(textField: self, didClear: t)
}
/// Handles the visibilityIconButton TouchUpInside event.
@objc
fileprivate func handleVisibilityIconButton() {
isSecureTextEntry = !isSecureTextEntry
if !isSecureTextEntry {
super.font = nil
font = placeholderLabel.font
}
visibilityIconButton?.tintColor = visibilityIconButton?.tintColor.withAlphaComponent(isSecureTextEntry ? 0.38 : 0.54)
}
}
extension TextField {
/// The animation for the divider when editing begins.
fileprivate func dividerEditingDidBeginAnimation() {
dividerThickness = dividerActiveHeight
dividerColor = dividerActiveColor
}
/// The animation for the divider when editing ends.
fileprivate func dividerEditingDidEndAnimation() {
dividerThickness = dividerNormalHeight
dividerColor = dividerNormalColor
}
/// The animation for the placeholder when editing begins.
fileprivate func placeholderEditingDidBeginAnimation() {
updatePlaceholderLabelColor()
guard isPlaceholderAnimated else { guard isPlaceholderAnimated else {
return return
} }
...@@ -576,10 +632,12 @@ open class TextField: UITextField { ...@@ -576,10 +632,12 @@ open class TextField: UITextField {
}) { [weak self] _ in }) { [weak self] _ in
self?.isAnimating = false self?.isAnimating = false
} }
} }
/// The animation for the placeholder when editing ends. /// The animation for the placeholder when editing ends.
open func placeholderEditingDidEndAnimation() { fileprivate func placeholderEditingDidEndAnimation() {
updatePlaceholderLabelColor()
guard isPlaceholderAnimated else { guard isPlaceholderAnimated else {
return return
} }
...@@ -597,66 +655,8 @@ open class TextField: UITextField { ...@@ -597,66 +655,8 @@ open class TextField: UITextField {
s.placeholderLabel.transform = CGAffineTransform.identity s.placeholderLabel.transform = CGAffineTransform.identity
s.placeholderLabel.x = s.leftViewWidth s.placeholderLabel.x = s.leftViewWidth
s.placeholderLabel.y = 0 s.placeholderLabel.y = 0
s.placeholderLabel.textColor = s.placeholderNormalColor
}) { [weak self] _ in }) { [weak self] _ in
self?.isAnimating = false self?.isAnimating = false
} }
}
/// Prepares the divider.
private func prepareDivider() {
dividerColor = dividerNormalColor
}
/// Prepares the placeholderLabel.
private func preparePlaceholderLabel() {
font = RobotoFont.regular(with: 16)
placeholderNormalColor = Color.darkText.others
addSubview(placeholderLabel)
addObserver(self, forKeyPath: "placeholderLabel.text", options: [], context: &TextFieldContext)
}
/// Prepares the detailLabel.
private func prepareDetailLabel() {
detailLabel.font = RobotoFont.regular(with: 12)
detailLabel.numberOfLines = 0
detailColor = Color.darkText.others
addSubview(detailLabel)
addObserver(self, forKeyPath: "detailLabel.text", options: [], context: &TextFieldContext)
}
/// Prepares the leftView.
private func prepareLeftView() {
leftView?.contentMode = .left
}
/// Prepares the target handlers.
private func prepareTargetHandlers() {
addTarget(self, action: #selector(handleEditingDidBegin), for: .editingDidBegin)
addTarget(self, action: #selector(handleEditingChanged), for: .editingChanged)
addTarget(self, action: #selector(handleEditingDidEnd), for: .editingDidEnd)
}
/// Prepares the textAlignment.
private func prepareTextAlignment() {
textAlignment = .rightToLeft == UIApplication.shared.userInterfaceLayoutDirection ? .right : .left
}
/// Updates the placeholderLabel attributedText.
private func updatePlaceholderLabelColor() {
guard let v = placeholder else {
return
}
placeholderLabel.attributedText = NSAttributedString(string: v, attributes: [NSForegroundColorAttributeName: isEditing ? placeholderActiveColor : placeholderNormalColor])
}
/// Updates the detailLabel attributedText.
private func updateDetailLabelColor() {
guard let v = detail else {
return
}
detailLabel.attributedText = NSAttributedString(string: v, attributes: [NSForegroundColorAttributeName: detailColor])
} }
} }
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