├── .gitignore ├── BTBubble.podspec ├── BTBubble.xmind ├── BTBubble ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── BTBubble+Animation.swift │ ├── BTBubble+Check.swift │ ├── BTBubble+Draw.swift │ ├── BTBubble+Location.swift │ ├── BTBubble+Menu.swift │ ├── BTBubble.swift │ ├── BTBubbleConfig.swift │ └── BubbleTools.swift ├── Example ├── BTBubble.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── BTBubble-Example.xcscheme ├── BTBubble.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── BTBubble │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Bubble │ │ ├── BubbleBaseViewController.swift │ │ ├── Tools.swift │ │ ├── 气泡的三种展示方式 │ │ │ └── BubbleShowStyleViewController.swift │ │ ├── 气泡的动画 │ │ │ └── BubbleAnimateViewController.swift │ │ ├── 气泡的手势 & 生命周期 │ │ │ └── GestureViewController.swift │ │ ├── 气泡的方向 │ │ │ └── BubbleDirectionViewController.swift │ │ └── 气泡的高阶用法 │ │ │ ├── BubbleMenuViewController.swift │ │ │ └── 气泡联动 │ │ │ └── BubbleInputViewController.swift │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── item1.imageset │ │ │ ├── Contents.json │ │ │ ├── yz选中=no@2x.png │ │ │ └── yz选中=no@3x.png │ │ ├── item2.imageset │ │ │ ├── Contents.json │ │ │ ├── yz选中=yes@2x.png │ │ │ └── yz选中=yes@3x.png │ │ ├── item3.imageset │ │ │ ├── Contents.json │ │ │ ├── 选中=no@2x.png │ │ │ └── 选中=no@3x.png │ │ └── item4.imageset │ │ │ ├── Contents.json │ │ │ ├── 选中=yes@2x.png │ │ │ └── 选中=yes@3x.png │ ├── Info.plist │ ├── Model.swift │ ├── ViewController+Extension.swift │ └── ViewController.swift ├── Podfile ├── Podfile.lock ├── Pods │ ├── Local Podspecs │ │ └── BTBubble.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ └── project.pbxproj │ ├── SnapKit │ │ ├── LICENSE │ │ ├── README.md │ │ └── Sources │ │ │ ├── Constraint.swift │ │ │ ├── ConstraintAttributes.swift │ │ │ ├── ConstraintConfig.swift │ │ │ ├── ConstraintConstantTarget.swift │ │ │ ├── ConstraintDSL.swift │ │ │ ├── ConstraintDescription.swift │ │ │ ├── ConstraintDirectionalInsetTarget.swift │ │ │ ├── ConstraintDirectionalInsets.swift │ │ │ ├── ConstraintInsetTarget.swift │ │ │ ├── ConstraintInsets.swift │ │ │ ├── ConstraintItem.swift │ │ │ ├── ConstraintLayoutGuide+Extensions.swift │ │ │ ├── ConstraintLayoutGuide.swift │ │ │ ├── ConstraintLayoutGuideDSL.swift │ │ │ ├── ConstraintLayoutSupport.swift │ │ │ ├── ConstraintLayoutSupportDSL.swift │ │ │ ├── ConstraintMaker.swift │ │ │ ├── ConstraintMakerEditable.swift │ │ │ ├── ConstraintMakerExtendable.swift │ │ │ ├── ConstraintMakerFinalizable.swift │ │ │ ├── ConstraintMakerPrioritizable.swift │ │ │ ├── ConstraintMakerRelatable+Extensions.swift │ │ │ ├── ConstraintMakerRelatable.swift │ │ │ ├── ConstraintMultiplierTarget.swift │ │ │ ├── ConstraintOffsetTarget.swift │ │ │ ├── ConstraintPriority.swift │ │ │ ├── ConstraintPriorityTarget.swift │ │ │ ├── ConstraintRelatableTarget.swift │ │ │ ├── ConstraintRelation.swift │ │ │ ├── ConstraintView+Extensions.swift │ │ │ ├── ConstraintView.swift │ │ │ ├── ConstraintViewDSL.swift │ │ │ ├── Debugging.swift │ │ │ ├── LayoutConstraint.swift │ │ │ ├── LayoutConstraintItem.swift │ │ │ ├── Typealiases.swift │ │ │ └── UILayoutSupport+Extensions.swift │ └── Target Support Files │ │ ├── BTBubble │ │ ├── BTBubble-Info.plist │ │ ├── BTBubble-dummy.m │ │ ├── BTBubble-prefix.pch │ │ ├── BTBubble-umbrella.h │ │ ├── BTBubble.debug.xcconfig │ │ ├── BTBubble.modulemap │ │ └── BTBubble.release.xcconfig │ │ ├── Pods-BTBubble_Example │ │ ├── Pods-BTBubble_Example-Info.plist │ │ ├── Pods-BTBubble_Example-acknowledgements.markdown │ │ ├── Pods-BTBubble_Example-acknowledgements.plist │ │ ├── Pods-BTBubble_Example-dummy.m │ │ ├── Pods-BTBubble_Example-frameworks.sh │ │ ├── Pods-BTBubble_Example-umbrella.h │ │ ├── Pods-BTBubble_Example.debug.xcconfig │ │ ├── Pods-BTBubble_Example.modulemap │ │ └── Pods-BTBubble_Example.release.xcconfig │ │ ├── Pods-BTBubble_Tests │ │ ├── Pods-BTBubble_Tests-Info.plist │ │ ├── Pods-BTBubble_Tests-acknowledgements.markdown │ │ ├── Pods-BTBubble_Tests-acknowledgements.plist │ │ ├── Pods-BTBubble_Tests-dummy.m │ │ ├── Pods-BTBubble_Tests-umbrella.h │ │ ├── Pods-BTBubble_Tests.debug.xcconfig │ │ ├── Pods-BTBubble_Tests.modulemap │ │ └── Pods-BTBubble_Tests.release.xcconfig │ │ └── SnapKit │ │ ├── SnapKit-Info.plist │ │ ├── SnapKit-dummy.m │ │ ├── SnapKit-prefix.pch │ │ ├── SnapKit-umbrella.h │ │ ├── SnapKit.debug.xcconfig │ │ ├── SnapKit.modulemap │ │ └── SnapKit.release.xcconfig └── Tests │ ├── Info.plist │ └── Tests.swift ├── LICENSE ├── README.md ├── Sample ├── BTBubble.png ├── bubbleSmaple.gif └── demo.png └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /BTBubble.podspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'BTBubble' 7 | s.version = '0.0.5' 8 | s.summary = '气泡' 9 | 10 | s.homepage = 'https://github.com/intsig171' 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { 'Mccc' => 'Mccc' } 13 | s.source = { :git => 'https://github.com/intsig171/BTBubble.git', :tag => s.version.to_s } 14 | 15 | s.platform = :ios, '11.0' 16 | s.ios.deployment_target = '11.0' 17 | s.swift_version = '5.0' 18 | 19 | 20 | 21 | s.source_files = 'BTBubble/Classes/**/*' 22 | 23 | end 24 | -------------------------------------------------------------------------------- /BTBubble.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/BTBubble.xmind -------------------------------------------------------------------------------- /BTBubble/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/BTBubble/Assets/.gitkeep -------------------------------------------------------------------------------- /BTBubble/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/BTBubble/Classes/.gitkeep -------------------------------------------------------------------------------- /BTBubble/Classes/BTBubble+Check.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BTBubble+Check.swift 3 | // BTBubble 4 | // 5 | // Created by Mccc on 2022/11/21. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | extension BTBubble { 12 | 13 | /// 获取目标的中心点X值 14 | func formCenterX() -> CGFloat { 15 | 16 | /** 校验 17 | 1. 不可以超出自身 18 | */ 19 | 20 | if horizontalOffset >= from.width / 2 { 21 | return from.origin.x + from.width / 2 22 | } else { 23 | return from.origin.x + from.width / 2 + horizontalOffset 24 | } 25 | } 26 | 27 | 28 | /// 获取目标的中心点Y值 29 | func getFormCenterY() -> CGFloat { 30 | return from.origin.y + from.height / 2 + horizontalOffset 31 | } 32 | } 33 | 34 | extension BTBubble { 35 | 36 | /// 箭头偏移量是否满足条件 37 | func checkArrowOffset(maxOffset: CGFloat) -> Bool { 38 | 39 | // arrowOffset需要大于0 ,不然箭头就和角重合了。 40 | 41 | switch arrowOffset { 42 | case .before(let o): 43 | if o > 0 && o < maxOffset { 44 | return true 45 | } 46 | case .center(let o): 47 | if o > 0 && o < maxOffset { 48 | return true 49 | } 50 | case .after(let o): 51 | if o > 0 && o < maxOffset { 52 | return true 53 | } 54 | case .auto(let o): 55 | if o > 0 && o < maxOffset { 56 | return true 57 | } 58 | } 59 | 60 | return false 61 | } 62 | } 63 | 64 | 65 | 66 | extension BTBubble { 67 | 68 | /** 明确气泡显示方向 69 | * 如果没有明确方向,就自己决定方向 70 | * 尽可能的让气泡的显示趋向屏幕中间 71 | */ 72 | func checkDirection() -> BTBubble.Direction { 73 | if direction.isAuto { 74 | guard let containerView = containerView else { return direction } 75 | var spaces: [BTBubble.Direction: CGFloat] = [:] 76 | 77 | if direction == .autoHorizontal || direction == .auto { 78 | spaces[.left] = from.minX - containerView.frame.minX 79 | spaces[.right] = containerView.frame.maxX - from.maxX 80 | } 81 | 82 | if direction == .autoVertical || direction == .auto { 83 | spaces[.up] = from.minY - containerView.frame.minY 84 | spaces[.down] = containerView.frame.maxY - from.maxY 85 | } 86 | 87 | // 降序排序, 获取最大空间的一个方案,尽可能的让气泡显示在屏幕中间 88 | if let space = spaces.sorted(by: { $0.1 > $1.1 }).first { 89 | return space.key 90 | } 91 | } 92 | 93 | return direction 94 | } 95 | } 96 | 97 | 98 | extension BTBubble { 99 | 100 | /// 校验最大宽度 101 | func checkMaxWidth() -> CGFloat { 102 | 103 | 104 | /** 校验最大宽度 105 | * 1. 最大宽度不可以超过(屏幕宽度 - distanceFromBoundary) 106 | */ 107 | func check(_ width: CGFloat) -> CGFloat { 108 | let maxWidth = UIDevice.width - distanceFromBoundary*2 109 | 110 | let width = min(width, maxWidth) 111 | 112 | return max(width, 10) 113 | } 114 | 115 | 116 | guard let containerView = containerView else { return maxWidth } 117 | if direction.isHorizontal { 118 | func check(autoWidth: inout CGFloat) { 119 | 120 | if autoWidth <= 0 { 121 | autoWidth = 0 122 | } 123 | 124 | if autoWidth > distanceFromBoundary { 125 | autoWidth = autoWidth - distanceFromBoundary 126 | } 127 | maxWidth = CGFloat.minimum(maxWidth, autoWidth) 128 | 129 | // 当方向上无法满足要求的时候,重新设置方向 (一直不满足条件的话,有可能会死循环) 130 | if maxWidth <= edgeInsets.horizontal && !isResetDirection { 131 | direction = .auto 132 | isResetDirection = true 133 | setup() 134 | return 135 | } 136 | } 137 | 138 | 139 | // 最大可显示宽度 140 | switch direction { 141 | case .left: 142 | var autoWidth = from.origin.x - arrowSize.height 143 | check(autoWidth: &autoWidth) 144 | case .right: 145 | var autoWidth = containerView.bounds.width - from.maxX - arrowSize.height 146 | check(autoWidth: &autoWidth) 147 | default: 148 | break 149 | } 150 | } else { 151 | let maxW = check(maxWidthBackUp) 152 | return maxW 153 | } 154 | 155 | let maxW = check(maxWidth) 156 | return maxW 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /BTBubble/Classes/BTBubble+Location.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BTBubble+Location.swift 3 | // BTBubble 4 | // 5 | // Created by Mccc on 2022/11/21. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | /** 待办 12 | 1. 通过象限,定位气泡箭头的位置。决定箭头处于气泡的位置。 13 | 2. 新增一个arrowMinOffset,气泡距离边界的最小距离。 14 | */ 15 | 16 | 17 | 18 | extension BTBubble { 19 | public enum Direction { 20 | /// 上面 21 | case up 22 | /// 下面 23 | case down 24 | /// 左侧 25 | case left 26 | /// 右侧 27 | case right 28 | /// 自动计算 29 | case auto 30 | /// 水平方向自动计算 31 | case autoHorizontal 32 | /// 竖直方向自动计算 33 | case autoVertical 34 | 35 | /// 是否自动计算方向 36 | var isAuto: Bool { 37 | return self == .autoVertical || self == .autoHorizontal || self == .auto 38 | } 39 | 40 | /// 是否横向方向 41 | var isHorizontal: Bool { 42 | return self == .left || self == .right || self == .autoHorizontal 43 | } 44 | 45 | /// 是否纵向方向 46 | var isVertical: Bool { 47 | return self == .up || self == .down || self == .autoVertical 48 | } 49 | } 50 | } 51 | 52 | extension BTBubble { 53 | 54 | 55 | /// 设置箭头所在的位置 56 | /// 1. 先确定气泡的方向,根据气泡和目标的连线判断:是水平方向还是竖直方向。 57 | /// 58 | /// 2. 确定了方向,再来理解ArrowOffset的几个枚举项。 59 | /// 60 | /// 3. before: 61 | /// 3.1 水平方向下, 62 | /// 箭头位于气泡最左侧。 63 | /// 期望箭头向左偏移就使用负数,向右偏移就使用正数。 64 | /// 65 | /// 3.2 竖直方向下 66 | /// 箭头在气泡的最上侧。 67 | /// 期望箭头向上偏移就使用负数,向下偏移就使用正数。 68 | /// 69 | /// 4 center: 70 | /// 4.1 水平方向下 71 | /// 箭头在气泡的中心。 72 | /// 期望箭头向左偏移就使用负数,向右偏移就使用正数。 73 | /// 74 | /// 4.2 竖直方向下 75 | /// 箭头在气泡的中心。 76 | /// 期望箭头向上偏移就使用负数,向下偏移就使用正数。 77 | /// 78 | /// 5 after: 79 | /// 5.1 水平方向下 80 | /// 箭头在气泡的最右侧。 81 | /// 期望箭头向左偏移就使用负数,向右偏移就使用正数。 82 | /// 83 | /// 5.2 竖直方向下 84 | /// 箭头在目标的最下侧 85 | /// 期望箭头向上偏移就使用负数,向下偏移就使用正数。 86 | /// 87 | /// 6 auto: 88 | /// 根据象限自动计算 89 | /// 90 | /// 7. 注意 91 | /// 气泡不允许超出屏幕,如果超出了,内部会自动修正。但是如果箭头位置超出了气泡的边缘,就隐藏箭头。 92 | public enum ArrowOffset { 93 | case before(CGFloat) 94 | case center(CGFloat) 95 | case after(CGFloat) 96 | case auto(CGFloat) 97 | 98 | var value: CGFloat { 99 | switch self { 100 | case .before(let o): 101 | return o 102 | case .center(let o): 103 | return o 104 | case .after(let o): 105 | return o 106 | case .auto(let o): 107 | return o 108 | } 109 | } 110 | } 111 | } 112 | 113 | 114 | 115 | extension BTBubble { 116 | 117 | /// 气泡所在的象限 118 | enum Quadrant { 119 | // 第一象限 120 | case first 121 | // 第二象限 122 | case second 123 | // 第三象限 124 | case third 125 | // 第四象限 126 | case fourth 127 | } 128 | } 129 | 130 | 131 | 132 | 133 | extension BTBubble { 134 | 135 | /// 计算目标区域,在以手机屏幕中心为坐标系的象限 136 | /// - 第一/四象限:箭头居气泡右侧 137 | /// - 第二/三象限:箭头居气泡左侧 138 | /// - 未获取到: 当第一象限处理。 139 | /// y轴 140 | /// | 141 | /// | 142 | /// 2 | 1 143 | /// | 144 | /// | 145 | ///----屏幕中心---- x轴 146 | /// | 147 | /// | 148 | /// 3 | 4 149 | /// | 150 | /// | 151 | internal func getQuadrant(with target: CGRect) -> Quadrant? { 152 | 153 | guard let reference = containerView else { return nil } 154 | 155 | 156 | 157 | // 获取参考系原点坐标 158 | let referenceFrameCenter = CGPoint(x: reference.frame.minX + reference.frame.width / 2, y: reference.frame.minY + reference.frame.height / 2) 159 | 160 | 161 | // 目标的中心点坐标 162 | let targetCenter = CGPoint(x: target.minX + target.size.width/2, y: target.minY + target.size.height/2) 163 | 164 | 165 | // 计算参考系中,目标的x和y 166 | let position = (targetCenter.x - referenceFrameCenter.x, referenceFrameCenter.y - targetCenter.y) 167 | 168 | 169 | switch position { 170 | case (0, 0): // 原点当第二象限处理 171 | return .second 172 | case (let x, 0): // 位于x轴上 173 | if x > 0 { return .first } else { return .second } 174 | case (0, let y): // 位于y轴 175 | if y >= 0 { return .second } else { return .third } 176 | case let (x, y) where x > 0 && y > 0: // 位于第一象限 177 | //注意此处let写在()外,let一整个元组对象 178 | return .first 179 | case let (x, y) where x < 0 && y > 0: // 位于第二象限 180 | return .second 181 | case let (x, y) where x < 0 && y < 0: // 位于第三象限 182 | return .third 183 | case let (x, y) where x > 0 && y < 0: // 位于第四象限 184 | return .fourth 185 | default: 186 | return nil 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /BTBubble/Classes/BTBubbleConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BTBubbleConstant.swift 3 | // BTBubble 4 | // 5 | // Created by Mccc on 2022/11/21. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | 12 | public struct BTBubbleConfig { 13 | public static var shared = BTBubbleConfig() 14 | 15 | /// 气泡外观相关的配置 16 | public var appearance = BTBubbleConfig.Appearance() 17 | 18 | /// 文字的相关设置 19 | public var textSetting = BTBubbleConfig.TextSetting() 20 | 21 | /// 气泡的箭头 22 | public var arrow = BTBubbleConfig.Arrow() 23 | 24 | /// 气泡的最大宽度 25 | public var maxWidth: CGFloat = 282 26 | /// 气泡文案最大高度(不影响自定义) 27 | public var maxHeight: CGFloat = UIScreen.main.bounds.size.height * 0.35 28 | 29 | /// 默认的反弹距离 30 | public var defaultBounceOffset = CGFloat(8) 31 | /// 默认的浮动距离 32 | public var defaultFloatOffset = CGFloat(8) 33 | /// 默认的跳动缩放比例 34 | public var defaultPulseOffset = CGFloat(1.1) 35 | 36 | 37 | } 38 | 39 | 40 | 41 | extension BTBubbleConfig { 42 | 43 | public struct Appearance { 44 | // 气泡 45 | /// 气泡的背景颜色 46 | public var backgroundColor = UIColor.white 47 | /// 气泡圆角的设置 48 | public var cornerRadius = CGFloat(4.0) 49 | /// 气泡边框颜色 50 | public var borderColor = UIColor.clear 51 | /// 气泡边框宽度 (设置过大,会出现UI问题) 52 | public var borderWidth = CGFloat(0.0) 53 | /// 气泡阴影的颜色 54 | public var shadowColor: UIColor = UIColor.init(white: 0, alpha: 0.8) 55 | /// 气泡阴影的偏移量 56 | public var shadowOffset: CGSize = .zero 57 | /// 气泡阴影的圆角 58 | public var shadowRadius: Float = 4 59 | /// 气泡阴影的不透明度 60 | public var shadowOpacity: Float = 0.2 61 | /// 气泡的内边距 62 | public var edgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) 63 | } 64 | } 65 | 66 | 67 | extension BTBubbleConfig { 68 | 69 | public struct TextSetting { 70 | // 气泡文字 71 | /// 气泡上的文字大小 72 | public var font = UIFont.systemFont(ofSize: 12) 73 | /// 气泡上的文字颜色 74 | public var textColor = UIColor.hex("212121") 75 | /// 气泡字体的`NSTextAlignment` 76 | public var textAlignment = NSTextAlignment.left 77 | } 78 | } 79 | 80 | extension BTBubbleConfig { 81 | /// 气泡箭头 82 | public struct Arrow { 83 | /// 气泡箭头的大小 84 | public var arrowSize = CGSize(width: 13, height: 7) 85 | /// 气泡箭头的圆角 86 | public var arrowRadius = CGFloat(0.0) 87 | /// 气泡箭头的偏移量 88 | public var arrowOffset: BTBubble.ArrowOffset = .auto(20) 89 | 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /BTBubble/Classes/BubbleTools.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleTools.swift 3 | // BTBubble 4 | // 5 | // Created by Mccc on 2022/11/21. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | 12 | 13 | extension UIView { 14 | 15 | ///获取当前视图相对 屏幕的frame 16 | /// - Returns: 相对屏幕的rect 17 | public func convertFrameToScreen() -> CGRect { 18 | 19 | if let keyWindow = UIApplication.shared.keyWindow, let newBounds = superview?.convert(frame, to: keyWindow) { 20 | return newBounds 21 | } 22 | 23 | var x: CGFloat = 0 24 | var y: CGFloat = 0 25 | 26 | var view: UIView = self 27 | 28 | while ((view.superview as? UIWindow) == nil) { 29 | x += view.frame.origin.x 30 | y += view.frame.origin.y 31 | 32 | 33 | guard let father = view.superview else { 34 | break 35 | } 36 | 37 | view = father 38 | 39 | if view.isKind(of: UIScrollView.self) { 40 | x -= (view as! UIScrollView).contentOffset.x 41 | y -= (view as! UIScrollView).contentOffset.y 42 | } 43 | } 44 | 45 | return CGRect(x: x, y: y, width: frame.size.width, height: frame.size.height) 46 | } 47 | } 48 | 49 | 50 | 51 | 52 | 53 | 54 | //MARK: - 字体的设置 55 | extension NSMutableAttributedString { 56 | /// 设置字体 57 | func addFont(_ font: UIFont, on range: NSRange) { 58 | 59 | if string.count == 0 { return } 60 | 61 | if length < range.location + range.length { return } 62 | let attrs = [NSAttributedString.Key.font: font] 63 | addAttributes(attrs, range: range) 64 | } 65 | } 66 | 67 | extension UIEdgeInsets { 68 | var horizontal: CGFloat { 69 | return self.left + self.right 70 | } 71 | 72 | var vertical: CGFloat { 73 | return self.top + self.bottom 74 | } 75 | } 76 | 77 | 78 | extension UIDevice { 79 | 80 | static var width: CGFloat { 81 | let size = UIScreen.main.bounds.size 82 | return size.width 83 | } 84 | 85 | static var height: CGFloat { 86 | let size = UIScreen.main.bounds.size 87 | return size.height 88 | } 89 | } 90 | 91 | extension String { 92 | 93 | /// 字符串 转 Number 94 | var numberValue: NSNumber? { 95 | let str = self 96 | if let value = Int(str) { 97 | return NSNumber.init(value: value) 98 | } else { 99 | return nil 100 | } 101 | } 102 | 103 | 104 | /// 计算字符串的宽度 105 | func getWidth(font: UIFont, height: CGFloat) -> CGFloat { 106 | let statusLabelText: NSString = self as NSString 107 | let size = CGSize.init(width: 9999, height: height) 108 | 109 | var dic: [NSAttributedString.Key : Any] = [:] 110 | dic[NSAttributedString.Key.font] = font 111 | let strSize = statusLabelText.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: dic, context: nil).size 112 | return strSize.width + 1 113 | } 114 | } 115 | 116 | 117 | extension UIColor { 118 | /// 生成Color对象 119 | /// - Parameters: 120 | /// - hex: 16进制的颜色色值 121 | /// - alpha: 透明度 122 | static func hex(_ hex: String, alpha: CGFloat? = nil) -> UIColor { 123 | 124 | /** 125 | * #ff000000 此为16进制颜色代码 126 | * 前两位ff为透明度,后六位为颜色值(000000为黑色,ffffff为白色,可以用ps等软件获取) 127 | * 透明度分为256阶(0~255),计算机上16进制表示为(00~ff),透明为0阶,不透明为255阶,如果50%透明度就是127阶(256的一半当然是128,但是因为从0开始,所以实际上是127) 128 | * 如果是6位,默认是不透明。 129 | */ 130 | 131 | var red: CGFloat = 0.0 132 | var green: CGFloat = 0.0 133 | var blue: CGFloat = 0.0 134 | 135 | var useAlpha: CGFloat = 1 136 | 137 | 138 | 139 | var hex: String = hex 140 | 141 | /** 开头是用0x开始的 */ 142 | if hex.hasPrefix("0X") { 143 | let index = hex.index(hex.startIndex, offsetBy: 2) 144 | hex = String(hex[index...]) 145 | } 146 | 147 | /** 开头是以##开始的 */ 148 | if hex.hasPrefix("##") { 149 | let index = hex.index(hex.startIndex, offsetBy: 2) 150 | hex = String(hex[index...]) 151 | } 152 | 153 | /** 开头是以#开头的 */ 154 | if hex.hasPrefix("#") { 155 | let index = hex.index(hex.startIndex, offsetBy: 1) 156 | hex = String(hex[index...]) 157 | } 158 | 159 | let scanner = Scanner(string: hex) 160 | var hexValue: CUnsignedLongLong = 0 161 | if scanner.scanHexInt64(&hexValue) { 162 | switch (hex.count) { 163 | case 3: 164 | red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 165 | green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 166 | blue = CGFloat(hexValue & 0x00F) / 15.0 167 | case 4: 168 | let index = hex.index(hex.startIndex, offsetBy: 1) 169 | 170 | /// 处理透明度 171 | let alphaStr = String(hex[hex.startIndex..> 8) / 15.0 178 | green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 179 | blue = CGFloat(hexValue & 0x00F) / 15.0 180 | case 6: 181 | red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 182 | green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 183 | blue = CGFloat(hexValue & 0x0000FF) / 255.0 184 | case 8: 185 | let index = hex.index(hex.startIndex, offsetBy: 2) 186 | /// 处理透明度 187 | let alphaStr = String(hex[hex.startIndex..> 16) / 255.0 194 | green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 195 | blue = CGFloat(hexValue & 0x0000FF) / 255.0 196 | 197 | 198 | default: 199 | print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8", terminator: "") 200 | } 201 | } else { 202 | print("Scan hex error") 203 | return UIColor.white 204 | } 205 | 206 | if let temp = alpha { 207 | useAlpha = temp 208 | } 209 | 210 | return UIColor(red: red, green: green, blue: blue, alpha: useAlpha) 211 | } 212 | } 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | extension UIWindow { 221 | /// 获取当前的window 222 | static var current: UIWindow? { 223 | if #available(iOS 13.0, *) { 224 | if let window = UIApplication.shared.connectedScenes 225 | .filter({$0.activationState == .foregroundActive}) 226 | .map({$0 as? UIWindowScene}) 227 | .compactMap({$0}) 228 | .first?.windows 229 | .filter({$0.isKeyWindow}).first{ 230 | return window 231 | }else if let window = UIApplication.shared.delegate?.window{ 232 | return window 233 | }else{ 234 | return nil 235 | } 236 | } else { 237 | if let window = UIApplication.shared.delegate?.window{ 238 | return window 239 | }else{ 240 | return nil 241 | } 242 | } 243 | } 244 | } 245 | 246 | 247 | 248 | -------------------------------------------------------------------------------- /Example/BTBubble.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/BTBubble.xcodeproj/xcshareddata/xcschemes/BTBubble-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 48 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 80 | 82 | 88 | 89 | 90 | 91 | 92 | 93 | 99 | 101 | 107 | 108 | 109 | 110 | 112 | 113 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /Example/BTBubble.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/BTBubble.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/BTBubble/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // BTBubble 4 | // 5 | // Created by Mccc on 12/18/2023. 6 | // Copyright (c) 2023 Mccc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/BTBubble/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Example/BTBubble/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Example/BTBubble/Bubble/BubbleBaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleViewController.swift 3 | // BTBubble_Example 4 | // 5 | // Created by qixin on 2023/12/19. 6 | // Copyright © 2023 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BTBubble 11 | 12 | class BubbleBaseViewController: UIViewController { 13 | 14 | var bubble = BTBubble() 15 | 16 | var isAutoShowBubble: Bool = true 17 | 18 | var isCustomCutout: Bool = false 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | 23 | view.backgroundColor = UIColor.white 24 | 25 | view.addSubview(button) 26 | button.snp.makeConstraints { make in 27 | make.centerX.equalToSuperview() 28 | make.top.equalTo(300) 29 | make.size.equalTo(CGSize(width: 60, height: 40)) 30 | } 31 | 32 | } 33 | 34 | override func viewDidAppear(_ animated: Bool) { 35 | super.viewDidAppear(animated) 36 | 37 | if isAutoShowBubble { 38 | event() 39 | } 40 | } 41 | 42 | @objc func event() { 43 | 44 | if isCustomCutout { 45 | customCutout() 46 | } 47 | 48 | bubble.show(text: "明亮的月光洒在窗户纸上,好像地上泛起了一层白霜。我抬起头来,看那天窗外空中的明月,不由得低头沉思,想起远方的家乡。", from: button, duration: nil) 49 | } 50 | 51 | lazy var button: UIButton = { 52 | let btn = UIButton(type: .custom) 53 | btn.setTitle("点击", for: .normal) 54 | btn.setTitleColor(UIColor.black, for: .normal) 55 | btn.backgroundColor = UIColor.red.withAlphaComponent(0.1) 56 | btn.addTarget(self, action: #selector(event), for: .touchUpInside) 57 | return btn 58 | }() 59 | } 60 | 61 | 62 | 63 | extension BubbleBaseViewController { 64 | func customCutout() { 65 | let from = button.convertFrameToScreen() 66 | let radio = max(from.width, from.height) 67 | bubble.cutoutBezierPath = UIBezierPath(roundedRect: from.insetBy(dx: -15, dy: -15), byRoundingCorners: .allCorners, cornerRadii: CGSize(width: radio, height: radio)) 68 | } 69 | } 70 | 71 | extension BubbleBaseViewController { 72 | func updateFrom() { 73 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 74 | 75 | // 需要拿到相对屏幕的frame 76 | var rect = self.button.convertFrameToScreen() 77 | rect.origin.y += 50 78 | 79 | self.bubble.from = rect 80 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 81 | rect.origin.y += 50 82 | self.bubble.from = rect 83 | 84 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 85 | rect.origin.y += 50 86 | self.bubble.from = rect 87 | 88 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 89 | rect.origin.y += 50 90 | self.bubble.from = rect 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Example/BTBubble/Bubble/Tools.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tools.swift 3 | // BTBubble 4 | // 5 | // Created by qixin on 2023/12/18. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | 12 | 13 | 14 | //MARK: - 字体的设置 15 | extension NSMutableAttributedString { 16 | /// 设置字体 17 | func addFont(_ font: UIFont, on range: NSRange) { 18 | 19 | if string.count == 0 { return } 20 | 21 | if length < range.location + range.length { return } 22 | let attrs = [NSAttributedString.Key.font: font] 23 | addAttributes(attrs, range: range) 24 | } 25 | } 26 | 27 | extension UIEdgeInsets { 28 | var horizontal: CGFloat { 29 | return self.left + self.right 30 | } 31 | 32 | var vertical: CGFloat { 33 | return self.top + self.bottom 34 | } 35 | } 36 | 37 | 38 | extension UIDevice { 39 | 40 | static var width: CGFloat { 41 | let size = UIScreen.main.bounds.size 42 | return size.width 43 | } 44 | 45 | static var height: CGFloat { 46 | let size = UIScreen.main.bounds.size 47 | return size.height 48 | } 49 | } 50 | 51 | extension String { 52 | 53 | /// 字符串 转 Number 54 | var numberValue: NSNumber? { 55 | let str = self 56 | if let value = Int(str) { 57 | return NSNumber.init(value: value) 58 | } else { 59 | return nil 60 | } 61 | } 62 | 63 | 64 | /// 计算字符串的宽度 65 | func getWidth(font: UIFont, height: CGFloat) -> CGFloat { 66 | let statusLabelText: NSString = self as NSString 67 | let size = CGSize.init(width: 9999, height: height) 68 | 69 | var dic: [NSAttributedString.Key : Any] = [:] 70 | dic[NSAttributedString.Key.font] = font 71 | let strSize = statusLabelText.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: dic, context: nil).size 72 | return strSize.width + 1 73 | } 74 | } 75 | 76 | 77 | extension UIColor { 78 | /// 生成Color对象 79 | /// - Parameters: 80 | /// - hex: 16进制的颜色色值 81 | /// - alpha: 透明度 82 | static func hex(_ hex: String, alpha: CGFloat? = nil) -> UIColor { 83 | 84 | /** 85 | * #ff000000 此为16进制颜色代码 86 | * 前两位ff为透明度,后六位为颜色值(000000为黑色,ffffff为白色,可以用ps等软件获取) 87 | * 透明度分为256阶(0~255),计算机上16进制表示为(00~ff),透明为0阶,不透明为255阶,如果50%透明度就是127阶(256的一半当然是128,但是因为从0开始,所以实际上是127) 88 | * 如果是6位,默认是不透明。 89 | */ 90 | 91 | var red: CGFloat = 0.0 92 | var green: CGFloat = 0.0 93 | var blue: CGFloat = 0.0 94 | 95 | var useAlpha: CGFloat = 1 96 | 97 | 98 | 99 | var hex: String = hex 100 | 101 | /** 开头是用0x开始的 */ 102 | if hex.hasPrefix("0X") { 103 | let index = hex.index(hex.startIndex, offsetBy: 2) 104 | hex = String(hex[index...]) 105 | } 106 | 107 | /** 开头是以##开始的 */ 108 | if hex.hasPrefix("##") { 109 | let index = hex.index(hex.startIndex, offsetBy: 2) 110 | hex = String(hex[index...]) 111 | } 112 | 113 | /** 开头是以#开头的 */ 114 | if hex.hasPrefix("#") { 115 | let index = hex.index(hex.startIndex, offsetBy: 1) 116 | hex = String(hex[index...]) 117 | } 118 | 119 | let scanner = Scanner(string: hex) 120 | var hexValue: CUnsignedLongLong = 0 121 | if scanner.scanHexInt64(&hexValue) { 122 | switch (hex.count) { 123 | case 3: 124 | red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 125 | green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 126 | blue = CGFloat(hexValue & 0x00F) / 15.0 127 | case 4: 128 | let index = hex.index(hex.startIndex, offsetBy: 1) 129 | 130 | /// 处理透明度 131 | let alphaStr = String(hex[hex.startIndex..> 8) / 15.0 138 | green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 139 | blue = CGFloat(hexValue & 0x00F) / 15.0 140 | case 6: 141 | red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 142 | green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 143 | blue = CGFloat(hexValue & 0x0000FF) / 255.0 144 | case 8: 145 | let index = hex.index(hex.startIndex, offsetBy: 2) 146 | /// 处理透明度 147 | let alphaStr = String(hex[hex.startIndex..> 16) / 255.0 154 | green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 155 | blue = CGFloat(hexValue & 0x0000FF) / 255.0 156 | 157 | 158 | default: 159 | print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8", terminator: "") 160 | } 161 | } else { 162 | print("Scan hex error") 163 | return UIColor.white 164 | } 165 | 166 | if let temp = alpha { 167 | useAlpha = temp 168 | } 169 | 170 | return UIColor(red: red, green: green, blue: blue, alpha: useAlpha) 171 | } 172 | } 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | extension UIWindow { 181 | /// 获取当前的window 182 | static var current: UIWindow? { 183 | if #available(iOS 13.0, *) { 184 | if let window = UIApplication.shared.connectedScenes 185 | .filter({$0.activationState == .foregroundActive}) 186 | .map({$0 as? UIWindowScene}) 187 | .compactMap({$0}) 188 | .first?.windows 189 | .filter({$0.isKeyWindow}).first{ 190 | return window 191 | }else if let window = UIApplication.shared.delegate?.window{ 192 | return window 193 | }else{ 194 | return nil 195 | } 196 | } else { 197 | if let window = UIApplication.shared.delegate?.window{ 198 | return window 199 | }else{ 200 | return nil 201 | } 202 | } 203 | } 204 | } 205 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /Example/BTBubble/Bubble/气泡的三种展示方式/BubbleShowStyleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleShowStyleViewController.swift 3 | // BTBubble_Example 4 | // 5 | // Created by qixin on 2023/12/19. 6 | // Copyright © 2023 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BubbleShowStyleViewController: BubbleBaseViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | isAutoShowBubble = false 17 | 18 | button.addTarget(self, action: #selector(showStyleEvent), for: .touchUpInside) 19 | 20 | 21 | } 22 | 23 | 24 | @objc func showStyleEvent() { 25 | 26 | switch button.tag { 27 | case 1000: 28 | 29 | let text = "明亮的月光洒在窗户纸上,好像地上泛起了一层白霜。我抬起头来,看那天窗外空中的明月,不由得低头沉思,想起远方的家乡。" 30 | bubble.show(text: text, direction: .auto, maxWidth: 200, from: button) 31 | case 1001: 32 | let attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12), NSAttributedString.Key.foregroundColor: UIColor.darkGray] 33 | let underline: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13), NSAttributedString.Key.foregroundColor: UIColor.systemBlue, NSAttributedString.Key.underlineStyle: NSUnderlineStyle.styleSingle.rawValue] 34 | let attributedText = NSMutableAttributedString(string: "该动态产在", attributes: attributes) 35 | attributedText.append(NSAttributedString(string: "XXXX有限公司", attributes: underline)) 36 | attributedText.append(NSAttributedString(string: ", 请及时关注,避免风险。", attributes: attributes)) 37 | bubble.show(attributedText: attributedText, direction: .up, maxWidth: 200, from: button) 38 | case 1002: 39 | let customView = UIView() 40 | customView.backgroundColor = UIColor.orange 41 | customView.frame.size = CGSize(width: 200, height: 100) 42 | 43 | let titleLabel = UILabel() 44 | titleLabel.text = "这是一个自定义的View" 45 | titleLabel.frame = CGRect(x: 10, y: 10, width: 180, height: 40) 46 | 47 | 48 | 49 | 50 | customView.addSubview(titleLabel) 51 | 52 | bubble.show(customView: customView, direction: .auto, from: button, duration: 10) 53 | 54 | default: 55 | break 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Example/BTBubble/Bubble/气泡的动画/BubbleAnimateViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleAnimateViewController.swift 3 | // BTBubble_Example 4 | // 5 | // Created by qixin on 2023/12/19. 6 | // Copyright © 2023 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import BTBubble 12 | 13 | class BubbleAnimateViewController: BubbleBaseViewController { 14 | 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | isAutoShowBubble = false 20 | 21 | button.addTarget(self, action: #selector(animateEvent), for: .touchUpInside) 22 | view.addSubview(button) 23 | button.snp.updateConstraints { make in 24 | make.top.equalTo(500) 25 | } 26 | 27 | initUI() 28 | 29 | } 30 | 31 | lazy var enterSegment: UISegmentedControl = { 32 | let items = ["进入动画选项", "缩放", "淡入", "自定义", "禁止"] 33 | let segmented = UISegmentedControl(items: items) 34 | segmented.selectedSegmentIndex = 1 35 | segmented.setEnabled(false, forSegmentAt: 0) 36 | segmented.setWidth(100, forSegmentAt: 0) 37 | return segmented 38 | }() 39 | 40 | lazy var showSegment: UISegmentedControl = { 41 | let items = ["动作动画选项", "弹性", "浮动", "脉冲", "禁止"] 42 | let segmented = UISegmentedControl(items: items) 43 | segmented.setEnabled(false, forSegmentAt: 0) 44 | segmented.setWidth(100, forSegmentAt: 0) 45 | segmented.selectedSegmentIndex = 1 46 | return segmented 47 | }() 48 | 49 | lazy var dismissSegment: UISegmentedControl = { 50 | let items = ["退出动画选项", "缩放", "淡出", "自定义", "禁止"] 51 | let segmented = UISegmentedControl(items: items) 52 | segmented.setEnabled(false, forSegmentAt: 0) 53 | segmented.setWidth(100, forSegmentAt: 0) 54 | segmented.selectedSegmentIndex = 1 55 | return segmented 56 | }() 57 | } 58 | 59 | extension BubbleAnimateViewController { 60 | 61 | @objc func animateEvent() { 62 | 63 | bubble.animationIn = 2 64 | bubble.delayIn = 0.2 65 | 66 | bubble.animationOut = 2 67 | bubble.delayOut = 0.2 68 | 69 | 70 | 71 | switch enterSegment.selectedSegmentIndex { 72 | case 1: 73 | bubble.entranceAnimation = .scale 74 | case 2: 75 | bubble.entranceAnimation = .fadeIn 76 | case 3: 77 | bubble.entranceAnimation = .custom 78 | bubble.entranceAnimationHandler = { [weak bubble] completion in 79 | bubble?.transform = CGAffineTransform(rotationAngle: 1) 80 | UIView.animate(withDuration: 0.5, animations: { 81 | bubble?.transform = .identity 82 | }, completion: { (_) in 83 | /// 一定要有回调 84 | completion() 85 | }) 86 | } 87 | case 4: 88 | bubble.entranceAnimation = .none 89 | default: 90 | break 91 | } 92 | 93 | 94 | switch showSegment.selectedSegmentIndex { 95 | case 1: 96 | bubble.actionAnimation = .bounce(2) 97 | case 2: 98 | bubble.actionAnimation = .float(offsetX: 2, offsetY: 2) 99 | case 3: 100 | bubble.actionAnimation = .pulse(1.2) 101 | case 4: 102 | bubble.actionAnimation = .none 103 | default: 104 | break 105 | } 106 | 107 | 108 | switch dismissSegment.selectedSegmentIndex { 109 | case 1: 110 | bubble.exitAnimation = .scale 111 | case 2: 112 | bubble.exitAnimation = .fadeOut 113 | case 3: 114 | bubble.exitAnimation = .custom 115 | bubble.exitAnimationHandler = { [weak bubble] completion in 116 | let ani: CAKeyframeAnimation = CAKeyframeAnimation(keyPath: "transform.rotation") 117 | ani.values = [-Double.pi/180*4,Double.pi/180*4,-Double.pi/180*4] 118 | ani.repeatCount = 10 119 | bubble?.layer.add(ani, forKey: "shakeAnimation") 120 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { 121 | bubble?.entranceAnimation = .scale 122 | bubble?.exitAnimation = .scale 123 | /// 一定要有回调 124 | completion() 125 | } 126 | } 127 | case 4: 128 | bubble.exitAnimation = .none 129 | default: 130 | break 131 | } 132 | 133 | bubble.show(text: "明亮的月光洒在窗户纸上,好像地上泛起了一层白霜。我抬起头来,看那天窗外空中的明月,不由得低头沉思,想起远方的家乡。", from: button) 134 | } 135 | } 136 | 137 | 138 | extension BubbleAnimateViewController { 139 | func initUI() { 140 | view.addSubview(enterSegment) 141 | enterSegment.snp.makeConstraints { make in 142 | make.left.equalTo(15) 143 | make.right.equalTo(-15) 144 | make.top.equalTo(100) 145 | make.height.equalTo(50) 146 | } 147 | 148 | view.addSubview(showSegment) 149 | showSegment.snp.makeConstraints { make in 150 | make.left.right.height.equalTo(enterSegment) 151 | make.top.equalTo(enterSegment.snp.bottom).offset(8) 152 | } 153 | 154 | view.addSubview(dismissSegment) 155 | dismissSegment.snp.makeConstraints { make in 156 | make.left.right.height.equalTo(enterSegment) 157 | make.top.equalTo(showSegment.snp.bottom).offset(8) 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Example/BTBubble/Bubble/气泡的手势 & 生命周期/GestureViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GestureViewController.swift 3 | // BTBubble_Example 4 | // 5 | // Created by qixin on 2023/12/18. 6 | // Copyright © 2023 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BTBubble 11 | import SnapKit 12 | 13 | class GestureViewController: BubbleBaseViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | isAutoShowBubble = false 19 | 20 | bubble.shouldDismissOnTap = true 21 | bubble.shouldDismissOnTapOutside = true 22 | bubble.shouldDismissOnScrollOutside = true 23 | 24 | 25 | 26 | 27 | bubble.tapHandler = { _ in 28 | print("点击气泡区域") 29 | } 30 | 31 | bubble.tapOutsideHandler = { _ in 32 | print("点击了气泡之外的区域") 33 | } 34 | 35 | bubble.tapTargetHandler = { _ in 36 | print("点击了目标区域") 37 | } 38 | 39 | bubble.scrollOutsideHandler = { _ in 40 | print("气泡外滑动") 41 | } 42 | 43 | bubble.appearHandler = { _ in 44 | print("气泡出现") 45 | } 46 | 47 | bubble.dismissHandler = { _ in 48 | print("气泡消失") 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Example/BTBubble/Bubble/气泡的方向/BubbleDirectionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleViewController.swift 3 | // BTMaterial_Example 4 | // 5 | // Created by qixin on 2022/11/22. 6 | // Copyright © 2022 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BTBubble 11 | 12 | class BubbleDirectionViewController: BubbleBaseViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | 18 | baseSetting() 19 | loadDirectionUI() 20 | } 21 | 22 | override func viewDidAppear(_ animated: Bool) { 23 | super.viewDidAppear(animated) 24 | // bubble.show(text: "将进酒 - 李白", direction: .up, from: centerButton) 25 | } 26 | 27 | 28 | 29 | lazy var bgScrollView: UIScrollView = { 30 | let sc = UIScrollView() 31 | sc.contentSize = CGSize(width: UIDevice.width, height: UIDevice.height * 1.5) 32 | sc.showsVerticalScrollIndicator = true 33 | 34 | return sc 35 | }() 36 | 37 | 38 | lazy var topButton: UIButton = createDirectionButton(tag: 0, text: "上") 39 | lazy var leftButton: UIButton = createDirectionButton(tag: 1, text: "左") 40 | lazy var rightButton: UIButton = createDirectionButton(tag: 2, text: "右") 41 | lazy var bottomButton: UIButton = createDirectionButton(tag: 3, text: "下") 42 | lazy var centerButton: UIButton = createDirectionButton(tag: 4, text: "中") 43 | } 44 | 45 | extension BubbleDirectionViewController { 46 | 47 | 48 | 49 | 50 | 51 | func update() { 52 | 53 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 54 | self.bubble.show(text: "将进酒 - 李白", direction: .up, maxWidth: 200, from: self.centerButton) 55 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 56 | self.bubble.show(text: "人生得意须尽欢", direction: .down, maxWidth: 200, from: self.bottomButton) 57 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 58 | self.bubble.show(text: "莫使金樽空对月", direction: .left, maxWidth: 200, from: self.leftButton) 59 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 60 | self.bubble.show(text: "天生我材必有用", direction: .up, maxWidth: 200, from: self.topButton) 61 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 62 | self.bubble.show(text: "千金散尽还复来", direction: .right, maxWidth: 200, from: self.rightButton) 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | 70 | } 71 | } 72 | 73 | 74 | extension BubbleDirectionViewController { 75 | 76 | func createDirectionButton(tag: Int, text: String) -> UIButton { 77 | let btn = UIButton.init(type: .custom) 78 | btn.backgroundColor = UIColor.orange 79 | btn.layer.cornerRadius = 30 80 | btn.layer.masksToBounds = true 81 | btn.setTitle(text, for: .normal) 82 | btn.tag = tag 83 | btn.addTarget(self, action: #selector(directionButtonEvent), for: .touchUpInside) 84 | 85 | return btn 86 | } 87 | 88 | 89 | func loadDirectionUI() { 90 | let wh = CGSize(width: 60, height: 60) 91 | 92 | bgScrollView.addSubview(centerButton) 93 | centerButton.snp.makeConstraints { 94 | $0.centerX.equalTo(UIDevice.width / 2) 95 | $0.size.equalTo(wh) 96 | $0.top.equalTo(200) 97 | } 98 | 99 | bgScrollView.addSubview(topButton) 100 | topButton.snp.makeConstraints { 101 | $0.centerX.size.equalTo(centerButton) 102 | $0.bottom.equalTo(centerButton.snp.top).offset(-10) 103 | } 104 | 105 | 106 | bgScrollView.addSubview(bottomButton) 107 | bottomButton.snp.makeConstraints { 108 | $0.centerX.size.equalTo(centerButton) 109 | $0.top.equalTo(centerButton.snp.bottom).offset(10) 110 | } 111 | 112 | 113 | bgScrollView.addSubview(leftButton) 114 | leftButton.snp.makeConstraints { 115 | $0.centerY.size.equalTo(centerButton) 116 | $0.right.equalTo(centerButton.snp.left).offset(-10) 117 | } 118 | 119 | bgScrollView.addSubview(rightButton) 120 | rightButton.snp.makeConstraints { 121 | $0.centerY.size.equalTo(centerButton) 122 | $0.left.equalTo(centerButton.snp.right).offset(10) 123 | } 124 | } 125 | 126 | 127 | 128 | @objc func directionButtonEvent(sender: UIButton) { 129 | 130 | let text = bubble.text ?? "" 131 | switch sender.tag { 132 | case 0: 133 | bubble.show(text: text, direction: .up, from: sender) 134 | 135 | case 1: 136 | bubble.show(text: text, direction: .left, from: sender) 137 | 138 | case 2: 139 | bubble.show(text: text, direction: .down, from: sender) 140 | 141 | case 3: 142 | bubble.show(text: text, direction: .right, from: sender) 143 | 144 | case 4: 145 | bubble = BTBubble() 146 | update() 147 | // bubble.show(text: text, direction: .auto, from: sender) 148 | 149 | default: 150 | break 151 | } 152 | } 153 | } 154 | 155 | 156 | 157 | extension BubbleDirectionViewController { 158 | 159 | 160 | func baseSetting() { 161 | button.isHidden = true 162 | view.backgroundColor = UIColor.white 163 | title = "气泡的方向" 164 | 165 | view.addSubview(bgScrollView) 166 | bgScrollView.snp.makeConstraints { 167 | $0.edges.equalToSuperview() 168 | } 169 | } 170 | } 171 | 172 | -------------------------------------------------------------------------------- /Example/BTBubble/Bubble/气泡的高阶用法/BubbleMenuViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleMenuViewController.swift 3 | // BTBubble_Example 4 | // 5 | // Created by qixin on 2023/12/19. 6 | // Copyright © 2023 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BTBubble 11 | 12 | 13 | class BubbleMenuViewController: BubbleBaseViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | isAutoShowBubble = false 19 | 20 | button.addTarget(self, action: #selector(menuEvent), for: .touchUpInside) 21 | 22 | 23 | } 24 | 25 | @objc override func event() { 26 | 27 | } 28 | 29 | 30 | @objc func menuEvent() { 31 | let menuBubble = BTBubble.makeMenuBubble() 32 | 33 | let item1 = BTBubble.Menu.Item(text: "监控动态", identifier: "", image: UIImage(named: "item1")) 34 | let item2 = BTBubble.Menu.Item(text: "监控列表", identifier: "", image: UIImage(named: "item2")) 35 | let item3 = BTBubble.Menu.Item(text: "取消监控", identifier: "", image: UIImage(named: "item3")) 36 | let item4 = BTBubble.Menu.Item(text: "取消监控", identifier: "", image: UIImage(named: "item4")) 37 | 38 | 39 | var config = BTBubble.Menu.Config() 40 | config.width = .auto(200) 41 | let menuView = BTBubbleMenu(items: [item1, item2, item3, item4], config: config) 42 | menuView.selectItemBlock = { item in 43 | print(item) 44 | } 45 | menuBubble.show(customView: menuView, direction: .auto, from: button, duration: nil) 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Example/BTBubble/Bubble/气泡的高阶用法/气泡联动/BubbleInputViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleInputViewController.swift 3 | // BTMaterial_Example 4 | // 5 | // Created by qixin on 2023/4/17. 6 | // Copyright © 2023 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import BTBubble 12 | class BubbleInputViewController: BubbleBaseViewController { 13 | 14 | /// 用于记录当前文字光标的位置 15 | private var currentPosition: Int = 0 16 | private var ignoreRecordMarkStart: Bool = false 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | 21 | button.isHidden = true 22 | isAutoShowBubble = false 23 | 24 | title = "气泡的联动" 25 | view.addSubview(textField) 26 | textField.inputView?.backgroundColor = UIColor.red 27 | } 28 | 29 | override func viewDidAppear(_ animated: Bool) { 30 | super.viewDidAppear(animated) 31 | textField.becomeFirstResponder() 32 | } 33 | 34 | lazy var textField: UITextField = { 35 | let tf = UITextField() 36 | tf.font = UIFont.systemFont(ofSize: 15) 37 | tf.frame = CGRect(x: 50, y: 200, width: 270, height: 50) 38 | tf.backgroundColor = UIColor.white 39 | tf.borderStyle = .roundedRect 40 | tf.addTarget(self, action: #selector(textFieldDidEditing(textField:)), for: .editingChanged) 41 | tf.addTarget(self, action: #selector(textFieldDidBegin(textField:)), for: .editingDidBegin) 42 | 43 | return tf 44 | }() 45 | 46 | 47 | 48 | lazy var bubbleView: BTBubble = { 49 | let b = BTBubble() 50 | b.arrowSize = CGSize(width: 6, height: 7) 51 | b.arrowOffset = .before(8) 52 | b.horizontalOffset = -130 53 | return b 54 | }() 55 | } 56 | 57 | extension BubbleInputViewController { 58 | @objc func textFieldDidEditing(textField: UITextField) { 59 | 60 | let textWidth = textField.text?.getWidth(font: UIFont.systemFont(ofSize: 15), height: 20) ?? 0 61 | 62 | var f = textField.convertFrameToScreen() 63 | var x = f.origin.x + textWidth 64 | print("x == \(x) || maxX = \(textField.frame.maxX)") 65 | 66 | if x > textField.frame.maxX - 8 { 67 | x = textField.frame.maxX - 8 68 | } 69 | 70 | f.origin.x = x 71 | 72 | 73 | bubbleView.from = f 74 | bubbleView.update(text: textField.text ?? "") 75 | } 76 | @objc func textFieldDidBegin(textField: UITextField) { 77 | // textField.selectedTextRange?.end 78 | bubbleView.show(text: "请输入", from: textField, duration: 100) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "yz选中=no@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "yz选中=no@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item1.imageset/yz选中=no@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Example/BTBubble/Images.xcassets/item1.imageset/yz选中=no@2x.png -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item1.imageset/yz选中=no@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Example/BTBubble/Images.xcassets/item1.imageset/yz选中=no@3x.png -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "yz选中=yes@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "yz选中=yes@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item2.imageset/yz选中=yes@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Example/BTBubble/Images.xcassets/item2.imageset/yz选中=yes@2x.png -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item2.imageset/yz选中=yes@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Example/BTBubble/Images.xcassets/item2.imageset/yz选中=yes@3x.png -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "选中=no@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "选中=no@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item3.imageset/选中=no@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Example/BTBubble/Images.xcassets/item3.imageset/选中=no@2x.png -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item3.imageset/选中=no@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Example/BTBubble/Images.xcassets/item3.imageset/选中=no@3x.png -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "选中=yes@2x.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "选中=yes@3x.png", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item4.imageset/选中=yes@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Example/BTBubble/Images.xcassets/item4.imageset/选中=yes@2x.png -------------------------------------------------------------------------------- /Example/BTBubble/Images.xcassets/item4.imageset/选中=yes@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Example/BTBubble/Images.xcassets/item4.imageset/选中=yes@3x.png -------------------------------------------------------------------------------- /Example/BTBubble/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Example/BTBubble/Model.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Model.swift 3 | // BTBubble_Example 4 | // 5 | // Created by qixin on 2023/12/18. 6 | // Copyright © 2023 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | struct Model { 13 | 14 | var title: String = "" 15 | 16 | var items: [SubModel] = [] 17 | } 18 | 19 | struct SubModel { 20 | var title: String = "" 21 | var vc: String = "" 22 | } 23 | -------------------------------------------------------------------------------- /Example/BTBubble/ViewController+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController+Extension.swift 3 | // BTBubble_Example 4 | // 5 | // Created by qixin on 2023/12/18. 6 | // Copyright © 2023 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | 13 | extension ViewController { 14 | 15 | func casePresentation(indexPath: IndexPath) -> UIViewController? { 16 | let model = dataArray[indexPath.section] 17 | let subModel = model.items[indexPath.row] 18 | guard let vc = createViewControllerObject(form: subModel.vc) else { return nil } 19 | 20 | guard let tempVc = vc as? BubbleBaseViewController else { return nil } 21 | 22 | switch indexPath.section { 23 | case 0: 24 | 25 | 26 | tempVc.title = subModel.title 27 | 28 | switch indexPath.row { 29 | case 0: 30 | tempVc.bubble.fillColor = UIColor.red.withAlphaComponent(0.2) 31 | case 1: 32 | tempVc.bubble.cornerRadius = 8 33 | case 2: 34 | tempVc.bubble.borderColor = UIColor.clear 35 | tempVc.bubble.borderWidth = 0.0 36 | case 3: 37 | tempVc.bubble.shadowColor = UIColor.red 38 | tempVc.bubble.shadowOffset = .zero 39 | tempVc.bubble.shadowRadius = 4 40 | tempVc.bubble.shadowOpacity = 0.2 41 | 42 | case 4: 43 | tempVc.bubble.edgeInsets = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) 44 | default: 45 | break 46 | } 47 | return tempVc 48 | 49 | 50 | case 1: 51 | 52 | switch indexPath.row { 53 | case 0: 54 | tempVc.title = subModel.title 55 | tempVc.bubble.font = UIFont.systemFont(ofSize: 20) 56 | tempVc.bubble.textColor = UIColor.red 57 | tempVc.bubble.textAlignment = .center 58 | 59 | case 1: 60 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 61 | tempVc.bubble.update(text: "床前看月光,疑是地上霜。") 62 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 63 | tempVc.bubble.update(text: "抬头望山月,低头思故乡。") 64 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) { 65 | tempVc.bubble.hide() 66 | } 67 | } 68 | } 69 | default: 70 | break 71 | } 72 | 73 | 74 | 75 | return tempVc 76 | 77 | 78 | case 2: 79 | 80 | tempVc.title = subModel.title 81 | 82 | switch indexPath.row { 83 | case 0: 84 | tempVc.bubble.arrowSize = CGSize(width: 20, height: 20) 85 | case 1: 86 | tempVc.bubble.arrowSize = CGSize(width: 20, height: 20) 87 | tempVc.bubble.arrowRadius = 10 88 | case 2: 89 | tempVc.bubble.arrowOffset = .auto(0) 90 | 91 | case 3: 92 | tempVc.bubble.verticalOffset = 50 93 | 94 | case 4: 95 | tempVc.bubble.horizontalOffset = -50 96 | default: 97 | break 98 | } 99 | return tempVc 100 | 101 | 102 | case 3: 103 | 104 | tempVc.title = subModel.title 105 | 106 | switch indexPath.row { 107 | case 0: 108 | tempVc.bubble.distanceFromBoundary = 100 109 | case 1: 110 | tempVc.bubble.verticalOffset = 50 111 | case 2: 112 | tempVc.bubble.horizontalOffset = -100 113 | case 3: 114 | tempVc.updateFrom() 115 | case 4: 116 | tempVc.bubble.horizontalOffset = -50 117 | default: 118 | break 119 | } 120 | return tempVc 121 | 122 | 123 | case 4: 124 | 125 | tempVc.title = subModel.title 126 | 127 | switch indexPath.row { 128 | case 0: 129 | tempVc.bubble.maskColor = UIColor.blue.withAlphaComponent(0.2) 130 | tempVc.bubble.shouldShowMask = true 131 | case 1: 132 | tempVc.bubble.maskColor = UIColor.blue.withAlphaComponent(0.2) 133 | tempVc.bubble.shouldShowMask = true 134 | tempVc.bubble.shouldCutoutMask = true 135 | case 2: 136 | tempVc.bubble.maskColor = UIColor.blue.withAlphaComponent(0.2) 137 | tempVc.bubble.shouldShowMask = true 138 | tempVc.bubble.shouldCutoutMask = true 139 | tempVc.isCustomCutout = true 140 | 141 | default: 142 | break 143 | } 144 | return tempVc 145 | 146 | 147 | case 5: 148 | 149 | let dirVc = BubbleDirectionViewController() 150 | dirVc.title = subModel.title 151 | 152 | switch indexPath.row { 153 | case 0: 154 | dirVc.isAutoShowBubble = false 155 | break 156 | case 1: 157 | dirVc.isAutoShowBubble = false 158 | dirVc.update() 159 | break 160 | default: 161 | break 162 | } 163 | return dirVc 164 | 165 | 166 | case 6: 167 | let dirVc = BubbleAnimateViewController() 168 | dirVc.title = "气泡的动画" 169 | return dirVc 170 | 171 | case 7: 172 | let ge = GestureViewController() 173 | ge.title = "气泡的手势" 174 | return ge 175 | 176 | case 8: 177 | let ge = GestureViewController() 178 | ge.title = "气泡的生命周期" 179 | return ge 180 | 181 | case 9: 182 | 183 | let style = BubbleShowStyleViewController() 184 | style.title = subModel.title 185 | 186 | switch indexPath.row { 187 | case 0: 188 | style.button.tag = 1000 189 | 190 | case 1: 191 | style.button.tag = 1001 192 | 193 | case 2: 194 | style.button.tag = 1002 195 | 196 | default: 197 | break 198 | } 199 | return style 200 | 201 | 202 | case 10: 203 | 204 | 205 | 206 | switch indexPath.row { 207 | case 0: 208 | let menu = BubbleMenuViewController() 209 | menu.title = subModel.title 210 | return menu 211 | 212 | case 1: 213 | let input = BubbleInputViewController() 214 | input.title = subModel.title 215 | return input 216 | 217 | default: 218 | break 219 | } 220 | 221 | 222 | default: 223 | break 224 | } 225 | 226 | return vc 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /Example/BTBubble/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // BTBubble 4 | // 5 | // Created by Mccc on 12/18/2023. 6 | // Copyright (c) 2023 Mccc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | 13 | class ViewController: UIViewController { 14 | 15 | 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | 20 | title = "气泡" 21 | view.addSubview(tableView) 22 | } 23 | 24 | // 添加一个跟随光标滚动的模式 25 | var dataArray: [Model] = [ 26 | Model(title: "气泡的外观设置", 27 | items: [ 28 | SubModel(title: "气泡的背景颜色", vc: "BubbleBaseViewController"), 29 | SubModel(title: "气泡的圆角", vc: "BubbleBaseViewController"), 30 | SubModel(title: "气泡的边框", vc: "BubbleBaseViewController"), 31 | SubModel(title: "气泡的阴影", vc: "BubbleBaseViewController"), 32 | SubModel(title: "气泡的内边距", vc: "BubbleBaseViewController"), 33 | ] 34 | ), 35 | 36 | 37 | Model(title: "气泡的文字", 38 | items: [ 39 | SubModel(title: "文字的设置", vc: "BubbleBaseViewController"), 40 | SubModel(title: "文字的更新内容", vc: "BubbleBaseViewController") 41 | 42 | ] 43 | ), 44 | 45 | 46 | Model(title: "气泡的箭头", 47 | items: [ 48 | SubModel(title: "箭头的大小", vc: "BubbleBaseViewController"), 49 | SubModel(title: "箭头的圆角", vc: "BubbleBaseViewController"), 50 | SubModel(title: "箭头的偏移量", vc: "BubbleBaseViewController"), 51 | ] 52 | ), 53 | 54 | 55 | Model(title: "气泡的位置", 56 | items: [ 57 | SubModel(title: "气泡距离屏幕最小间距", vc: "BubbleBaseViewController"), 58 | SubModel(title: "气泡相对于目标控件的中心的偏移量", vc: "BubbleBaseViewController"), 59 | SubModel(title: "气泡(整体)相对于目标控件的中心的偏移量", vc: "BubbleBaseViewController"), 60 | SubModel(title: "气泡的目标区域设置", vc: "BubbleBaseViewController"), 61 | ] 62 | ), 63 | 64 | 65 | Model(title: "气泡的遮罩层", 66 | items: [ 67 | SubModel(title: "遮罩层的颜色", vc: "BubbleBaseViewController"), 68 | SubModel(title: "遮罩层的挖孔", vc: "BubbleBaseViewController"), 69 | SubModel(title: "遮罩层的自定义挖孔", vc: "BubbleBaseViewController"), 70 | ] 71 | ), 72 | 73 | 74 | Model(title: "气泡的方向", 75 | items: [ 76 | SubModel(title: "气泡的方向", vc: "BubbleDirectionViewController"), 77 | SubModel(title: "气泡自动更换方向", vc: "BubbleDirectionViewController"), 78 | ] 79 | ), 80 | 81 | Model(title: "气泡的动画", 82 | items: [ 83 | SubModel(title: "气泡的开始动画", vc: "BubbleAnimateViewController"), 84 | SubModel(title: "气泡的动作动画", vc: "BubbleAnimateViewController"), 85 | SubModel(title: "气泡的退出动画", vc: "BubbleAnimateViewController"), 86 | ] 87 | ), 88 | 89 | Model(title: "气泡的手势", 90 | items: [ 91 | SubModel(title: "点击气泡是否支持消失", vc: "BubbleBaseViewController"), 92 | SubModel(title: "点击气泡外区域是否支持消失", vc: "BubbleBaseViewController"), 93 | SubModel(title: "在气泡外滑动是否隐藏气泡", vc: "BubbleBaseViewController"), 94 | ] 95 | ), 96 | 97 | Model(title: "气泡的生命周期", 98 | items: [ 99 | SubModel(title: "气泡出现", vc: "BubbleBaseViewController"), 100 | SubModel(title: "气泡消失", vc: "BubbleBaseViewController"), 101 | ] 102 | ), 103 | 104 | Model(title: "气泡的三种展示方式", 105 | items: [ 106 | SubModel(title: "文字类型", vc: "BubbleBaseViewController"), 107 | SubModel(title: "富文本类型", vc: "BubbleBaseViewController"), 108 | SubModel(title: "自定类型", vc: "BubbleBaseViewController"), 109 | ] 110 | ), 111 | 112 | Model(title: "气泡的高阶用法", 113 | items: [ 114 | SubModel(title: "菜单气泡", vc: "BubbleMenuViewController"), 115 | SubModel(title: "输入联动", vc: "BubbleInputViewController"), 116 | ] 117 | ), 118 | ] 119 | 120 | 121 | lazy var tableView: UITableView = { 122 | let tb = UITableView.init(frame: .zero, style: .grouped) 123 | tb.register(UITableViewCell.self, forCellReuseIdentifier: "cell") 124 | tb.delegate = self 125 | tb.dataSource = self 126 | tb.frame = view.frame 127 | return tb 128 | }() 129 | 130 | 131 | 132 | } 133 | 134 | 135 | extension ViewController: UITableViewDelegate, UITableViewDataSource { 136 | 137 | 138 | func numberOfSections(in tableView: UITableView) -> Int { 139 | return dataArray.count 140 | } 141 | 142 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 143 | let model = dataArray[section] 144 | return model.items.count 145 | } 146 | 147 | func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 148 | return 50 149 | } 150 | 151 | func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 152 | let label = UILabel() 153 | label.font = UIFont.boldSystemFont(ofSize: 20) 154 | label.backgroundColor = UIColor.red.withAlphaComponent(0.1) 155 | label.text = " " + dataArray[section].title 156 | return label 157 | } 158 | 159 | 160 | 161 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 162 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 163 | let model = dataArray[indexPath.section] 164 | cell.textLabel?.text = model.items[indexPath.row].title 165 | cell.selectionStyle = .none 166 | return cell 167 | } 168 | 169 | 170 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 171 | 172 | if let vc = casePresentation(indexPath: indexPath) { 173 | navigationController?.pushViewController(vc, animated: true) 174 | } 175 | } 176 | } 177 | 178 | 179 | extension ViewController { 180 | 181 | func createViewControllerObject(form className: String) -> UIViewController? { 182 | let projectName = Bundle.main.infoDictionary?["CFBundleName"] as? String ?? "" 183 | let classStringName = projectName + "." + className 184 | if let viewControllerClass = NSClassFromString(classStringName) as? UIViewController.Type { 185 | let viewController = viewControllerClass.init() 186 | return viewController 187 | } else { 188 | return nil 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | platform :ios, '10.0' 4 | 5 | target 'BTBubble_Example' do 6 | pod 'BTBubble', :path => '../' 7 | 8 | pod 'SnapKit' 9 | 10 | target 'BTBubble_Tests' do 11 | inherit! :search_paths 12 | 13 | 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - BTBubble (0.0.5) 3 | - SnapKit (5.6.0) 4 | 5 | DEPENDENCIES: 6 | - BTBubble (from `../`) 7 | - SnapKit 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - SnapKit 12 | 13 | EXTERNAL SOURCES: 14 | BTBubble: 15 | :path: "../" 16 | 17 | SPEC CHECKSUMS: 18 | BTBubble: c2a296a15665a742fb547f70414ee5b5252863e3 19 | SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25 20 | 21 | PODFILE CHECKSUM: 183ed891eac6bf1191e28517bce96c625966fd0a 22 | 23 | COCOAPODS: 1.11.2 24 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/BTBubble.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BTBubble", 3 | "version": "0.0.5", 4 | "summary": "气泡", 5 | "homepage": "https://github.com/intsig171", 6 | "license": { 7 | "type": "MIT", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "Mccc": "Mccc" 12 | }, 13 | "source": { 14 | "git": "https://github.com/intsig171/BTBubble.git", 15 | "tag": "0.0.5" 16 | }, 17 | "platforms": { 18 | "ios": "11.0" 19 | }, 20 | "swift_versions": "5.0", 21 | "source_files": "BTBubble/Classes/**/*", 22 | "swift_version": "5.0" 23 | } 24 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - BTBubble (0.0.5) 3 | - SnapKit (5.6.0) 4 | 5 | DEPENDENCIES: 6 | - BTBubble (from `../`) 7 | - SnapKit 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - SnapKit 12 | 13 | EXTERNAL SOURCES: 14 | BTBubble: 15 | :path: "../" 16 | 17 | SPEC CHECKSUMS: 18 | BTBubble: c2a296a15665a742fb547f70414ee5b5252863e3 19 | SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25 20 | 21 | PODFILE CHECKSUM: 183ed891eac6bf1191e28517bce96c625966fd0a 22 | 23 | COCOAPODS: 1.11.2 24 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | SnapKit is a DSL to make Auto Layout easy on both iOS and OS X. 4 | 5 | [![Build Status](https://travis-ci.org/SnapKit/SnapKit.svg)](https://travis-ci.org/SnapKit/SnapKit) 6 | [![Platform](https://img.shields.io/cocoapods/p/SnapKit.svg?style=flat)](https://github.com/SnapKit/SnapKit) 7 | [![Cocoapods Compatible](https://img.shields.io/cocoapods/v/SnapKit.svg)](https://cocoapods.org/pods/SnapKit) 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 9 | 10 | #### ⚠️ **To use with Swift 4.x please ensure you are using >= 4.0.0** ⚠️ 11 | #### ⚠️ **To use with Swift 5.x please ensure you are using >= 5.0.0** ⚠️ 12 | 13 | ## Contents 14 | 15 | - [Requirements](#requirements) 16 | - [Migration Guides](#migration-guides) 17 | - [Communication](#communication) 18 | - [Installation](#installation) 19 | - [Usage](#usage) 20 | - [Credits](#credits) 21 | - [License](#license) 22 | 23 | ## Requirements 24 | 25 | - iOS 10.0+ / Mac OS X 10.12+ / tvOS 10.0+ 26 | - Xcode 10.0+ 27 | - Swift 4.0+ 28 | 29 | ## Migration Guides 30 | 31 | - [SnapKit 3.0 Migration Guide](Documentation/SnapKit%203.0%20Migration%20Guide.md) 32 | 33 | ## Communication 34 | 35 | - If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit). (Tag 'snapkit') 36 | - If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit). 37 | - If you **found a bug**, open an issue. 38 | - If you **have a feature request**, open an issue. 39 | - If you **want to contribute**, submit a pull request. 40 | 41 | 42 | ## Installation 43 | 44 | ### CocoaPods 45 | 46 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: 47 | 48 | ```bash 49 | $ gem install cocoapods 50 | ``` 51 | 52 | > CocoaPods 1.1.0+ is required to build SnapKit 4.0.0+. 53 | 54 | To integrate SnapKit into your Xcode project using CocoaPods, specify it in your `Podfile`: 55 | 56 | ```ruby 57 | source 'https://github.com/CocoaPods/Specs.git' 58 | platform :ios, '10.0' 59 | use_frameworks! 60 | 61 | target '' do 62 | pod 'SnapKit', '~> 5.6.0' 63 | end 64 | ``` 65 | 66 | Then, run the following command: 67 | 68 | ```bash 69 | $ pod install 70 | ``` 71 | 72 | ### Carthage 73 | 74 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 75 | 76 | You can install Carthage with [Homebrew](http://brew.sh/) using the following command: 77 | 78 | ```bash 79 | $ brew update 80 | $ brew install carthage 81 | ``` 82 | 83 | To integrate SnapKit into your Xcode project using Carthage, specify it in your `Cartfile`: 84 | 85 | ```ogdl 86 | github "SnapKit/SnapKit" ~> 5.0.0 87 | ``` 88 | 89 | Run `carthage update` to build the framework and drag the built `SnapKit.framework` into your Xcode project. 90 | 91 | ### Swift Package Manager 92 | 93 | [Swift Package Manager](https://swift.org/package-manager/) is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies. 94 | 95 | > Xcode 11+ is required to build SnapKit using Swift Package Manager. 96 | 97 | To integrate SnapKit into your Xcode project using Swift Package Manager, add it to the dependencies value of your `Package.swift`: 98 | 99 | ```swift 100 | dependencies: [ 101 | .package(url: "https://github.com/SnapKit/SnapKit.git", .upToNextMajor(from: "5.0.1")) 102 | ] 103 | ``` 104 | 105 | ### Manually 106 | 107 | If you prefer not to use either of the aforementioned dependency managers, you can integrate SnapKit into your project manually. 108 | 109 | --- 110 | 111 | ## Usage 112 | 113 | ### Quick Start 114 | 115 | ```swift 116 | import SnapKit 117 | 118 | class MyViewController: UIViewController { 119 | 120 | lazy var box = UIView() 121 | 122 | override func viewDidLoad() { 123 | super.viewDidLoad() 124 | 125 | self.view.addSubview(box) 126 | box.backgroundColor = .green 127 | box.snp.makeConstraints { (make) -> Void in 128 | make.width.height.equalTo(50) 129 | make.center.equalTo(self.view) 130 | } 131 | } 132 | 133 | } 134 | ``` 135 | 136 | ### Playground 137 | You can try SnapKit in Playground. 138 | 139 | **Note:** 140 | 141 | > To try SnapKit in playground, open `SnapKit.xcworkspace` and build SnapKit.framework for any simulator first. 142 | 143 | ### Resources 144 | 145 | - [Documentation](https://snapkit.github.io/SnapKit/docs/) 146 | - [F.A.Q.](https://snapkit.github.io/SnapKit/faq/) 147 | 148 | ## Credits 149 | 150 | - Robert Payne ([@robertjpayne](https://twitter.com/robertjpayne)) 151 | - Many other contributors 152 | 153 | ## License 154 | 155 | SnapKit is released under the MIT license. See LICENSE for details. 156 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | public typealias ConstraintInterfaceLayoutDirection = UIUserInterfaceLayoutDirection 27 | #else 28 | import AppKit 29 | public typealias ConstraintInterfaceLayoutDirection = NSUserInterfaceLayoutDirection 30 | #endif 31 | 32 | 33 | public struct ConstraintConfig { 34 | 35 | public static var interfaceLayoutDirection: ConstraintInterfaceLayoutDirection = .leftToRight 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintDescription.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintDescription { 32 | 33 | internal let item: LayoutConstraintItem 34 | internal var attributes: ConstraintAttributes 35 | internal var relation: ConstraintRelation? = nil 36 | internal var sourceLocation: (String, UInt)? = nil 37 | internal var label: String? = nil 38 | internal var related: ConstraintItem? = nil 39 | internal var multiplier: ConstraintMultiplierTarget = 1.0 40 | internal var constant: ConstraintConstantTarget = 0.0 41 | internal var priority: ConstraintPriorityTarget = 1000.0 42 | internal lazy var constraint: Constraint? = { 43 | guard let relation = self.relation, 44 | let related = self.related, 45 | let sourceLocation = self.sourceLocation else { 46 | return nil 47 | } 48 | let from = ConstraintItem(target: self.item, attributes: self.attributes) 49 | 50 | return Constraint( 51 | from: from, 52 | to: related, 53 | relation: relation, 54 | sourceLocation: sourceLocation, 55 | label: self.label, 56 | multiplier: self.multiplier, 57 | constant: self.constant, 58 | priority: self.priority 59 | ) 60 | }() 61 | 62 | // MARK: Initialization 63 | 64 | internal init(item: LayoutConstraintItem, attributes: ConstraintAttributes) { 65 | self.item = item 66 | self.attributes = attributes 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintDirectionalInsetTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | #if os(iOS) || os(tvOS) 31 | public protocol ConstraintDirectionalInsetTarget: ConstraintConstantTarget { 32 | } 33 | 34 | @available(iOS 11.0, tvOS 11.0, *) 35 | extension ConstraintDirectionalInsets: ConstraintDirectionalInsetTarget { 36 | } 37 | 38 | extension ConstraintDirectionalInsetTarget { 39 | 40 | @available(iOS 11.0, tvOS 11.0, *) 41 | internal var constraintDirectionalInsetTargetValue: ConstraintDirectionalInsets { 42 | if let amount = self as? ConstraintDirectionalInsets { 43 | return amount 44 | } else { 45 | return ConstraintDirectionalInsets(top: 0, leading: 0, bottom: 0, trailing: 0) 46 | } 47 | } 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintDirectionalInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | @available(iOS 11.0, tvOS 11.0, *) 33 | public typealias ConstraintDirectionalInsets = NSDirectionalEdgeInsets 34 | #endif 35 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintInsetTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintInsetTarget: ConstraintConstantTarget { 32 | } 33 | 34 | extension Int: ConstraintInsetTarget { 35 | } 36 | 37 | extension UInt: ConstraintInsetTarget { 38 | } 39 | 40 | extension Float: ConstraintInsetTarget { 41 | } 42 | 43 | extension Double: ConstraintInsetTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintInsetTarget { 47 | } 48 | 49 | extension ConstraintInsets: ConstraintInsetTarget { 50 | } 51 | 52 | extension ConstraintInsetTarget { 53 | 54 | internal var constraintInsetTargetValue: ConstraintInsets { 55 | if let amount = self as? ConstraintInsets { 56 | return amount 57 | } else if let amount = self as? Float { 58 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 59 | } else if let amount = self as? Double { 60 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 61 | } else if let amount = self as? CGFloat { 62 | return ConstraintInsets(top: amount, left: amount, bottom: amount, right: amount) 63 | } else if let amount = self as? Int { 64 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 65 | } else if let amount = self as? UInt { 66 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 67 | } else { 68 | return ConstraintInsets(top: 0, left: 0, bottom: 0, right: 0) 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | public typealias ConstraintInsets = UIEdgeInsets 33 | #else 34 | public typealias ConstraintInsets = NSEdgeInsets 35 | #endif 36 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public final class ConstraintItem { 32 | 33 | internal weak var target: AnyObject? 34 | internal let attributes: ConstraintAttributes 35 | 36 | internal init(target: AnyObject?, attributes: ConstraintAttributes) { 37 | self.target = target 38 | self.attributes = attributes 39 | } 40 | 41 | internal var layoutConstraintItem: LayoutConstraintItem? { 42 | return self.target as? LayoutConstraintItem 43 | } 44 | 45 | } 46 | 47 | public func ==(lhs: ConstraintItem, rhs: ConstraintItem) -> Bool { 48 | // pointer equality 49 | guard lhs !== rhs else { 50 | return true 51 | } 52 | 53 | // must both have valid targets and identical attributes 54 | guard let target1 = lhs.target, 55 | let target2 = rhs.target, 56 | target1 === target2 && lhs.attributes == rhs.attributes else { 57 | return false 58 | } 59 | 60 | return true 61 | } 62 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintLayoutGuide+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #endif 27 | 28 | 29 | @available(iOS 9.0, OSX 10.11, *) 30 | public extension ConstraintLayoutGuide { 31 | 32 | var snp: ConstraintLayoutGuideDSL { 33 | return ConstraintLayoutGuideDSL(guide: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintLayoutGuide.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | @available(iOS 9.0, *) 33 | public typealias ConstraintLayoutGuide = UILayoutGuide 34 | #else 35 | @available(OSX 10.11, *) 36 | public typealias ConstraintLayoutGuide = NSLayoutGuide 37 | #endif 38 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintLayoutGuideDSL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | @available(iOS 9.0, OSX 10.11, *) 32 | public struct ConstraintLayoutGuideDSL: ConstraintAttributesDSL { 33 | 34 | @discardableResult 35 | public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { 36 | return ConstraintMaker.prepareConstraints(item: self.guide, closure: closure) 37 | } 38 | 39 | public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 40 | ConstraintMaker.makeConstraints(item: self.guide, closure: closure) 41 | } 42 | 43 | public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 44 | ConstraintMaker.remakeConstraints(item: self.guide, closure: closure) 45 | } 46 | 47 | public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 48 | ConstraintMaker.updateConstraints(item: self.guide, closure: closure) 49 | } 50 | 51 | public func removeConstraints() { 52 | ConstraintMaker.removeConstraints(item: self.guide) 53 | } 54 | 55 | public var target: AnyObject? { 56 | return self.guide 57 | } 58 | 59 | internal let guide: ConstraintLayoutGuide 60 | 61 | internal init(guide: ConstraintLayoutGuide) { 62 | self.guide = guide 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintLayoutSupport.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | @available(iOS 8.0, *) 33 | public typealias ConstraintLayoutSupport = UILayoutSupport 34 | #else 35 | public class ConstraintLayoutSupport {} 36 | #endif 37 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintLayoutSupportDSL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | @available(iOS 8.0, *) 32 | public struct ConstraintLayoutSupportDSL: ConstraintDSL { 33 | 34 | public var target: AnyObject? { 35 | return self.support 36 | } 37 | 38 | internal let support: ConstraintLayoutSupport 39 | 40 | internal init(support: ConstraintLayoutSupport) { 41 | self.support = support 42 | 43 | } 44 | 45 | public var top: ConstraintItem { 46 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top) 47 | } 48 | 49 | public var bottom: ConstraintItem { 50 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom) 51 | } 52 | 53 | public var height: ConstraintItem { 54 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintMakerEditable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerEditable: ConstraintMakerPrioritizable { 32 | 33 | @discardableResult 34 | public func multipliedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable { 35 | self.description.multiplier = amount 36 | return self 37 | } 38 | 39 | @discardableResult 40 | public func dividedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable { 41 | return self.multipliedBy(1.0 / amount.constraintMultiplierTargetValue) 42 | } 43 | 44 | @discardableResult 45 | public func offset(_ amount: ConstraintOffsetTarget) -> ConstraintMakerEditable { 46 | self.description.constant = amount.constraintOffsetTargetValue 47 | return self 48 | } 49 | 50 | @discardableResult 51 | public func inset(_ amount: ConstraintInsetTarget) -> ConstraintMakerEditable { 52 | self.description.constant = amount.constraintInsetTargetValue 53 | return self 54 | } 55 | 56 | #if os(iOS) || os(tvOS) 57 | @discardableResult 58 | @available(iOS 11.0, tvOS 11.0, *) 59 | public func inset(_ amount: ConstraintDirectionalInsetTarget) -> ConstraintMakerEditable { 60 | self.description.constant = amount.constraintDirectionalInsetTargetValue 61 | return self 62 | } 63 | #endif 64 | } 65 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintMakerExtendable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerExtendable: ConstraintMakerRelatable { 32 | 33 | public var left: ConstraintMakerExtendable { 34 | self.description.attributes += .left 35 | return self 36 | } 37 | 38 | public var top: ConstraintMakerExtendable { 39 | self.description.attributes += .top 40 | return self 41 | } 42 | 43 | public var bottom: ConstraintMakerExtendable { 44 | self.description.attributes += .bottom 45 | return self 46 | } 47 | 48 | public var right: ConstraintMakerExtendable { 49 | self.description.attributes += .right 50 | return self 51 | } 52 | 53 | public var leading: ConstraintMakerExtendable { 54 | self.description.attributes += .leading 55 | return self 56 | } 57 | 58 | public var trailing: ConstraintMakerExtendable { 59 | self.description.attributes += .trailing 60 | return self 61 | } 62 | 63 | public var width: ConstraintMakerExtendable { 64 | self.description.attributes += .width 65 | return self 66 | } 67 | 68 | public var height: ConstraintMakerExtendable { 69 | self.description.attributes += .height 70 | return self 71 | } 72 | 73 | public var centerX: ConstraintMakerExtendable { 74 | self.description.attributes += .centerX 75 | return self 76 | } 77 | 78 | public var centerY: ConstraintMakerExtendable { 79 | self.description.attributes += .centerY 80 | return self 81 | } 82 | 83 | @available(*, deprecated, renamed:"lastBaseline") 84 | public var baseline: ConstraintMakerExtendable { 85 | self.description.attributes += .lastBaseline 86 | return self 87 | } 88 | 89 | public var lastBaseline: ConstraintMakerExtendable { 90 | self.description.attributes += .lastBaseline 91 | return self 92 | } 93 | 94 | @available(iOS 8.0, OSX 10.11, *) 95 | public var firstBaseline: ConstraintMakerExtendable { 96 | self.description.attributes += .firstBaseline 97 | return self 98 | } 99 | 100 | @available(iOS 8.0, *) 101 | public var leftMargin: ConstraintMakerExtendable { 102 | self.description.attributes += .leftMargin 103 | return self 104 | } 105 | 106 | @available(iOS 8.0, *) 107 | public var rightMargin: ConstraintMakerExtendable { 108 | self.description.attributes += .rightMargin 109 | return self 110 | } 111 | 112 | @available(iOS 8.0, *) 113 | public var topMargin: ConstraintMakerExtendable { 114 | self.description.attributes += .topMargin 115 | return self 116 | } 117 | 118 | @available(iOS 8.0, *) 119 | public var bottomMargin: ConstraintMakerExtendable { 120 | self.description.attributes += .bottomMargin 121 | return self 122 | } 123 | 124 | @available(iOS 8.0, *) 125 | public var leadingMargin: ConstraintMakerExtendable { 126 | self.description.attributes += .leadingMargin 127 | return self 128 | } 129 | 130 | @available(iOS 8.0, *) 131 | public var trailingMargin: ConstraintMakerExtendable { 132 | self.description.attributes += .trailingMargin 133 | return self 134 | } 135 | 136 | @available(iOS 8.0, *) 137 | public var centerXWithinMargins: ConstraintMakerExtendable { 138 | self.description.attributes += .centerXWithinMargins 139 | return self 140 | } 141 | 142 | @available(iOS 8.0, *) 143 | public var centerYWithinMargins: ConstraintMakerExtendable { 144 | self.description.attributes += .centerYWithinMargins 145 | return self 146 | } 147 | 148 | public var edges: ConstraintMakerExtendable { 149 | self.description.attributes += .edges 150 | return self 151 | } 152 | public var horizontalEdges: ConstraintMakerExtendable { 153 | self.description.attributes += .horizontalEdges 154 | return self 155 | } 156 | public var verticalEdges: ConstraintMakerExtendable { 157 | self.description.attributes += .verticalEdges 158 | return self 159 | } 160 | public var directionalEdges: ConstraintMakerExtendable { 161 | self.description.attributes += .directionalEdges 162 | return self 163 | } 164 | public var directionalHorizontalEdges: ConstraintMakerExtendable { 165 | self.description.attributes += .directionalHorizontalEdges 166 | return self 167 | } 168 | public var directionalVerticalEdges: ConstraintMakerExtendable { 169 | self.description.attributes += .directionalVerticalEdges 170 | return self 171 | } 172 | public var size: ConstraintMakerExtendable { 173 | self.description.attributes += .size 174 | return self 175 | } 176 | 177 | @available(iOS 8.0, *) 178 | public var margins: ConstraintMakerExtendable { 179 | self.description.attributes += .margins 180 | return self 181 | } 182 | 183 | @available(iOS 8.0, *) 184 | public var directionalMargins: ConstraintMakerExtendable { 185 | self.description.attributes += .directionalMargins 186 | return self 187 | } 188 | 189 | @available(iOS 8.0, *) 190 | public var centerWithinMargins: ConstraintMakerExtendable { 191 | self.description.attributes += .centerWithinMargins 192 | return self 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintMakerFinalizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerFinalizable { 32 | 33 | internal let description: ConstraintDescription 34 | 35 | internal init(_ description: ConstraintDescription) { 36 | self.description = description 37 | } 38 | 39 | @discardableResult 40 | public func labeled(_ label: String) -> ConstraintMakerFinalizable { 41 | self.description.label = label 42 | return self 43 | } 44 | 45 | public var constraint: Constraint { 46 | return self.description.constraint! 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintMakerPrioritizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | @available(*, deprecated, message:"Use ConstraintMakerPrioritizable instead.") 31 | public typealias ConstraintMakerPriortizable = ConstraintMakerPrioritizable 32 | 33 | public class ConstraintMakerPrioritizable: ConstraintMakerFinalizable { 34 | 35 | @discardableResult 36 | public func priority(_ amount: ConstraintPriority) -> ConstraintMakerFinalizable { 37 | self.description.priority = amount.value 38 | return self 39 | } 40 | 41 | @discardableResult 42 | public func priority(_ amount: ConstraintPriorityTarget) -> ConstraintMakerFinalizable { 43 | self.description.priority = amount 44 | return self 45 | } 46 | 47 | @available(*, deprecated, message:"Use priority(.required) instead.") 48 | @discardableResult 49 | public func priorityRequired() -> ConstraintMakerFinalizable { 50 | return self.priority(.required) 51 | } 52 | 53 | @available(*, deprecated, message:"Use priority(.high) instead.") 54 | @discardableResult 55 | public func priorityHigh() -> ConstraintMakerFinalizable { 56 | return self.priority(.high) 57 | } 58 | 59 | @available(*, deprecated, message:"Use priority(.medium) instead.") 60 | @discardableResult 61 | public func priorityMedium() -> ConstraintMakerFinalizable { 62 | return self.priority(.medium) 63 | } 64 | 65 | @available(*, deprecated, message:"Use priority(.low) instead.") 66 | @discardableResult 67 | public func priorityLow() -> ConstraintMakerFinalizable { 68 | return self.priority(.low) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintMakerRelatable+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | extension ConstraintMakerRelatable { 32 | 33 | @discardableResult 34 | public func equalToSuperview(_ closure: (ConstraintView) -> T, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable { 35 | guard let other = self.description.item.superview else { 36 | fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.") 37 | } 38 | return self.relatedTo(closure(other), relation: .equal, file: file, line: line) 39 | } 40 | 41 | @discardableResult 42 | public func lessThanOrEqualToSuperview(_ closure: (ConstraintView) -> T, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable { 43 | guard let other = self.description.item.superview else { 44 | fatalError("Expected superview but found nil when attempting make constraint `lessThanOrEqualToSuperview`.") 45 | } 46 | return self.relatedTo(closure(other), relation: .lessThanOrEqual, file: file, line: line) 47 | } 48 | 49 | @discardableResult 50 | public func greaterThanOrEqualTo(_ closure: (ConstraintView) -> T, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable { 51 | guard let other = self.description.item.superview else { 52 | fatalError("Expected superview but found nil when attempting make constraint `greaterThanOrEqualToSuperview`.") 53 | } 54 | return self.relatedTo(closure(other), relation: .greaterThanOrEqual, file: file, line: line) 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintMakerRelatable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerRelatable { 32 | 33 | internal let description: ConstraintDescription 34 | 35 | internal init(_ description: ConstraintDescription) { 36 | self.description = description 37 | } 38 | 39 | internal func relatedTo(_ other: ConstraintRelatableTarget, relation: ConstraintRelation, file: String, line: UInt) -> ConstraintMakerEditable { 40 | let related: ConstraintItem 41 | let constant: ConstraintConstantTarget 42 | 43 | if let other = other as? ConstraintItem { 44 | guard other.attributes == ConstraintAttributes.none || 45 | other.attributes.layoutAttributes.count <= 1 || 46 | other.attributes.layoutAttributes == self.description.attributes.layoutAttributes || 47 | other.attributes == .edges && self.description.attributes == .margins || 48 | other.attributes == .margins && self.description.attributes == .edges || 49 | other.attributes == .directionalEdges && self.description.attributes == .directionalMargins || 50 | other.attributes == .directionalMargins && self.description.attributes == .directionalEdges else { 51 | fatalError("Cannot constraint to multiple non identical attributes. (\(file), \(line))"); 52 | } 53 | 54 | related = other 55 | constant = 0.0 56 | } else if let other = other as? ConstraintView { 57 | related = ConstraintItem(target: other, attributes: ConstraintAttributes.none) 58 | constant = 0.0 59 | } else if let other = other as? ConstraintConstantTarget { 60 | related = ConstraintItem(target: nil, attributes: ConstraintAttributes.none) 61 | constant = other 62 | } else if #available(iOS 9.0, OSX 10.11, *), let other = other as? ConstraintLayoutGuide { 63 | related = ConstraintItem(target: other, attributes: ConstraintAttributes.none) 64 | constant = 0.0 65 | } else { 66 | fatalError("Invalid constraint. (\(file), \(line))") 67 | } 68 | 69 | let editable = ConstraintMakerEditable(self.description) 70 | editable.description.sourceLocation = (file, line) 71 | editable.description.relation = relation 72 | editable.description.related = related 73 | editable.description.constant = constant 74 | return editable 75 | } 76 | 77 | @discardableResult 78 | public func equalTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable { 79 | return self.relatedTo(other, relation: .equal, file: file, line: line) 80 | } 81 | 82 | @discardableResult 83 | public func equalToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable { 84 | guard let other = self.description.item.superview else { 85 | fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.") 86 | } 87 | return self.relatedTo(other, relation: .equal, file: file, line: line) 88 | } 89 | 90 | @discardableResult 91 | public func lessThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable { 92 | return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line) 93 | } 94 | 95 | @discardableResult 96 | public func lessThanOrEqualToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable { 97 | guard let other = self.description.item.superview else { 98 | fatalError("Expected superview but found nil when attempting make constraint `lessThanOrEqualToSuperview`.") 99 | } 100 | return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line) 101 | } 102 | 103 | @discardableResult 104 | public func greaterThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable { 105 | return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line) 106 | } 107 | 108 | @discardableResult 109 | public func greaterThanOrEqualToSuperview(_ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable { 110 | guard let other = self.description.item.superview else { 111 | fatalError("Expected superview but found nil when attempting make constraint `greaterThanOrEqualToSuperview`.") 112 | } 113 | return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintMultiplierTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintMultiplierTarget { 32 | 33 | var constraintMultiplierTargetValue: CGFloat { get } 34 | 35 | } 36 | 37 | extension Int: ConstraintMultiplierTarget { 38 | 39 | public var constraintMultiplierTargetValue: CGFloat { 40 | return CGFloat(self) 41 | } 42 | 43 | } 44 | 45 | extension UInt: ConstraintMultiplierTarget { 46 | 47 | public var constraintMultiplierTargetValue: CGFloat { 48 | return CGFloat(self) 49 | } 50 | 51 | } 52 | 53 | extension Float: ConstraintMultiplierTarget { 54 | 55 | public var constraintMultiplierTargetValue: CGFloat { 56 | return CGFloat(self) 57 | } 58 | 59 | } 60 | 61 | extension Double: ConstraintMultiplierTarget { 62 | 63 | public var constraintMultiplierTargetValue: CGFloat { 64 | return CGFloat(self) 65 | } 66 | 67 | } 68 | 69 | extension CGFloat: ConstraintMultiplierTarget { 70 | 71 | public var constraintMultiplierTargetValue: CGFloat { 72 | return self 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintOffsetTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintOffsetTarget: ConstraintConstantTarget { 32 | } 33 | 34 | extension Int: ConstraintOffsetTarget { 35 | } 36 | 37 | extension UInt: ConstraintOffsetTarget { 38 | } 39 | 40 | extension Float: ConstraintOffsetTarget { 41 | } 42 | 43 | extension Double: ConstraintOffsetTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintOffsetTarget { 47 | } 48 | 49 | extension ConstraintOffsetTarget { 50 | 51 | internal var constraintOffsetTargetValue: CGFloat { 52 | let offset: CGFloat 53 | if let amount = self as? Float { 54 | offset = CGFloat(amount) 55 | } else if let amount = self as? Double { 56 | offset = CGFloat(amount) 57 | } else if let amount = self as? CGFloat { 58 | offset = CGFloat(amount) 59 | } else if let amount = self as? Int { 60 | offset = CGFloat(amount) 61 | } else if let amount = self as? UInt { 62 | offset = CGFloat(amount) 63 | } else { 64 | offset = 0.0 65 | } 66 | return offset 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintPriority.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | public struct ConstraintPriority : ExpressibleByFloatLiteral, Equatable, Strideable { 31 | public typealias FloatLiteralType = Float 32 | 33 | public let value: Float 34 | 35 | public init(floatLiteral value: Float) { 36 | self.value = value 37 | } 38 | 39 | public init(_ value: Float) { 40 | self.value = value 41 | } 42 | 43 | public static var required: ConstraintPriority { 44 | return 1000.0 45 | } 46 | 47 | public static var high: ConstraintPriority { 48 | return 750.0 49 | } 50 | 51 | public static var medium: ConstraintPriority { 52 | #if os(OSX) 53 | return 501.0 54 | #else 55 | return 500.0 56 | #endif 57 | 58 | } 59 | 60 | public static var low: ConstraintPriority { 61 | return 250.0 62 | } 63 | 64 | public static func ==(lhs: ConstraintPriority, rhs: ConstraintPriority) -> Bool { 65 | return lhs.value == rhs.value 66 | } 67 | 68 | // MARK: Strideable 69 | 70 | public func advanced(by n: FloatLiteralType) -> ConstraintPriority { 71 | return ConstraintPriority(floatLiteral: value + n) 72 | } 73 | 74 | public func distance(to other: ConstraintPriority) -> FloatLiteralType { 75 | return other.value - value 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintPriorityTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintPriorityTarget { 32 | 33 | var constraintPriorityTargetValue: Float { get } 34 | 35 | } 36 | 37 | extension Int: ConstraintPriorityTarget { 38 | 39 | public var constraintPriorityTargetValue: Float { 40 | return Float(self) 41 | } 42 | 43 | } 44 | 45 | extension UInt: ConstraintPriorityTarget { 46 | 47 | public var constraintPriorityTargetValue: Float { 48 | return Float(self) 49 | } 50 | 51 | } 52 | 53 | extension Float: ConstraintPriorityTarget { 54 | 55 | public var constraintPriorityTargetValue: Float { 56 | return self 57 | } 58 | 59 | } 60 | 61 | extension Double: ConstraintPriorityTarget { 62 | 63 | public var constraintPriorityTargetValue: Float { 64 | return Float(self) 65 | } 66 | 67 | } 68 | 69 | extension CGFloat: ConstraintPriorityTarget { 70 | 71 | public var constraintPriorityTargetValue: Float { 72 | return Float(self) 73 | } 74 | 75 | } 76 | 77 | #if os(iOS) || os(tvOS) 78 | extension UILayoutPriority: ConstraintPriorityTarget { 79 | 80 | public var constraintPriorityTargetValue: Float { 81 | return self.rawValue 82 | } 83 | 84 | } 85 | #endif 86 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintRelatableTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintRelatableTarget { 32 | } 33 | 34 | extension Int: ConstraintRelatableTarget { 35 | } 36 | 37 | extension UInt: ConstraintRelatableTarget { 38 | } 39 | 40 | extension Float: ConstraintRelatableTarget { 41 | } 42 | 43 | extension Double: ConstraintRelatableTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintRelatableTarget { 47 | } 48 | 49 | extension CGSize: ConstraintRelatableTarget { 50 | } 51 | 52 | extension CGPoint: ConstraintRelatableTarget { 53 | } 54 | 55 | extension ConstraintInsets: ConstraintRelatableTarget { 56 | } 57 | 58 | #if os(iOS) || os(tvOS) 59 | @available(iOS 11.0, tvOS 11.0, *) 60 | extension ConstraintDirectionalInsets: ConstraintRelatableTarget { 61 | } 62 | #endif 63 | 64 | extension ConstraintItem: ConstraintRelatableTarget { 65 | } 66 | 67 | extension ConstraintView: ConstraintRelatableTarget { 68 | } 69 | 70 | @available(iOS 9.0, OSX 10.11, *) 71 | extension ConstraintLayoutGuide: ConstraintRelatableTarget { 72 | } 73 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintRelation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | internal enum ConstraintRelation : Int { 32 | case equal = 1 33 | case lessThanOrEqual 34 | case greaterThanOrEqual 35 | 36 | internal var layoutRelation: LayoutRelation { 37 | get { 38 | switch(self) { 39 | case .equal: 40 | return .equal 41 | case .lessThanOrEqual: 42 | return .lessThanOrEqual 43 | case .greaterThanOrEqual: 44 | return .greaterThanOrEqual 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintView+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public extension ConstraintView { 32 | 33 | @available(*, deprecated, renamed:"snp.left") 34 | var snp_left: ConstraintItem { return self.snp.left } 35 | 36 | @available(*, deprecated, renamed:"snp.top") 37 | var snp_top: ConstraintItem { return self.snp.top } 38 | 39 | @available(*, deprecated, renamed:"snp.right") 40 | var snp_right: ConstraintItem { return self.snp.right } 41 | 42 | @available(*, deprecated, renamed:"snp.bottom") 43 | var snp_bottom: ConstraintItem { return self.snp.bottom } 44 | 45 | @available(*, deprecated, renamed:"snp.leading") 46 | var snp_leading: ConstraintItem { return self.snp.leading } 47 | 48 | @available(*, deprecated, renamed:"snp.trailing") 49 | var snp_trailing: ConstraintItem { return self.snp.trailing } 50 | 51 | @available(*, deprecated, renamed:"snp.width") 52 | var snp_width: ConstraintItem { return self.snp.width } 53 | 54 | @available(*, deprecated, renamed:"snp.height") 55 | var snp_height: ConstraintItem { return self.snp.height } 56 | 57 | @available(*, deprecated, renamed:"snp.centerX") 58 | var snp_centerX: ConstraintItem { return self.snp.centerX } 59 | 60 | @available(*, deprecated, renamed:"snp.centerY") 61 | var snp_centerY: ConstraintItem { return self.snp.centerY } 62 | 63 | @available(*, deprecated, renamed:"snp.baseline") 64 | var snp_baseline: ConstraintItem { return self.snp.baseline } 65 | 66 | @available(*, deprecated, renamed:"snp.lastBaseline") 67 | @available(iOS 8.0, OSX 10.11, *) 68 | var snp_lastBaseline: ConstraintItem { return self.snp.lastBaseline } 69 | 70 | @available(iOS, deprecated, renamed:"snp.firstBaseline") 71 | @available(iOS 8.0, OSX 10.11, *) 72 | var snp_firstBaseline: ConstraintItem { return self.snp.firstBaseline } 73 | 74 | @available(iOS, deprecated, renamed:"snp.leftMargin") 75 | @available(iOS 8.0, *) 76 | var snp_leftMargin: ConstraintItem { return self.snp.leftMargin } 77 | 78 | @available(iOS, deprecated, renamed:"snp.topMargin") 79 | @available(iOS 8.0, *) 80 | var snp_topMargin: ConstraintItem { return self.snp.topMargin } 81 | 82 | @available(iOS, deprecated, renamed:"snp.rightMargin") 83 | @available(iOS 8.0, *) 84 | var snp_rightMargin: ConstraintItem { return self.snp.rightMargin } 85 | 86 | @available(iOS, deprecated, renamed:"snp.bottomMargin") 87 | @available(iOS 8.0, *) 88 | var snp_bottomMargin: ConstraintItem { return self.snp.bottomMargin } 89 | 90 | @available(iOS, deprecated, renamed:"snp.leadingMargin") 91 | @available(iOS 8.0, *) 92 | var snp_leadingMargin: ConstraintItem { return self.snp.leadingMargin } 93 | 94 | @available(iOS, deprecated, renamed:"snp.trailingMargin") 95 | @available(iOS 8.0, *) 96 | var snp_trailingMargin: ConstraintItem { return self.snp.trailingMargin } 97 | 98 | @available(iOS, deprecated, renamed:"snp.centerXWithinMargins") 99 | @available(iOS 8.0, *) 100 | var snp_centerXWithinMargins: ConstraintItem { return self.snp.centerXWithinMargins } 101 | 102 | @available(iOS, deprecated, renamed:"snp.centerYWithinMargins") 103 | @available(iOS 8.0, *) 104 | var snp_centerYWithinMargins: ConstraintItem { return self.snp.centerYWithinMargins } 105 | 106 | @available(*, deprecated, renamed:"snp.edges") 107 | var snp_edges: ConstraintItem { return self.snp.edges } 108 | 109 | @available(*, deprecated, renamed:"snp.size") 110 | var snp_size: ConstraintItem { return self.snp.size } 111 | 112 | @available(*, deprecated, renamed:"snp.center") 113 | var snp_center: ConstraintItem { return self.snp.center } 114 | 115 | @available(iOS, deprecated, renamed:"snp.margins") 116 | @available(iOS 8.0, *) 117 | var snp_margins: ConstraintItem { return self.snp.margins } 118 | 119 | @available(iOS, deprecated, renamed:"snp.centerWithinMargins") 120 | @available(iOS 8.0, *) 121 | var snp_centerWithinMargins: ConstraintItem { return self.snp.centerWithinMargins } 122 | 123 | @available(*, deprecated, renamed:"snp.prepareConstraints(_:)") 124 | func snp_prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { 125 | return self.snp.prepareConstraints(closure) 126 | } 127 | 128 | @available(*, deprecated, renamed:"snp.makeConstraints(_:)") 129 | func snp_makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 130 | self.snp.makeConstraints(closure) 131 | } 132 | 133 | @available(*, deprecated, renamed:"snp.remakeConstraints(_:)") 134 | func snp_remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 135 | self.snp.remakeConstraints(closure) 136 | } 137 | 138 | @available(*, deprecated, renamed:"snp.updateConstraints(_:)") 139 | func snp_updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 140 | self.snp.updateConstraints(closure) 141 | } 142 | 143 | @available(*, deprecated, renamed:"snp.removeConstraints()") 144 | func snp_removeConstraints() { 145 | self.snp.removeConstraints() 146 | } 147 | 148 | var snp: ConstraintViewDSL { 149 | return ConstraintViewDSL(view: self) 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | public typealias ConstraintView = UIView 33 | #else 34 | public typealias ConstraintView = NSView 35 | #endif 36 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/ConstraintViewDSL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public struct ConstraintViewDSL: ConstraintAttributesDSL { 32 | 33 | @discardableResult 34 | public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { 35 | return ConstraintMaker.prepareConstraints(item: self.view, closure: closure) 36 | } 37 | 38 | public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 39 | ConstraintMaker.makeConstraints(item: self.view, closure: closure) 40 | } 41 | 42 | public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 43 | ConstraintMaker.remakeConstraints(item: self.view, closure: closure) 44 | } 45 | 46 | public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 47 | ConstraintMaker.updateConstraints(item: self.view, closure: closure) 48 | } 49 | 50 | public func removeConstraints() { 51 | ConstraintMaker.removeConstraints(item: self.view) 52 | } 53 | 54 | public var contentHuggingHorizontalPriority: Float { 55 | get { 56 | return self.view.contentHuggingPriority(for: .horizontal).rawValue 57 | } 58 | nonmutating set { 59 | self.view.setContentHuggingPriority(LayoutPriority(rawValue: newValue), for: .horizontal) 60 | } 61 | } 62 | 63 | public var contentHuggingVerticalPriority: Float { 64 | get { 65 | return self.view.contentHuggingPriority(for: .vertical).rawValue 66 | } 67 | nonmutating set { 68 | self.view.setContentHuggingPriority(LayoutPriority(rawValue: newValue), for: .vertical) 69 | } 70 | } 71 | 72 | public var contentCompressionResistanceHorizontalPriority: Float { 73 | get { 74 | return self.view.contentCompressionResistancePriority(for: .horizontal).rawValue 75 | } 76 | nonmutating set { 77 | self.view.setContentCompressionResistancePriority(LayoutPriority(rawValue: newValue), for: .horizontal) 78 | } 79 | } 80 | 81 | public var contentCompressionResistanceVerticalPriority: Float { 82 | get { 83 | return self.view.contentCompressionResistancePriority(for: .vertical).rawValue 84 | } 85 | nonmutating set { 86 | self.view.setContentCompressionResistancePriority(LayoutPriority(rawValue: newValue), for: .vertical) 87 | } 88 | } 89 | 90 | public var target: AnyObject? { 91 | return self.view 92 | } 93 | 94 | internal let view: ConstraintView 95 | 96 | internal init(view: ConstraintView) { 97 | self.view = view 98 | 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/Debugging.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | public extension LayoutConstraint { 31 | 32 | override var description: String { 33 | var description = "<" 34 | 35 | description += descriptionForObject(self) 36 | 37 | if let firstItem = conditionalOptional(from: self.firstItem) { 38 | description += " \(descriptionForObject(firstItem))" 39 | } 40 | 41 | if self.firstAttribute != .notAnAttribute { 42 | description += ".\(descriptionForAttribute(self.firstAttribute))" 43 | } 44 | 45 | description += " \(descriptionForRelation(self.relation))" 46 | 47 | if let secondItem = self.secondItem { 48 | description += " \(descriptionForObject(secondItem))" 49 | } 50 | 51 | if self.secondAttribute != .notAnAttribute { 52 | description += ".\(descriptionForAttribute(self.secondAttribute))" 53 | } 54 | 55 | if self.multiplier != 1.0 { 56 | description += " * \(self.multiplier)" 57 | } 58 | 59 | if self.secondAttribute == .notAnAttribute { 60 | description += " \(self.constant)" 61 | } else { 62 | if self.constant > 0.0 { 63 | description += " + \(self.constant)" 64 | } else if self.constant < 0.0 { 65 | description += " - \(abs(self.constant))" 66 | } 67 | } 68 | 69 | if self.priority.rawValue != 1000.0 { 70 | description += " ^\(self.priority)" 71 | } 72 | 73 | description += ">" 74 | 75 | return description 76 | } 77 | 78 | } 79 | 80 | private func descriptionForRelation(_ relation: LayoutRelation) -> String { 81 | switch relation { 82 | case .equal: return "==" 83 | case .greaterThanOrEqual: return ">=" 84 | case .lessThanOrEqual: return "<=" 85 | #if swift(>=5.0) 86 | @unknown default: return "unknown" 87 | #endif 88 | } 89 | } 90 | 91 | private func descriptionForAttribute(_ attribute: LayoutAttribute) -> String { 92 | #if os(iOS) || os(tvOS) 93 | switch attribute { 94 | case .notAnAttribute: return "notAnAttribute" 95 | case .top: return "top" 96 | case .left: return "left" 97 | case .bottom: return "bottom" 98 | case .right: return "right" 99 | case .leading: return "leading" 100 | case .trailing: return "trailing" 101 | case .width: return "width" 102 | case .height: return "height" 103 | case .centerX: return "centerX" 104 | case .centerY: return "centerY" 105 | case .lastBaseline: return "lastBaseline" 106 | case .firstBaseline: return "firstBaseline" 107 | case .topMargin: return "topMargin" 108 | case .leftMargin: return "leftMargin" 109 | case .bottomMargin: return "bottomMargin" 110 | case .rightMargin: return "rightMargin" 111 | case .leadingMargin: return "leadingMargin" 112 | case .trailingMargin: return "trailingMargin" 113 | case .centerXWithinMargins: return "centerXWithinMargins" 114 | case .centerYWithinMargins: return "centerYWithinMargins" 115 | #if swift(>=5.0) 116 | @unknown default: return "unknown" 117 | #endif 118 | } 119 | #else 120 | switch attribute { 121 | case .notAnAttribute: return "notAnAttribute" 122 | case .top: return "top" 123 | case .left: return "left" 124 | case .bottom: return "bottom" 125 | case .right: return "right" 126 | case .leading: return "leading" 127 | case .trailing: return "trailing" 128 | case .width: return "width" 129 | case .height: return "height" 130 | case .centerX: return "centerX" 131 | case .centerY: return "centerY" 132 | case .lastBaseline: return "lastBaseline" 133 | case .firstBaseline: return "firstBaseline" 134 | #if swift(>=5.0) 135 | @unknown default: return "unknown" 136 | #endif 137 | } 138 | #endif 139 | } 140 | 141 | private func conditionalOptional(from object: Optional) -> Optional { 142 | return object 143 | } 144 | 145 | private func conditionalOptional(from object: T) -> Optional { 146 | return Optional.some(object) 147 | } 148 | 149 | private func descriptionForObject(_ object: AnyObject) -> String { 150 | let pointerDescription = String(format: "%p", UInt(bitPattern: ObjectIdentifier(object))) 151 | var desc = "" 152 | 153 | desc += type(of: object).description() 154 | 155 | if let object = object as? ConstraintView { 156 | desc += ":\(object.snp.label() ?? pointerDescription)" 157 | } else if let object = object as? LayoutConstraint { 158 | desc += ":\(object.label ?? pointerDescription)" 159 | } else { 160 | desc += ":\(pointerDescription)" 161 | } 162 | 163 | if let object = object as? LayoutConstraint, let file = object.constraint?.sourceLocation.0, let line = object.constraint?.sourceLocation.1 { 164 | desc += "@\((file as NSString).lastPathComponent)#\(line)" 165 | } 166 | 167 | desc += "" 168 | return desc 169 | } 170 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/LayoutConstraint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class LayoutConstraint : NSLayoutConstraint { 32 | 33 | public var label: String? { 34 | get { 35 | return self.identifier 36 | } 37 | set { 38 | self.identifier = newValue 39 | } 40 | } 41 | 42 | internal weak var constraint: Constraint? = nil 43 | 44 | } 45 | 46 | internal func ==(lhs: LayoutConstraint, rhs: LayoutConstraint) -> Bool { 47 | // If firstItem or secondItem on either constraint has a dangling pointer 48 | // this comparison can cause a crash. The solution for this is to ensure 49 | // your layout code hold strong references to things like Views, LayoutGuides 50 | // and LayoutAnchors as SnapKit will not keep strong references to any of these. 51 | guard lhs.firstAttribute == rhs.firstAttribute && 52 | lhs.secondAttribute == rhs.secondAttribute && 53 | lhs.relation == rhs.relation && 54 | lhs.priority == rhs.priority && 55 | lhs.multiplier == rhs.multiplier && 56 | lhs.secondItem === rhs.secondItem && 57 | lhs.firstItem === rhs.firstItem else { 58 | return false 59 | } 60 | return true 61 | } 62 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/LayoutConstraintItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol LayoutConstraintItem: AnyObject { 32 | } 33 | 34 | @available(iOS 9.0, OSX 10.11, *) 35 | extension ConstraintLayoutGuide : LayoutConstraintItem { 36 | } 37 | 38 | extension ConstraintView : LayoutConstraintItem { 39 | } 40 | 41 | 42 | extension LayoutConstraintItem { 43 | 44 | internal func prepare() { 45 | if let view = self as? ConstraintView { 46 | view.translatesAutoresizingMaskIntoConstraints = false 47 | } 48 | } 49 | 50 | internal var superview: ConstraintView? { 51 | if let view = self as? ConstraintView { 52 | return view.superview 53 | } 54 | 55 | if #available(iOS 9.0, OSX 10.11, *), let guide = self as? ConstraintLayoutGuide { 56 | return guide.owningView 57 | } 58 | 59 | return nil 60 | } 61 | internal var constraints: [Constraint] { 62 | return self.constraintsSet.allObjects as! [Constraint] 63 | } 64 | 65 | internal func add(constraints: [Constraint]) { 66 | let constraintsSet = self.constraintsSet 67 | for constraint in constraints { 68 | constraintsSet.add(constraint) 69 | } 70 | } 71 | 72 | internal func remove(constraints: [Constraint]) { 73 | let constraintsSet = self.constraintsSet 74 | for constraint in constraints { 75 | constraintsSet.remove(constraint) 76 | } 77 | } 78 | 79 | private var constraintsSet: NSMutableSet { 80 | let constraintsSet: NSMutableSet 81 | 82 | if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet { 83 | constraintsSet = existing 84 | } else { 85 | constraintsSet = NSMutableSet() 86 | objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 87 | } 88 | return constraintsSet 89 | 90 | } 91 | 92 | } 93 | private var constraintsKey: UInt8 = 0 94 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/Typealiases.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | import Foundation 25 | 26 | #if os(iOS) || os(tvOS) 27 | import UIKit 28 | #if swift(>=4.2) 29 | typealias LayoutRelation = NSLayoutConstraint.Relation 30 | typealias LayoutAttribute = NSLayoutConstraint.Attribute 31 | #else 32 | typealias LayoutRelation = NSLayoutRelation 33 | typealias LayoutAttribute = NSLayoutAttribute 34 | #endif 35 | typealias LayoutPriority = UILayoutPriority 36 | #else 37 | import AppKit 38 | typealias LayoutRelation = NSLayoutConstraint.Relation 39 | typealias LayoutAttribute = NSLayoutConstraint.Attribute 40 | typealias LayoutPriority = NSLayoutConstraint.Priority 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /Example/Pods/SnapKit/Sources/UILayoutSupport+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #endif 27 | 28 | 29 | @available(iOS 8.0, *) 30 | public extension ConstraintLayoutSupport { 31 | 32 | var snp: ConstraintLayoutSupportDSL { 33 | return ConstraintLayoutSupportDSL(support: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/BTBubble/BTBubble-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.0.5 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/BTBubble/BTBubble-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_BTBubble : NSObject 3 | @end 4 | @implementation PodsDummy_BTBubble 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/BTBubble/BTBubble-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/BTBubble/BTBubble-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double BTBubbleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char BTBubbleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/BTBubble/BTBubble.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BTBubble 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/BTBubble/BTBubble.modulemap: -------------------------------------------------------------------------------- 1 | framework module BTBubble { 2 | umbrella header "BTBubble-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/BTBubble/BTBubble.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BTBubble 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Example/Pods-BTBubble_Example-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Example/Pods-BTBubble_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## BTBubble 5 | 6 | Copyright (c) 2023 Mccc 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | 27 | ## SnapKit 28 | 29 | Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy 32 | of this software and associated documentation files (the "Software"), to deal 33 | in the Software without restriction, including without limitation the rights 34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 | copies of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in 39 | all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 | THE SOFTWARE. 48 | 49 | Generated by CocoaPods - https://cocoapods.org 50 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Example/Pods-BTBubble_Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2023 Mccc <Mccc> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | BTBubble 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 47 | 48 | Permission is hereby granted, free of charge, to any person obtaining a copy 49 | of this software and associated documentation files (the "Software"), to deal 50 | in the Software without restriction, including without limitation the rights 51 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 52 | copies of the Software, and to permit persons to whom the Software is 53 | furnished to do so, subject to the following conditions: 54 | 55 | The above copyright notice and this permission notice shall be included in 56 | all copies or substantial portions of the Software. 57 | 58 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 62 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 63 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 64 | THE SOFTWARE. 65 | 66 | License 67 | MIT 68 | Title 69 | SnapKit 70 | Type 71 | PSGroupSpecifier 72 | 73 | 74 | FooterText 75 | Generated by CocoaPods - https://cocoapods.org 76 | Title 77 | 78 | Type 79 | PSGroupSpecifier 80 | 81 | 82 | StringsTable 83 | Acknowledgements 84 | Title 85 | Acknowledgements 86 | 87 | 88 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Example/Pods-BTBubble_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_BTBubble_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_BTBubble_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Example/Pods-BTBubble_Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_BTBubble_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_BTBubble_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Example/Pods-BTBubble_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BTBubble" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BTBubble/BTBubble.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "BTBubble" -framework "SnapKit" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Example/Pods-BTBubble_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_BTBubble_Example { 2 | umbrella header "Pods-BTBubble_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Example/Pods-BTBubble_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BTBubble" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BTBubble/BTBubble.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "BTBubble" -framework "SnapKit" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Tests/Pods-BTBubble_Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Tests/Pods-BTBubble_Tests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Tests/Pods-BTBubble_Tests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Tests/Pods-BTBubble_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_BTBubble_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_BTBubble_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Tests/Pods-BTBubble_Tests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_BTBubble_TestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_BTBubble_TestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Tests/Pods-BTBubble_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BTBubble" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BTBubble/BTBubble.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "BTBubble" -framework "SnapKit" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Tests/Pods-BTBubble_Tests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_BTBubble_Tests { 2 | umbrella header "Pods-BTBubble_Tests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-BTBubble_Tests/Pods-BTBubble_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BTBubble" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BTBubble/BTBubble.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "BTBubble" -framework "SnapKit" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SnapKit/SnapKit-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 5.6.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SnapKit/SnapKit-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SnapKit : NSObject 3 | @end 4 | @implementation PodsDummy_SnapKit 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SnapKit/SnapKit-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SnapKit/SnapKit-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double SnapKitVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char SnapKitVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SnapKit/SnapKit.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SnapKit 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SnapKit 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SnapKit/SnapKit.modulemap: -------------------------------------------------------------------------------- 1 | framework module SnapKit { 2 | umbrella header "SnapKit-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/SnapKit/SnapKit.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SnapKit 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SnapKit 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Example/Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/Tests/Tests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | class Tests: XCTestCase { 4 | 5 | override func setUp() { 6 | super.setUp() 7 | // Put setup code here. This method is called before the invocation of each test method in the class. 8 | } 9 | 10 | override func tearDown() { 11 | // Put teardown code here. This method is called after the invocation of each test method in the class. 12 | super.tearDown() 13 | } 14 | 15 | func testExample() { 16 | // This is an example of a functional test case. 17 | XCTAssert(true, "Pass") 18 | } 19 | 20 | func testPerformanceExample() { 21 | // This is an example of a performance test case. 22 | self.measure() { 23 | // Put the code you want to measure the time of here. 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Mccc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # BTBubble(气泡) 4 | 5 | 6 | 7 | 这是Swift语言实现的一款气泡能力。 8 | 9 | ![BTBubbleGif](https://github.com/intsig171/BTBubble/blob/main/Sample/bubbleSmaple.gif) 10 | 11 | 12 | 13 | 您可以下载本项目,查看 **Example** 工程,获取更多的使用示例。 14 | 15 | 16 | 17 | ### 如何使用 18 | 19 | ``` 20 | pod 'BTBubble' 21 | ``` 22 | 23 | ``` 24 | import BTBubble 25 | 26 | var bubble = BTBubble() 27 | bubble.show(text: "明亮的月光洒在窗户纸上,好像地上泛起了一层白霜。", from: button) 28 | ``` 29 | 30 | 31 | 32 | ### 简介 33 | 34 | ![BTBubble](https://github.com/intsig171/BTBubble/assets/87351449/8b8b197d-c412-443a-98c7-42d655a2f6c3) 35 | 36 | 37 | 38 | ### 联系我们 39 | ![QQ](https://github.com/intsig171/BTBubble/assets/87351449/22c7d153-a618-42fc-af61-4ed1983be91d) 40 | 41 | 42 | ## License 43 | 44 | BTBubble is available under the MIT license. See the LICENSE file for more info. 45 | -------------------------------------------------------------------------------- /Sample/BTBubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Sample/BTBubble.png -------------------------------------------------------------------------------- /Sample/bubbleSmaple.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Sample/bubbleSmaple.gif -------------------------------------------------------------------------------- /Sample/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intsig171/BTBubble/c8149d544e3100ce1f5b3e053fa6bc95d37454f7/Sample/demo.png -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------