added StatefulButton & RoundedStatefulButton.
added CACornerMask rounding extension. added UIControl.State dictionary extensions. added UIFont registration. reworked BaseTextAttributes & ViewText. removed ViewTextConfigurable.
This commit is contained in:
parent
f3fe5e08d8
commit
102c15ca07
|
|
@ -1,5 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
### 0.12.0
|
||||
- **Add**: StatefulButton & RoundedStatefulButton to TIUIElements.
|
||||
- **Add**: added CACornerMask rounding extension to TIUIElements.
|
||||
- **Add**: UIControl.State dictionary extensions to TIUIKitCore.
|
||||
- **Add**: UIFont and CTFont extensions to TIUIKitCore.
|
||||
- **Breaking change**: reworked BaseTextAttributes & ViewText. Removed ViewTextConfigurable protocol & conformances.
|
||||
|
||||
### 0.11.0
|
||||
- **Add**: Cocoapods support for TI-family libraries.
|
||||
- **Add**: `SeparatorConfigurable` and all helper types for separator configuration.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ let package = Package(
|
|||
.target(name: "TIUIKitCore", path: "TIUIKitCore/Sources"),
|
||||
.target(name: "TISwiftUtils", path: "TISwiftUtils/Sources"),
|
||||
.target(name: "TIFoundationUtils", dependencies: ["TISwiftUtils"], path: "TIFoundationUtils/Sources"),
|
||||
.target(name: "TIUIElements", dependencies: ["TIUIKitCore"], path: "TIUIElements/Sources"),
|
||||
.target(name: "TIUIElements", dependencies: ["TIUIKitCore", "TISwiftUtils"], path: "TIUIElements/Sources"),
|
||||
.target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"),
|
||||
.target(name: "OTPSwiftView", dependencies: ["TIUIKitCore", "TISwiftUtils"], path: "OTPSwiftView/Sources")
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIFoundationUtils'
|
||||
s.version = '0.11.0'
|
||||
s.version = '0.12.0'
|
||||
s.summary = 'Set of helpers for Foundation framework classes.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TISwiftUtils'
|
||||
s.version = '0.11.0'
|
||||
s.version = '0.12.0'
|
||||
s.summary = 'Bunch of useful helpers for Swift development.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TITableKitUtils'
|
||||
s.version = '0.11.0'
|
||||
s.version = '0.12.0'
|
||||
s.summary = 'Set of helpers for TableKit classes.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -20,25 +20,23 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import UIKit.UITextField
|
||||
import QuartzCore
|
||||
|
||||
extension UITextField: ViewTextConfigurable {
|
||||
|
||||
public var textFont: UIFont? {
|
||||
get {
|
||||
return font
|
||||
}
|
||||
set {
|
||||
font = newValue
|
||||
}
|
||||
public extension CACornerMask {
|
||||
static var topCorners: Self {
|
||||
[.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||||
}
|
||||
|
||||
public var titleColor: UIColor? {
|
||||
get {
|
||||
return textColor
|
||||
}
|
||||
set {
|
||||
textColor = newValue
|
||||
}
|
||||
static var bottomCorners: Self {
|
||||
[.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
||||
}
|
||||
|
||||
static var allCorners: Self {
|
||||
[
|
||||
.layerMinXMinYCorner,
|
||||
.layerMaxXMinYCorner,
|
||||
.layerMinXMaxYCorner,
|
||||
.layerMaxXMaxYCorner
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -20,25 +20,17 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import UIKit.UILabel
|
||||
import QuartzCore
|
||||
|
||||
extension UILabel: ViewTextConfigurable {
|
||||
|
||||
public var textFont: UIFont? {
|
||||
get {
|
||||
return font
|
||||
}
|
||||
set {
|
||||
font = newValue
|
||||
}
|
||||
public extension CALayer {
|
||||
func round(corners: CACornerMask) {
|
||||
masksToBounds = true
|
||||
maskedCorners = corners
|
||||
}
|
||||
|
||||
public var titleColor: UIColor? {
|
||||
get {
|
||||
return textColor
|
||||
}
|
||||
set {
|
||||
textColor = newValue
|
||||
}
|
||||
func round(corners: CACornerMask, radius: CGFloat) {
|
||||
round(corners: corners)
|
||||
|
||||
cornerRadius = radius
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +74,7 @@ open class BaseSeparatorCell: BaseInitializableCell, SeparatorConfigurable {
|
|||
|
||||
open override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
|
||||
configureSeparators(with: .none)
|
||||
}
|
||||
|
||||
|
|
@ -131,17 +132,21 @@ open class BaseSeparatorCell: BaseInitializableCell, SeparatorConfigurable {
|
|||
private extension BaseSeparatorCell {
|
||||
func updateTopSeparator(with configuration: SeparatorConfiguration) {
|
||||
topSeparatorView.backgroundColor = configuration.color
|
||||
|
||||
topViewHeightConstraint?.constant = configuration.height
|
||||
|
||||
topViewTopConstraint?.constant = configuration.insets.top
|
||||
topViewLeftConstraint?.constant = configuration.insets.left
|
||||
topViewRightConstraint?.constant = -configuration.insets.right
|
||||
topViewRightConstraint?.constant = configuration.insets.right
|
||||
}
|
||||
|
||||
func updateBottomSeparator(with configuration: SeparatorConfiguration) {
|
||||
bottomSeparatorView.backgroundColor = configuration.color
|
||||
|
||||
bottomViewHeightConstraint?.constant = configuration.height
|
||||
bottomViewBottomConstraint?.constant = -configuration.insets.bottom
|
||||
|
||||
bottomViewBottomConstraint?.constant = configuration.insets.bottom
|
||||
bottomViewLeftConstraint?.constant = configuration.insets.left
|
||||
bottomViewRightConstraint?.constant = -configuration.insets.right
|
||||
bottomViewRightConstraint?.constant = configuration.insets.right
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,25 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit
|
||||
import TIUIKitCore
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit
|
||||
|
||||
open class RoundedStatefulButton: StatefulButton {
|
||||
|
||||
// UIView override
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
configureAppearance()
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
|
||||
configureAppearance()
|
||||
}
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
layer.cornerRadius = calculateCornerRadius(for: bounds)
|
||||
}
|
||||
|
||||
// MARK: - Open methods
|
||||
|
||||
open func configureAppearance() {
|
||||
layer.round(corners: .allCorners)
|
||||
}
|
||||
|
||||
open func calculateCornerRadius(for bounds: CGRect) -> CGFloat {
|
||||
min(bounds.width, bounds.height) / 2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 TISwiftUtils
|
||||
import TIUIKitCore
|
||||
import UIKit
|
||||
|
||||
open class StatefulButton: UIButton {
|
||||
|
||||
public enum ActivityIndicatorPosition {
|
||||
case center
|
||||
case before(view: UIView, offset: CGFloat)
|
||||
case after(view: UIView, offset: CGFloat)
|
||||
|
||||
var offset: CGFloat {
|
||||
switch self {
|
||||
case .center:
|
||||
return .zero
|
||||
|
||||
case let .before(_, offset), let .after(_, offset):
|
||||
return offset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public typealias StateEventPropagations = [State: Bool]
|
||||
|
||||
private var activityIndicator: ActivityIndicator? {
|
||||
willSet {
|
||||
activityIndicator?.removeFromSuperview()
|
||||
}
|
||||
didSet {
|
||||
if let activityIndicator = activityIndicator {
|
||||
addSubview(activityIndicator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var isLoading = false {
|
||||
didSet {
|
||||
isLoading
|
||||
? activityIndicator?.startAnimating()
|
||||
: activityIndicator?.stopAnimating()
|
||||
|
||||
isEnabled = !isLoading
|
||||
}
|
||||
}
|
||||
|
||||
public var additionalHitTestMargins: UIEdgeInsets = .zero
|
||||
|
||||
public var onDisabledStateTapHandler: VoidClosure?
|
||||
|
||||
var eventPropagations: StateEventPropagations = [:]
|
||||
|
||||
// MARK: - Background
|
||||
|
||||
private var backgroundColors: StateColors = [:] {
|
||||
didSet {
|
||||
updateBackgroundColor()
|
||||
}
|
||||
}
|
||||
|
||||
public func set(backgroundColors: StateColors) {
|
||||
backgroundColors.forEach { setBackgroundColor($1, for: $0) }
|
||||
}
|
||||
|
||||
public func setBackgroundColor(_ color: UIColor?, for state: State) {
|
||||
backgroundColors[state] = color
|
||||
}
|
||||
|
||||
public func backgroundColor(for state: State) -> UIColor? {
|
||||
// Value of optional type 'UIColor??' must be unwrapped to a value of type 'UIColor?'
|
||||
// 🤷 Swift 5.3 (Xcode 12.2)
|
||||
backgroundColors[state] ?? nil //swiftlint:disable:this redundant_nil_coalescing
|
||||
}
|
||||
|
||||
public func setEventPropagation(_ eventPropagation: Bool, for state: State) {
|
||||
eventPropagations[state] = eventPropagation
|
||||
}
|
||||
|
||||
// MARK: - UIControl override
|
||||
|
||||
override open var isEnabled: Bool {
|
||||
didSet {
|
||||
updateBackgroundColor()
|
||||
}
|
||||
}
|
||||
|
||||
override open var isHighlighted: Bool {
|
||||
didSet {
|
||||
updateBackgroundColor()
|
||||
}
|
||||
}
|
||||
|
||||
open override var isSelected: Bool {
|
||||
didSet {
|
||||
updateBackgroundColor()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIView override
|
||||
|
||||
open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
||||
let insetBounds = CGRect(x: bounds.minX - additionalHitTestMargins.left,
|
||||
y: bounds.minY - additionalHitTestMargins.top,
|
||||
width: bounds.width + additionalHitTestMargins.right,
|
||||
height: bounds.height + additionalHitTestMargins.bottom)
|
||||
|
||||
return super.point(inside: point, with: event)
|
||||
|| insetBounds.contains(point)
|
||||
}
|
||||
|
||||
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let pointInsideView = self.point(inside: point, with: event)
|
||||
|
||||
// hitTest called multiple times, but we need only one
|
||||
// so the current solution is to pick a final call with nil event
|
||||
|
||||
if !isEnabled && pointInsideView && event == nil {
|
||||
onDisabledStateTapHandler?()
|
||||
}
|
||||
|
||||
let touchEventReceiver = super.hitTest(point, with: event)
|
||||
|
||||
let shouldPropagateEvent = eventPropagations[state] ?? true
|
||||
|
||||
if pointInsideView && touchEventReceiver == nil && !shouldPropagateEvent {
|
||||
return self // disable propagation
|
||||
}
|
||||
|
||||
return touchEventReceiver
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
public func configure(activityIndicator: ActivityIndicator,
|
||||
at position: ActivityIndicatorPosition) {
|
||||
|
||||
self.activityIndicator = activityIndicator
|
||||
|
||||
let titleInset = activityIndicator.intrinsicContentSize.width + position.offset
|
||||
|
||||
switch position {
|
||||
case .center:
|
||||
titleEdgeInsets = .zero
|
||||
|
||||
case .before:
|
||||
titleEdgeInsets = UIEdgeInsets(top: .zero,
|
||||
left: titleInset,
|
||||
bottom: .zero,
|
||||
right: .zero)
|
||||
|
||||
case .after:
|
||||
titleEdgeInsets = UIEdgeInsets(top: .zero,
|
||||
left: .zero,
|
||||
bottom: .zero,
|
||||
right: titleInset)
|
||||
}
|
||||
|
||||
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate(constraints(for: activityIndicator,
|
||||
at: position))
|
||||
}
|
||||
|
||||
private func constraints(for activityIndicator: ActivityIndicator,
|
||||
at position: ActivityIndicatorPosition) -> [NSLayoutConstraint] {
|
||||
switch position {
|
||||
case .center:
|
||||
return [
|
||||
activityIndicator.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||
activityIndicator.centerYAnchor.constraint(equalTo: centerYAnchor)
|
||||
]
|
||||
|
||||
case let .before(view, offset):
|
||||
return [
|
||||
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||
activityIndicator.trailingAnchor.constraint(equalTo: view.leadingAnchor, constant: -offset)
|
||||
]
|
||||
|
||||
case let .after(view, offset):
|
||||
return [
|
||||
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||
activityIndicator.leadingAnchor.constraint(equalTo: view.trailingAnchor, constant: offset)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func updateBackgroundColor() {
|
||||
if isEnabled {
|
||||
if isHighlighted {
|
||||
updateBackgroundColor(to: .highlighted)
|
||||
} else {
|
||||
updateBackgroundColor(to: .normal)
|
||||
}
|
||||
} else {
|
||||
updateBackgroundColor(to: .disabled)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateBackgroundColor(to state: State) {
|
||||
if let stateColor = backgroundColor(for: state) {
|
||||
backgroundColor = stateColor
|
||||
} else if state != .normal, let normalStateColor = backgroundColor(for: .normal) {
|
||||
backgroundColor = normalStateColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIUIElements'
|
||||
s.version = '0.11.0'
|
||||
s.version = '0.12.0'
|
||||
s.summary = 'Bunch of useful protocols and views.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
@ -13,4 +13,5 @@ Pod::Spec.new do |s|
|
|||
s.source_files = s.name + '/Sources/**/*'
|
||||
|
||||
s.dependency 'TIUIKitCore', s.version.to_s
|
||||
s.dependency 'TISwiftUtils', s.version.to_s
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 CoreGraphics
|
||||
import CoreText
|
||||
import Foundation
|
||||
|
||||
public extension CTFont {
|
||||
enum FontRegistrationError: Error {
|
||||
case fontsNotFound
|
||||
case unableToCreateCGFontFromData
|
||||
case unableToRegisterFont(CFError)
|
||||
case unknown
|
||||
}
|
||||
|
||||
static func registerFont(at url: URL) throws {
|
||||
let fontData = try Data(contentsOf: url)
|
||||
|
||||
guard let dataProvider = CGDataProvider(data: fontData as CFData),
|
||||
let font = CGFont(dataProvider) else {
|
||||
throw FontRegistrationError.unableToCreateCGFontFromData
|
||||
}
|
||||
|
||||
var errorRef: Unmanaged<CFError>?
|
||||
let registrationWasSuccessful = CTFontManagerRegisterGraphicsFont(font, &errorRef)
|
||||
|
||||
if registrationWasSuccessful {
|
||||
return
|
||||
} else if let error = errorRef?.takeRetainedValue() {
|
||||
if CFErrorGetCode(error) != CTFontManagerError.alreadyRegistered.rawValue {
|
||||
throw FontRegistrationError.unableToRegisterFont(error)
|
||||
} else {
|
||||
return // it's okay, font is already registered
|
||||
}
|
||||
} else {
|
||||
throw FontRegistrationError.unknown
|
||||
}
|
||||
}
|
||||
|
||||
static func registerAllFonts(in bundle: Bundle) throws {
|
||||
guard let fontUrls = bundle.urls(forResourcesWithExtension: "woff2", subdirectory: nil),
|
||||
!fontUrls.isEmpty else {
|
||||
throw FontRegistrationError.fontsNotFound
|
||||
}
|
||||
|
||||
try fontUrls.forEach {
|
||||
try registerFont(at: $0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit.UIButton
|
||||
|
||||
public extension UIButton {
|
||||
func set(titleColors: StateColors) {
|
||||
titleColors.forEach { setTitleColor($1, for: $0) }
|
||||
}
|
||||
|
||||
func set(titles: StateTitles) {
|
||||
titles.forEach { setTitle($1, for: $0) }
|
||||
}
|
||||
|
||||
func set(attributtedTitles: StateAttributedTitles) {
|
||||
attributtedTitles.forEach { setAttributedTitle($1, for: $0) }
|
||||
}
|
||||
|
||||
// MARK: - Images
|
||||
|
||||
func set(images: StateImages) {
|
||||
images.forEach { setImage($1, for: $0) }
|
||||
}
|
||||
|
||||
func set(backgroundImages: StateImages) {
|
||||
backgroundImages.forEach { setBackgroundImage($1, for: $0) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit.UIControl
|
||||
|
||||
extension UIControl.State: Hashable {
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(Int(rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
public extension UIControl {
|
||||
typealias StateColors = [UIControl.State: UIColor?]
|
||||
typealias StateImages = [UIControl.State: UIImage?]
|
||||
typealias StateTitles = [UIControl.State: String?]
|
||||
typealias StateAttributedTitles = [UIControl.State: NSAttributedString?]
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit.UIFont
|
||||
|
||||
public extension UIFont {
|
||||
convenience init(fontFamily: String, fontFace: String, size: CGFloat) {
|
||||
let fontDescriptor = UIFontDescriptor(fontAttributes: [
|
||||
UIFontDescriptor.AttributeName.size: size,
|
||||
UIFontDescriptor.AttributeName.family: fontFamily,
|
||||
UIFontDescriptor.AttributeName.face: fontFace
|
||||
])
|
||||
|
||||
self.init(descriptor: fontDescriptor, size: size)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit.UIFont
|
||||
import UIKit.UIColor
|
||||
|
||||
/// Base set of attributes to configure appearance of text.
|
||||
open class BaseTextAttributes {
|
||||
|
||||
/// Text font.
|
||||
public let font: UIFont
|
||||
/// Text color.
|
||||
public let color: UIColor
|
||||
/// Text alignment.
|
||||
public let alignment: NSTextAlignment
|
||||
/// Paragraph line height.
|
||||
public let lineHeightMultiple: CGFloat
|
||||
/// Number of lines for labels.
|
||||
public let numberOfLines: Int
|
||||
|
||||
public init(font: UIFont,
|
||||
color: UIColor,
|
||||
alignment: NSTextAlignment,
|
||||
lineHeightMultiple: CGFloat,
|
||||
numberOfLines: Int) {
|
||||
self.font = font
|
||||
self.color = color
|
||||
self.alignment = alignment
|
||||
self.lineHeightMultiple = lineHeightMultiple
|
||||
self.numberOfLines = numberOfLines
|
||||
}
|
||||
|
||||
private func configure<T: BaseTextAttributesConfigurable>(textContainer: T) {
|
||||
textContainer.set(font: font)
|
||||
textContainer.set(color: color)
|
||||
textContainer.set(alignment: alignment)
|
||||
}
|
||||
|
||||
open func configure(label: UILabel) {
|
||||
configure(textContainer: label)
|
||||
|
||||
label.numberOfLines = numberOfLines
|
||||
}
|
||||
|
||||
open func configure(textField: UITextField) {
|
||||
configure(textContainer: textField)
|
||||
}
|
||||
|
||||
open func configure(button: UIButton, for state: UIControl.State) {
|
||||
if let buttonLabel = button.titleLabel {
|
||||
configure(label: buttonLabel)
|
||||
}
|
||||
|
||||
button.setTitleColor(color, for: state)
|
||||
}
|
||||
|
||||
private func configure<T>(textContainer: T,
|
||||
with string: String?,
|
||||
appearanceConfiguration: (T) -> Void,
|
||||
textConfiguration: (String?) -> Void,
|
||||
attributedTextConfiguration: (NSAttributedString?) -> Void) {
|
||||
if lineHeightMultiple == 1.0 { // default
|
||||
appearanceConfiguration(textContainer)
|
||||
|
||||
textConfiguration(string)
|
||||
} else {
|
||||
let resultAttributedString: NSAttributedString?
|
||||
|
||||
if let string = string {
|
||||
resultAttributedString = attributedString(for: string)
|
||||
} else {
|
||||
resultAttributedString = nil
|
||||
}
|
||||
|
||||
attributedTextConfiguration(resultAttributedString)
|
||||
}
|
||||
}
|
||||
|
||||
open func configure(label: UILabel, with string: String?) {
|
||||
configure(textContainer: label,
|
||||
with: string,
|
||||
appearanceConfiguration: configure(label:),
|
||||
textConfiguration: { label.text = $0 },
|
||||
attributedTextConfiguration: {
|
||||
label.attributedText = $0
|
||||
label.numberOfLines = numberOfLines
|
||||
})
|
||||
}
|
||||
|
||||
open func configure(textField: UITextField, with string: String?) {
|
||||
configure(textContainer: textField,
|
||||
with: string,
|
||||
appearanceConfiguration: configure(textField:),
|
||||
textConfiguration: { textField.text = $0 },
|
||||
attributedTextConfiguration: { textField.attributedText = $0 })
|
||||
}
|
||||
|
||||
open func configure(button: UIButton, with string: String?, for state: UIControl.State) {
|
||||
configure(textContainer: button,
|
||||
with: string,
|
||||
appearanceConfiguration: { configure(button: $0, for: state) },
|
||||
textConfiguration: { button.setTitle($0, for: state) },
|
||||
attributedTextConfiguration: {
|
||||
button.setAttributedTitle($0, for: state)
|
||||
button.titleLabel?.numberOfLines = numberOfLines
|
||||
})
|
||||
}
|
||||
|
||||
open func attributedString(for string: String) -> NSAttributedString {
|
||||
let paragraphStyle = NSMutableParagraphStyle()
|
||||
paragraphStyle.alignment = alignment
|
||||
paragraphStyle.lineHeightMultiple = lineHeightMultiple
|
||||
|
||||
let attributes: [NSAttributedString.Key: Any] = [
|
||||
.font: font,
|
||||
.foregroundColor: color,
|
||||
.paragraphStyle: paragraphStyle
|
||||
]
|
||||
|
||||
return NSAttributedString(string: string, attributes: attributes)
|
||||
}
|
||||
}
|
||||
|
||||
public extension BaseTextAttributes {
|
||||
typealias FigmaPercent = CGFloat
|
||||
|
||||
convenience init(font: UIFont,
|
||||
color: UIColor,
|
||||
alignment: NSTextAlignment,
|
||||
isMultiline: Bool,
|
||||
lineHeight: FigmaPercent = 100.0) {
|
||||
|
||||
self.init(font: font,
|
||||
color: color,
|
||||
alignment: alignment,
|
||||
lineHeightMultiple: lineHeight / 100.0,
|
||||
numberOfLines: isMultiline ? 0 : 1)
|
||||
}
|
||||
}
|
||||
|
|
@ -20,38 +20,38 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import UIKit.UIFont
|
||||
import UIKit.UIColor
|
||||
import UIKit
|
||||
|
||||
/// Base set of attributes to configure appearance of text.
|
||||
open class BaseTextAttributes {
|
||||
protocol BaseTextAttributesConfigurable {
|
||||
func set(font: UIFont)
|
||||
func set(color: UIColor)
|
||||
func set(alignment: NSTextAlignment)
|
||||
}
|
||||
|
||||
/// Text font.
|
||||
public let font: UIFont
|
||||
/// Text color.
|
||||
public let color: UIColor
|
||||
/// Text alignment.
|
||||
public let alignment: NSTextAlignment
|
||||
|
||||
/// Memberwise initializer.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - font: Text font.
|
||||
/// - color: Text color.
|
||||
/// - alignment: Text alignment.
|
||||
public init(font: UIFont, color: UIColor, alignment: NSTextAlignment = .natural) {
|
||||
extension UILabel: BaseTextAttributesConfigurable {
|
||||
public func set(font: UIFont) {
|
||||
self.font = font
|
||||
self.color = color
|
||||
self.alignment = alignment
|
||||
}
|
||||
|
||||
public func set(color: UIColor) {
|
||||
self.textColor = color
|
||||
}
|
||||
|
||||
public func set(alignment: NSTextAlignment) {
|
||||
self.textAlignment = alignment
|
||||
}
|
||||
}
|
||||
|
||||
public extension BaseTextAttributes {
|
||||
extension UITextField: BaseTextAttributesConfigurable {
|
||||
public func set(font: UIFont) {
|
||||
self.font = font
|
||||
}
|
||||
|
||||
/// Configures text appearance of given ViewTextConfigurable instance.
|
||||
///
|
||||
/// - Parameter view: ViewTextConfigurable instance to configure with BaseTextAttributes.
|
||||
func configureBaseApperance(of view: ViewTextConfigurable) {
|
||||
view.configureBaseAppearance(with: self)
|
||||
public func set(color: UIColor) {
|
||||
self.textColor = color
|
||||
}
|
||||
|
||||
public func set(alignment: NSTextAlignment) {
|
||||
self.textAlignment = alignment
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit
|
||||
|
||||
public struct ViewText {
|
||||
public let text: String?
|
||||
public let attributes: BaseTextAttributes
|
||||
|
||||
public init(text: String?, attributes: BaseTextAttributes) {
|
||||
self.text = text
|
||||
self.attributes = attributes
|
||||
}
|
||||
|
||||
public init(string: String,
|
||||
font: UIFont,
|
||||
color: UIColor,
|
||||
alignment: NSTextAlignment = .natural,
|
||||
lineHeightMultiple: CGFloat = 1.0,
|
||||
numberOfLines: Int = 1) {
|
||||
|
||||
text = string
|
||||
attributes = BaseTextAttributes(font: font,
|
||||
color: color,
|
||||
alignment: alignment,
|
||||
lineHeightMultiple: lineHeightMultiple,
|
||||
numberOfLines: numberOfLines)
|
||||
}
|
||||
|
||||
public func size(maxWidth: CGFloat = .greatestFiniteMagnitude,
|
||||
maxHeight: CGFloat = .greatestFiniteMagnitude) -> CGSize {
|
||||
|
||||
guard let text = text else {
|
||||
return .zero
|
||||
}
|
||||
|
||||
let attributedString = attributes.attributedString(for: text)
|
||||
|
||||
return attributedString.boundingRect(with: CGSize(width: maxWidth, height: maxHeight),
|
||||
options: [.usesLineFragmentOrigin, .usesFontLeading],
|
||||
context: nil).size
|
||||
}
|
||||
|
||||
public func configure(label: UILabel) {
|
||||
attributes.configure(label: label, with: text)
|
||||
}
|
||||
|
||||
public func configure(textField: UITextField) {
|
||||
attributes.configure(textField: textField, with: text)
|
||||
}
|
||||
|
||||
public func configure(button: UIButton, for state: UIControl.State) {
|
||||
attributes.configure(button: button, with: text, for: state)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit
|
||||
|
||||
/// Enum that describes text with appearance options.
|
||||
///
|
||||
/// - string: Regular string with common and often-used text attributes.
|
||||
/// - attributedString: Attributed string.
|
||||
public enum ViewText {
|
||||
|
||||
case string(String, textAttributes: BaseTextAttributes)
|
||||
case attributedString(NSAttributedString)
|
||||
}
|
||||
|
||||
public extension ViewText {
|
||||
|
||||
/// Convenient initializer for .string case with default alignment parameter.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - string: Text to use.
|
||||
/// - font: Font to use.
|
||||
/// - color: Color to use.
|
||||
/// - alignment: Alignment to use. Default is natural.
|
||||
init(string: String, font: UIFont, color: UIColor, alignment: NSTextAlignment = .natural) {
|
||||
self = .string(string, textAttributes: BaseTextAttributes(font: font,
|
||||
color: color,
|
||||
alignment: alignment))
|
||||
}
|
||||
|
||||
/// Attributed string created using text attributes.
|
||||
var attributedString: NSAttributedString {
|
||||
switch self {
|
||||
case let .string(title, textAttributes):
|
||||
|
||||
let paragraphStyle = NSMutableParagraphStyle()
|
||||
paragraphStyle.alignment = textAttributes.alignment
|
||||
|
||||
let attributes: [NSAttributedString.Key: Any] = [
|
||||
.font: textAttributes.font,
|
||||
.foregroundColor: textAttributes.color,
|
||||
.paragraphStyle: paragraphStyle
|
||||
]
|
||||
|
||||
return NSAttributedString(string: title, attributes: attributes)
|
||||
|
||||
case .attributedString(let attributedTitle):
|
||||
return attributedTitle
|
||||
}
|
||||
}
|
||||
|
||||
/// Method that calculates size of view text using given max width and height arguments.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - maxWidth: The width constraint to apply when computing the string’s bounding rectangle.
|
||||
/// - maxHeight: The width constraint to apply when computing the string’s bounding rectangle.
|
||||
/// - Returns: Returns the size required to draw the text.
|
||||
func size(maxWidth: CGFloat = CGFloat.greatestFiniteMagnitude,
|
||||
maxHeight: CGFloat = CGFloat.greatestFiniteMagnitude) -> CGSize {
|
||||
|
||||
return attributedString.boundingRect(with: CGSize(width: maxWidth, height: maxHeight),
|
||||
options: [.usesLineFragmentOrigin, .usesFontLeading],
|
||||
context: nil).size
|
||||
}
|
||||
|
||||
/// Configures given ViewTextConfigurable instance.
|
||||
///
|
||||
/// - Parameter view: ViewTextConfigurable instance to configure with ViewText.
|
||||
func configure(view: ViewTextConfigurable) {
|
||||
view.configure(with: self)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit.UIButton
|
||||
|
||||
extension UIButton: ViewTextConfigurable {
|
||||
|
||||
public var textFont: UIFont? {
|
||||
get {
|
||||
return titleLabel?.font
|
||||
}
|
||||
set {
|
||||
titleLabel?.font = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public var titleColor: UIColor? {
|
||||
get {
|
||||
return currentTitleColor
|
||||
}
|
||||
set {
|
||||
setTitleColor(newValue, for: [])
|
||||
}
|
||||
}
|
||||
|
||||
public var textAlignment: NSTextAlignment {
|
||||
get {
|
||||
return contentHorizontalAlignment.textAlignment
|
||||
}
|
||||
set {
|
||||
contentHorizontalAlignment = .init(textAlignment: newValue)
|
||||
}
|
||||
}
|
||||
|
||||
public var text: String? {
|
||||
get {
|
||||
return currentTitle
|
||||
}
|
||||
set {
|
||||
setTitle(newValue, for: [])
|
||||
}
|
||||
}
|
||||
|
||||
public var attributedText: NSAttributedString? {
|
||||
get {
|
||||
return currentAttributedTitle
|
||||
}
|
||||
set {
|
||||
setAttributedTitle(newValue, for: [])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension UIControl.ContentHorizontalAlignment {
|
||||
|
||||
init(textAlignment: NSTextAlignment) {
|
||||
switch textAlignment {
|
||||
case .left:
|
||||
self = .leading
|
||||
|
||||
case .right:
|
||||
self = .trailing
|
||||
|
||||
case .center:
|
||||
self = .center
|
||||
|
||||
case .justified:
|
||||
self = .fill
|
||||
|
||||
case .natural:
|
||||
self = .leading
|
||||
|
||||
@unknown default:
|
||||
self = .leading
|
||||
}
|
||||
}
|
||||
|
||||
var textAlignment: NSTextAlignment {
|
||||
switch self {
|
||||
case .left:
|
||||
return .left
|
||||
|
||||
case .right:
|
||||
return .right
|
||||
|
||||
case .center:
|
||||
return .center
|
||||
|
||||
case .fill:
|
||||
return .justified
|
||||
|
||||
case .leading:
|
||||
return .natural
|
||||
|
||||
case .trailing:
|
||||
return .right
|
||||
|
||||
@unknown default:
|
||||
return .natural
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2020 Touch Instinct
|
||||
//
|
||||
// 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 UIKit.UIFont
|
||||
import UIKit.UIColor
|
||||
|
||||
/// Protocol that represents text object with appearance attributes.
|
||||
public protocol ViewTextConfigurable: AnyObject {
|
||||
|
||||
/// Font of text object.
|
||||
var textFont: UIFont? { get set }
|
||||
|
||||
/// Text color of text object.
|
||||
var titleColor: UIColor? { get set }
|
||||
|
||||
/// Text alignment of text object.
|
||||
var textAlignment: NSTextAlignment { get set }
|
||||
|
||||
/// Text itself of text object.
|
||||
var text: String? { get set }
|
||||
|
||||
/// Attributed text of text object.
|
||||
var attributedText: NSAttributedString? { get set }
|
||||
}
|
||||
|
||||
public extension ViewTextConfigurable {
|
||||
|
||||
/// Configures text and text appearance of view using ViewText object.
|
||||
///
|
||||
/// - Parameter viewText: ViewText object with text and text appearance.
|
||||
func configure(with viewText: ViewText) {
|
||||
switch viewText {
|
||||
case let .string(text, textAttributes):
|
||||
self.text = text
|
||||
self.configureBaseAppearance(with: textAttributes)
|
||||
|
||||
case .attributedString(let attributedString):
|
||||
self.attributedText = attributedString
|
||||
}
|
||||
}
|
||||
|
||||
/// Configures text appearance of view.
|
||||
///
|
||||
/// - Parameter baseTextAttributes: Set of attributes to configure appearance of text.
|
||||
func configureBaseAppearance(with baseTextAttributes: BaseTextAttributes) {
|
||||
textFont = baseTextAttributes.font
|
||||
titleColor = baseTextAttributes.color
|
||||
textAlignment = baseTextAttributes.alignment
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIUIKitCore'
|
||||
s.version = '0.11.0'
|
||||
s.version = '0.12.0'
|
||||
s.summary = 'Core UI elements: protocols, views and helpers.'
|
||||
s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
Loading…
Reference in New Issue