| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- //
- // Auto.swift
- // ┌─┐ ┌───────┐ ┌───────┐
- // │ │ │ ┌─────┘ │ ┌─────┘
- // │ │ │ └─────┐ │ └─────┐
- // │ │ │ ┌─────┘ │ ┌─────┘
- // │ └─────┐│ └─────┐ │ └─────┐
- // └───────┘└───────┘ └───────┘
- //
- // Created by lee on 2018/11/2.
- // Copyright © 2018年 lee. All rights reserved.
- //
- #if canImport(Foundation)
- import Foundation
- #if os(iOS)
- import UIKit
- public enum Auto {
-
- /// 设置转换闭包
- ///
- /// - Parameter conversion: 转换闭包
- public static func set(conversion: @escaping ((Double) -> Double)) {
- conversionClosure = conversion
- }
-
- /// 转换 用于数值的等比例计算 如需自定义可重新设置
- static var conversionClosure: ((Double) -> Double) = { (origin) in
- guard UIDevice.current.userInterfaceIdiom == .phone else {
- return origin
- }
-
- let base = 375.0
- let screenWidth = Double(UIScreen.main.bounds.width)
- let screenHeight = Double(UIScreen.main.bounds.height)
- let width = min(screenWidth, screenHeight)
- let result = origin * (width / base)
- let scale = Double(UIScreen.main.scale)
- return (result * scale).rounded(.up) / scale
- }
- }
- extension Auto {
-
- static func conversion(_ value: Double) -> Double {
- return conversionClosure(value)
- }
- }
- protocol AutoCalculationable {
-
- /// 自动计算
- ///
- /// - Returns: 结果
- func auto() -> Self
- }
- extension Double: AutoCalculationable {
-
- func auto() -> Double {
- return Auto.conversion(self)
- }
- }
- extension BinaryInteger {
-
- public func auto() -> Double {
- let temp = Double("\(self)") ?? 0
- return temp.auto()
- }
- public func auto<T>() -> T where T : BinaryInteger {
- let temp = Double("\(self)") ?? 0
- return temp.auto()
- }
- public func auto<T>() -> T where T : BinaryFloatingPoint {
- let temp = Double("\(self)") ?? 0
- return temp.auto()
- }
- }
- extension BinaryFloatingPoint {
-
- public func auto() -> Double {
- let temp = Double("\(self)") ?? 0
- return temp.auto()
- }
- public func auto<T>() -> T where T : BinaryInteger {
- let temp = Double("\(self)") ?? 0
- return T(temp.auto())
- }
- public func auto<T>() -> T where T : BinaryFloatingPoint {
- let temp = Double("\(self)") ?? 0
- return T(temp.auto())
- }
- }
- extension CGPoint: AutoCalculationable {
-
- public func auto() -> CGPoint {
- return CGPoint(x: x.auto(), y: y.auto())
- }
- }
- extension CGSize: AutoCalculationable {
-
- public func auto() -> CGSize {
- return CGSize(width: width.auto(), height: height.auto())
- }
- }
- extension CGRect: AutoCalculationable {
-
- public func auto() -> CGRect {
- return CGRect(origin: origin.auto(), size: size.auto())
- }
- }
- extension CGVector: AutoCalculationable {
-
- public func auto() -> CGVector {
- return CGVector(dx: dx.auto(), dy: dy.auto())
- }
- }
- extension UIOffset: AutoCalculationable {
-
- public func auto() -> UIOffset {
- return UIOffset(horizontal: horizontal.auto(), vertical: vertical.auto())
- }
- }
- extension UIEdgeInsets: AutoCalculationable {
-
- public func auto() -> UIEdgeInsets {
- return UIEdgeInsets(
- top: top.auto(),
- left: left.auto(),
- bottom: bottom.auto(),
- right: right.auto()
- )
- }
- }
- extension NSLayoutConstraint {
-
- @IBInspectable private var autoConstant: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- constant = constant.auto()
- }
- }
- }
- extension UIView {
-
- @IBInspectable private var autoCornerRadius: CGFloat {
- get { return layer.cornerRadius }
- set {
- let value: CGFloat = newValue.auto()
- layer.masksToBounds = true
- layer.cornerRadius = abs(CGFloat(Int(value * 100)) / 100)
- }
- }
- }
- extension UILabel {
-
- @IBInspectable private var autoFont: Bool {
- get { return false }
- set {
- guard newValue else { return }
- guard let text = attributedText?.mutableCopy() as? NSMutableAttributedString else {
- return
- }
-
- font = font.withSize(font.pointSize.auto())
- attributedText = text.reset(font: { $0.auto() })
- }
- }
-
- @IBInspectable private var autoLine: Bool {
- get { return false }
- set {
- guard newValue else { return }
- guard let text = attributedText else { return }
-
- attributedText = text.reset(line: { $0.auto() })
- }
- }
-
- @IBInspectable private var autoShadowOffset: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- shadowOffset = shadowOffset.auto()
- }
- }
- }
- extension UITextView {
-
- @IBInspectable private var autoFont: Bool {
- get { return false }
- set {
- guard newValue else { return }
- guard let font = font else { return }
-
- self.font = font.withSize(font.pointSize.auto())
- }
- }
- }
- extension UITextField {
-
- @IBInspectable private var autoFont: Bool {
- get { return false }
- set {
- guard newValue else { return }
- guard let font = font else { return }
-
- self.font = font.withSize(font.pointSize.auto())
- }
- }
- }
- extension UIImageView {
-
- @IBInspectable private var autoImage: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- if let width = image?.size.width {
- image = image?.scaled(to: width.auto())
- }
- if let width = highlightedImage?.size.width {
- highlightedImage = highlightedImage?.scaled(to: width.auto())
- }
- }
- }
- }
- extension UIButton {
-
- @IBInspectable private var autoTitle: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- let states: [UIControl.State] = [
- .normal,
- .highlighted,
- .selected,
- .disabled
- ]
-
- if
- let _ = title(for: state),
- let label = titleLabel,
- let font = label.font {
- label.font = font.withSize(font.pointSize.auto())
- }
-
- let titles = states.enumerated().compactMap {
- (i, state) -> (Int, NSAttributedString)? in
- guard let t = attributedTitle(for: state) else { return nil }
- return (i, t)
- }
- titles.filtered(duplication: { $0.1 }).forEach {
- setAttributedTitle(
- $0.1.reset(font: { $0.auto() }),
- for: states[$0.0]
- )
- }
- }
- }
-
- @IBInspectable private var autoImage: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- let states: [UIControl.State] = [
- .normal,
- .highlighted,
- .selected,
- .disabled
- ]
-
- let images = states.enumerated().compactMap {
- (i, state) -> (Int, UIImage)? in
- guard let v = image(for: state) else { return nil }
- return (i, v)
- }
- images.filtered(duplication: { $0.1 }).forEach {
- setImage(
- $0.1.scaled(to: $0.1.size.width.auto()),
- for: states[$0.0]
- )
- }
-
- let backgrounds = states.enumerated().compactMap {
- (i, state) -> (Int, UIImage)? in
- guard let v = backgroundImage(for: state) else { return nil }
- return (i, v)
- }
- backgrounds.filtered(duplication: { $0.1 }).forEach {
- setBackgroundImage(
- $0.1.scaled(to: $0.1.size.width.auto()),
- for: states[$0.0]
- )
- }
- }
- }
-
- @IBInspectable private var autoTitleInsets: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- titleEdgeInsets = titleEdgeInsets.auto()
- }
- }
-
- @IBInspectable private var autoImageInsets: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- imageEdgeInsets = imageEdgeInsets.auto()
- }
- }
-
- @IBInspectable private var autoContentInsets: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- contentEdgeInsets = contentEdgeInsets.auto()
- }
- }
- }
- @available(iOS 9.0, *)
- extension UIStackView {
-
- @IBInspectable private var autoSpacing: Bool {
- get { return false }
- set {
- guard newValue else { return }
-
- spacing = spacing.auto()
- }
- }
- }
- fileprivate extension NSAttributedString {
-
- func reset(font size: (CGFloat) -> CGFloat) -> NSAttributedString {
- let string = NSMutableAttributedString(attributedString: self)
- enumerateAttributes(
- in: NSRange(location: 0, length: length),
- options: .longestEffectiveRangeNotRequired
- ) { (attributes, range, stop) in
- var temp = attributes
- if let font = attributes[.font] as? UIFont {
- temp[.font] = font.withSize(size(font.pointSize))
- }
- string.setAttributes(temp, range: range)
- }
- return string
- }
-
- func reset(line spacing: (CGFloat) -> CGFloat) -> NSAttributedString {
- let string = NSMutableAttributedString(attributedString: self)
- enumerateAttributes(
- in: NSRange(location: 0, length: length),
- options: .longestEffectiveRangeNotRequired
- ) { (attributes, range, stop) in
- var temp = attributes
- if let paragraph = attributes[.paragraphStyle] as? NSMutableParagraphStyle {
- paragraph.lineSpacing = spacing(paragraph.lineSpacing)
- temp[.paragraphStyle] = paragraph
- }
- string.setAttributes(temp, range: range)
- }
- return string
- }
- }
- fileprivate extension UIImage {
-
- func scaled(to width: CGFloat, opaque: Bool = false) -> UIImage? {
- guard self.size.width > 0 else {
- return nil
- }
-
- let scale = width / self.size.width
- let size = CGSize(width: width, height: self.size.height * scale)
- UIGraphicsBeginImageContextWithOptions(size, false, 0)
- draw(in: CGRect(origin: .zero, size: size))
- let new = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
- return new
- }
- }
- fileprivate extension Array {
-
- func filtered<E: Equatable>(duplication closure: (Element) throws -> E) rethrows -> [Element] {
- return try reduce(into: [Element]()) { (result, e) in
- let contains = try result.contains { try closure($0) == closure(e) }
- result += contains ? [] : [e]
- }
- }
- }
- public extension Double {
-
- func rounded(_ decimalPlaces: Int) -> Double {
- let divisor = pow(10.0, Double(max(0, decimalPlaces)))
- return (self * divisor).rounded() / divisor
- }
- }
- public extension BinaryFloatingPoint {
-
- func rounded(_ decimalPlaces: Int) -> Double {
- let temp = Double("\(self)") ?? 0
- return temp.rounded(decimalPlaces)
- }
-
- func rounded<T>(_ decimalPlaces: Int) -> T where T: BinaryFloatingPoint {
- let temp = Double("\(self)") ?? 0
- return T(temp.rounded(decimalPlaces))
- }
- }
- public extension CGPoint {
-
- func rounded(_ decimalPlaces: Int) -> CGPoint {
- return CGPoint(x: x.rounded(decimalPlaces), y: y.rounded(decimalPlaces))
- }
- }
- public extension CGSize {
-
- func rounded(_ decimalPlaces: Int) -> CGSize {
- return CGSize(width: width.rounded(decimalPlaces), height: height.rounded(decimalPlaces))
- }
- }
- public extension CGRect {
-
- func rounded(_ decimalPlaces: Int) -> CGRect {
- return CGRect(origin: origin.rounded(decimalPlaces), size: size.rounded(decimalPlaces))
- }
- }
- public extension UIEdgeInsets {
-
- func rounded(_ decimalPlaces: Int) -> UIEdgeInsets {
- return UIEdgeInsets(
- top: top.rounded(decimalPlaces),
- left: left.rounded(decimalPlaces),
- bottom: bottom.rounded(decimalPlaces),
- right: right.rounded(decimalPlaces)
- )
- }
- }
- #endif
- #endif
|