├── .gitignore ├── README.md ├── Tests ├── LinuxMain.swift └── BxRefreshableScrollViewTests │ ├── XCTestManifests.swift │ └── BxRefreshableScrollViewTests.swift ├── BxRefreshableScrollView.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── project.pbxproj ├── Sources └── BxRefreshableScrollView │ ├── ActivityIndicator.swift │ ├── BxRefreshableScrollView.h │ ├── RefreshableKey.swift │ └── BxRefreshableScrollView.swift └── Package.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BxRefreshableScrollView 2 | 3 | A description of this package. 4 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import BxRefreshableScrollViewTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += BxRefreshableScrollViewTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /BxRefreshableScrollView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /Tests/BxRefreshableScrollViewTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(BxRefreshableScrollViewTests.allTests), 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /Tests/BxRefreshableScrollViewTests/BxRefreshableScrollViewTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import BxRefreshableScrollView 3 | 4 | final class BxRefreshableScrollViewTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | XCTAssertEqual(BxRefreshableScrollView().text, "Hello, World!") 10 | } 11 | 12 | static var allTests = [ 13 | ("testExample", testExample), 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Sources/BxRefreshableScrollView/ActivityIndicator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityIndicator.swift 3 | // BxRefreshableScrollView 4 | // 5 | // Created by Mars on 2020/1/17. 6 | // Copyright © 2020 Mars. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftUI 11 | 12 | struct ActivityIndicator: UIViewRepresentable { 13 | func makeUIView(context: UIViewRepresentableContext) -> UIActivityIndicatorView { 14 | return UIActivityIndicatorView() 15 | } 16 | 17 | func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext) { 18 | uiView.startAnimating() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/BxRefreshableScrollView/BxRefreshableScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // BxRefreshableScrollView.h 3 | // BxRefreshableScrollView 4 | // 5 | // Created by Mars on 2020/1/17. 6 | // Copyright © 2020 Mars. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for BxRefreshableScrollView. 12 | FOUNDATION_EXPORT double BxRefreshableScrollViewVersionNumber; 13 | 14 | //! Project version string for BxRefreshableScrollView. 15 | FOUNDATION_EXPORT const unsigned char BxRefreshableScrollViewVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "BxRefreshableScrollView", 8 | platforms: [ 9 | .iOS(.v13) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries a package produces, and make them visible to other packages. 13 | .library( 14 | name: "BxRefreshableScrollView", 15 | targets: ["BxRefreshableScrollView"]), 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 24 | .target( 25 | name: "BxRefreshableScrollView", 26 | dependencies: []), 27 | .testTarget( 28 | name: "BxRefreshableScrollViewTests", 29 | dependencies: ["BxRefreshableScrollView"]), 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /Sources/BxRefreshableScrollView/RefreshableKey.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RefreshableKey.swift 3 | // BxRefreshableScrollView 4 | // 5 | // Created by Mars on 2020/1/17. 6 | // Copyright © 2020 Mars. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import Foundation 11 | 12 | struct RefreshableKey { 13 | enum ViewType: Int { 14 | case movingView 15 | case fixedView 16 | case contentView 17 | } 18 | 19 | struct PrefData: Equatable { 20 | let vType: ViewType 21 | var bounds: CGRect 22 | } 23 | 24 | struct PrefKey: PreferenceKey { 25 | typealias Value = [PrefData] 26 | static var defaultValue: [PrefData] = [] 27 | 28 | static func reduce( 29 | value: inout [RefreshableKey.PrefData], 30 | nextValue: () -> [RefreshableKey.PrefData]) { 31 | value.append(contentsOf: nextValue()) 32 | } 33 | } 34 | 35 | struct ContentPrefData { 36 | let vType: ViewType 37 | let bounds: Anchor 38 | } 39 | 40 | struct ContentPrefKey: PreferenceKey { 41 | typealias Value = [ContentPrefData] 42 | static var defaultValue: [ContentPrefData] = [] 43 | 44 | static func reduce( 45 | value: inout [RefreshableKey.ContentPrefData], 46 | nextValue: () -> [RefreshableKey.ContentPrefData]) { 47 | value.append(contentsOf: nextValue()) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/BxRefreshableScrollView/BxRefreshableScrollView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BxRefreshableScrollView.swift 3 | // BxRefreshableScrollView 4 | // 5 | // Created by Mars on 2020/1/17. 6 | // Copyright © 2020 Mars. All rights reserved. 7 | // 8 | import Combine 9 | import SwiftUI 10 | 11 | //private var contentBounds: CGRect = .zero 12 | 13 | public struct RefreshableScrollView: View { 14 | @State private var previousScrollOffset: CGFloat = 0 15 | @State private var scrollOffset: CGFloat = 0 16 | 17 | // Keep the loading indication area above the scroll view. 18 | @State private var frozen: Bool = false 19 | @State private var rotation: Angle = .degrees(0) 20 | 21 | // Trigger the action after scrolling over the threshold. 22 | var threshold: CGFloat = 80 23 | 24 | // Pull down to refresh 25 | @Binding var refreshing: Bool 26 | 27 | // Pull up to refresh 28 | private let bottomRefreshable: Bool 29 | @Binding var showNoMoreData: Bool 30 | @Binding var showBottomLoading: Bool 31 | var noDataPrompt: String 32 | 33 | @State var contentBounds: CGRect = .zero 34 | 35 | let content: Content 36 | 37 | public init(height: CGFloat = 80, 38 | refreshing: Binding, 39 | bottomRefreshable: Bool = false, 40 | showNoMoreData: Binding = .constant(false), 41 | showBottomLoading: Binding = .constant(false), 42 | noDataPrompt: String = "", 43 | @ViewBuilder content: () -> Content) { 44 | self.threshold = height 45 | self._refreshing = refreshing 46 | self.bottomRefreshable = bottomRefreshable 47 | self._showNoMoreData = showNoMoreData 48 | self._showBottomLoading = showBottomLoading 49 | self.noDataPrompt = noDataPrompt 50 | self.content = content() 51 | } 52 | 53 | public var body: some View { 54 | ScrollView { 55 | ZStack(alignment: .top) { 56 | MovingView() 57 | VStack { 58 | /// GeometryReader { 59 | /// self.content.preference( 60 | /// key: RefreshableKey.PrefKey.self, 61 | /// value: [ 62 | /// RefreshableKey.PrefData(vType: .contentView, 63 | /// bounds: $0.frame(in: CoordinateSpace.local)) 64 | /// ]) } 65 | self.content 66 | .anchorPreference( 67 | key: RefreshableKey.ContentPrefKey.self, 68 | value: .bounds, 69 | transform: { [RefreshableKey.ContentPrefData(vType: .contentView, bounds: $0)] }) 70 | 71 | if bottomRefreshable { 72 | ZStack { 73 | ActivityIndicator().opacity(showBottomLoading ? 1 : 0) 74 | Text(noDataPrompt).opacity(showNoMoreData ? 1 : 0) 75 | } 76 | .foregroundColor(Color.secondary) 77 | .padding([.top, .bottom], 5) 78 | } 79 | } 80 | .alignmentGuide(.top, computeValue: { d in (self.refreshing && self.frozen ? -self.threshold : 0.0) }) 81 | SymbolView(height: self.threshold, loading: self.refreshing, frozen: self.frozen, rotation: self.rotation) 82 | } 83 | } 84 | // .backgroundPreferenceValue(RefreshableKey.PrefKey.self) { 85 | // (preferences: [RefreshableKey.PrefData]) in 86 | // return GeometryReader { (proxy: GeometryProxy) -> FixedView in 87 | // let p = preferences.first(where: { $0.vType == .contentView })! 88 | // self.contentBounds = p.bounds 89 | // 90 | // return FixedView() 91 | // } 92 | // } 93 | .backgroundPreferenceValue(RefreshableKey.ContentPrefKey.self) { 94 | (preferences: [RefreshableKey.ContentPrefData]) in 95 | return GeometryReader { (proxy: GeometryProxy) -> FixedView in 96 | if self.bottomRefreshable { 97 | let p = preferences.first(where: { $0.vType == .contentView }) 98 | 99 | DispatchQueue.main.async { 100 | if let pref = p { 101 | self.contentBounds = proxy[pref.bounds] 102 | } 103 | } 104 | } 105 | 106 | return FixedView() 107 | } 108 | } 109 | .onPreferenceChange(RefreshableKey.PrefKey.self ) { preferences in 110 | self.refreshLogic(values: preferences) 111 | } 112 | } 113 | 114 | func refreshLogic(values: [RefreshableKey.PrefData]) { 115 | let movingBounds = values.first { $0.vType == .movingView }?.bounds ?? .zero 116 | let fixedBounds = values.first { $0.vType == .fixedView }?.bounds ?? .zero 117 | 118 | scrollOffset = movingBounds.minY - fixedBounds.minY 119 | rotation = symbolRotation(scrollOffset) 120 | 121 | // Crossing the threshold on the way down, we start the refreshing process 122 | if !refreshing && (scrollOffset > threshold && previousScrollOffset <= threshold) { 123 | refreshing = true 124 | } 125 | 126 | if refreshing { 127 | /// Keep the symbol view above the scrollview during updating process. 128 | /// `self.scrollOffset <= self.threshold` prevents the UI from scrolling back 129 | /// to the top of screen. 130 | if previousScrollOffset > threshold && scrollOffset <= threshold { 131 | frozen = true 132 | } 133 | } 134 | else { 135 | frozen = false 136 | } 137 | 138 | #if DEBUG 139 | print("Scroll offset: \(scrollOffset)") 140 | print("Fix height: \(fixedBounds.size.height)") 141 | print("Content bounds: \(contentBounds)") 142 | print("-------------------------") 143 | #endif 144 | if bottomRefreshable, 145 | contentBounds.height > 0 && 146 | scrollOffset < -(contentBounds.height - fixedBounds.size.height) && 147 | showBottomLoading == false && 148 | showNoMoreData == false { 149 | print("display bottom indicator") 150 | showBottomLoading = true 151 | } 152 | 153 | previousScrollOffset = scrollOffset 154 | } 155 | 156 | func symbolRotation(_ scrollOffset: CGFloat) -> Angle { 157 | if scrollOffset < threshold * 0.6 { 158 | return .degrees(0) 159 | } 160 | else { 161 | let h = Double(threshold) 162 | let d = Double(scrollOffset) 163 | let v = max(min(d - (h * 0.6), h * 0.4), 0) 164 | 165 | return .degrees(180 * v / (h * 0.4)) 166 | } 167 | } 168 | 169 | struct SymbolView: View { 170 | var height: CGFloat 171 | var loading: Bool 172 | var frozen: Bool 173 | var rotation: Angle 174 | 175 | var body: some View { 176 | Group { 177 | if loading { 178 | VStack { 179 | Spacer() 180 | ActivityIndicator() 181 | Spacer() 182 | } 183 | .frame(height: height).fixedSize() 184 | .offset(y: -height + (loading && frozen ? height : 0)) 185 | } 186 | else { 187 | Image(systemName: "arrow.down") 188 | .resizable() 189 | .aspectRatio(contentMode: .fit) 190 | .frame(width: height * 0.25, height: height*0.25).fixedSize() 191 | .padding(height * 0.375) 192 | .rotationEffect(rotation) 193 | .offset(y: -height + (loading && frozen ? height : 0)) 194 | } 195 | } 196 | } 197 | } 198 | 199 | struct MovingView: View { 200 | var body: some View { 201 | GeometryReader { 202 | Color.clear 203 | /// Compare to: 204 | /// ``` 205 | /// .anchorPreference(key: TagPreferenceKey.self, 206 | /// value: .bounds, 207 | /// transform: { [TagPreferenceData(bounds: $0)] }) 208 | /// ``` 209 | .preference(key: RefreshableKey.PrefKey.self, 210 | value: [RefreshableKey.PrefData(vType: .movingView, bounds: $0.frame(in: .global))]) 211 | } 212 | .frame(height: 0) 213 | } 214 | } 215 | 216 | struct FixedView: View { 217 | var body: some View { 218 | GeometryReader { 219 | Color.clear 220 | .preference(key: RefreshableKey.PrefKey.self, 221 | value: [RefreshableKey.PrefData(vType: .fixedView, bounds: $0.frame(in: .global))]) 222 | } 223 | } 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /BxRefreshableScrollView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = "1"; 4 | objectVersion = "46"; 5 | objects = { 6 | "BxRefreshableScrollView::BxRefreshableScrollView" = { 7 | isa = "PBXNativeTarget"; 8 | buildConfigurationList = "OBJ_23"; 9 | buildPhases = ( 10 | "OBJ_26", 11 | "OBJ_30" 12 | ); 13 | dependencies = ( 14 | ); 15 | name = "BxRefreshableScrollView"; 16 | productName = "BxRefreshableScrollView"; 17 | productReference = "BxRefreshableScrollView::BxRefreshableScrollView::Product"; 18 | productType = "com.apple.product-type.framework"; 19 | }; 20 | "BxRefreshableScrollView::BxRefreshableScrollView::Product" = { 21 | isa = "PBXFileReference"; 22 | path = "BxRefreshableScrollView.framework"; 23 | sourceTree = "BUILT_PRODUCTS_DIR"; 24 | }; 25 | "BxRefreshableScrollView::BxRefreshableScrollViewPackageTests::ProductTarget" = { 26 | isa = "PBXAggregateTarget"; 27 | buildConfigurationList = "OBJ_38"; 28 | buildPhases = ( 29 | ); 30 | dependencies = ( 31 | "OBJ_41" 32 | ); 33 | name = "BxRefreshableScrollViewPackageTests"; 34 | productName = "BxRefreshableScrollViewPackageTests"; 35 | }; 36 | "BxRefreshableScrollView::BxRefreshableScrollViewTests" = { 37 | isa = "PBXNativeTarget"; 38 | buildConfigurationList = "OBJ_43"; 39 | buildPhases = ( 40 | "OBJ_46", 41 | "OBJ_49" 42 | ); 43 | dependencies = ( 44 | "OBJ_51" 45 | ); 46 | name = "BxRefreshableScrollViewTests"; 47 | productName = "BxRefreshableScrollViewTests"; 48 | productReference = "BxRefreshableScrollView::BxRefreshableScrollViewTests::Product"; 49 | productType = "com.apple.product-type.bundle.unit-test"; 50 | }; 51 | "BxRefreshableScrollView::BxRefreshableScrollViewTests::Product" = { 52 | isa = "PBXFileReference"; 53 | path = "BxRefreshableScrollViewTests.xctest"; 54 | sourceTree = "BUILT_PRODUCTS_DIR"; 55 | }; 56 | "BxRefreshableScrollView::SwiftPMPackageDescription" = { 57 | isa = "PBXNativeTarget"; 58 | buildConfigurationList = "OBJ_32"; 59 | buildPhases = ( 60 | "OBJ_35" 61 | ); 62 | dependencies = ( 63 | ); 64 | name = "BxRefreshableScrollViewPackageDescription"; 65 | productName = "BxRefreshableScrollViewPackageDescription"; 66 | productType = "com.apple.product-type.framework"; 67 | }; 68 | "OBJ_1" = { 69 | isa = "PBXProject"; 70 | attributes = { 71 | LastSwiftMigration = "9999"; 72 | LastUpgradeCheck = "9999"; 73 | }; 74 | buildConfigurationList = "OBJ_2"; 75 | compatibilityVersion = "Xcode 3.2"; 76 | developmentRegion = "en"; 77 | hasScannedForEncodings = "0"; 78 | knownRegions = ( 79 | "en" 80 | ); 81 | mainGroup = "OBJ_5"; 82 | productRefGroup = "OBJ_18"; 83 | projectDirPath = "."; 84 | targets = ( 85 | "BxRefreshableScrollView::BxRefreshableScrollView", 86 | "BxRefreshableScrollView::SwiftPMPackageDescription", 87 | "BxRefreshableScrollView::BxRefreshableScrollViewPackageTests::ProductTarget", 88 | "BxRefreshableScrollView::BxRefreshableScrollViewTests" 89 | ); 90 | }; 91 | "OBJ_10" = { 92 | isa = "PBXFileReference"; 93 | path = "Info.plist"; 94 | sourceTree = ""; 95 | }; 96 | "OBJ_11" = { 97 | isa = "PBXFileReference"; 98 | path = "ActivityIndicator.swift"; 99 | sourceTree = ""; 100 | }; 101 | "OBJ_12" = { 102 | isa = "PBXFileReference"; 103 | path = "BxRefreshableScrollView.swift"; 104 | sourceTree = ""; 105 | }; 106 | "OBJ_13" = { 107 | isa = "PBXFileReference"; 108 | path = "RefreshableKey.swift"; 109 | sourceTree = ""; 110 | }; 111 | "OBJ_14" = { 112 | isa = "PBXGroup"; 113 | children = ( 114 | "OBJ_15" 115 | ); 116 | name = "Tests"; 117 | path = ""; 118 | sourceTree = "SOURCE_ROOT"; 119 | }; 120 | "OBJ_15" = { 121 | isa = "PBXGroup"; 122 | children = ( 123 | "OBJ_16", 124 | "OBJ_17" 125 | ); 126 | name = "BxRefreshableScrollViewTests"; 127 | path = "Tests/BxRefreshableScrollViewTests"; 128 | sourceTree = "SOURCE_ROOT"; 129 | }; 130 | "OBJ_16" = { 131 | isa = "PBXFileReference"; 132 | path = "BxRefreshableScrollViewTests.swift"; 133 | sourceTree = ""; 134 | }; 135 | "OBJ_17" = { 136 | isa = "PBXFileReference"; 137 | path = "XCTestManifests.swift"; 138 | sourceTree = ""; 139 | }; 140 | "OBJ_18" = { 141 | isa = "PBXGroup"; 142 | children = ( 143 | "BxRefreshableScrollView::BxRefreshableScrollViewTests::Product", 144 | "BxRefreshableScrollView::BxRefreshableScrollView::Product" 145 | ); 146 | name = "Products"; 147 | path = ""; 148 | sourceTree = "BUILT_PRODUCTS_DIR"; 149 | }; 150 | "OBJ_2" = { 151 | isa = "XCConfigurationList"; 152 | buildConfigurations = ( 153 | "OBJ_3", 154 | "OBJ_4" 155 | ); 156 | defaultConfigurationIsVisible = "0"; 157 | defaultConfigurationName = "Release"; 158 | }; 159 | "OBJ_21" = { 160 | isa = "PBXFileReference"; 161 | path = "README.md"; 162 | sourceTree = ""; 163 | }; 164 | "OBJ_23" = { 165 | isa = "XCConfigurationList"; 166 | buildConfigurations = ( 167 | "OBJ_24", 168 | "OBJ_25" 169 | ); 170 | defaultConfigurationIsVisible = "0"; 171 | defaultConfigurationName = "Release"; 172 | }; 173 | "OBJ_24" = { 174 | isa = "XCBuildConfiguration"; 175 | buildSettings = { 176 | ENABLE_TESTABILITY = "YES"; 177 | FRAMEWORK_SEARCH_PATHS = ( 178 | "$(inherited)", 179 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 180 | ); 181 | HEADER_SEARCH_PATHS = ( 182 | "$(inherited)" 183 | ); 184 | INFOPLIST_FILE = "BxRefreshableScrollView.xcodeproj/BxRefreshableScrollView_Info.plist"; 185 | IPHONEOS_DEPLOYMENT_TARGET = "9.0"; 186 | LD_RUNPATH_SEARCH_PATHS = ( 187 | "$(inherited)", 188 | "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx" 189 | ); 190 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 191 | OTHER_CFLAGS = ( 192 | "$(inherited)" 193 | ); 194 | OTHER_LDFLAGS = ( 195 | "$(inherited)" 196 | ); 197 | OTHER_SWIFT_FLAGS = ( 198 | "$(inherited)" 199 | ); 200 | PRODUCT_BUNDLE_IDENTIFIER = "BxRefreshableScrollView"; 201 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 202 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 203 | SKIP_INSTALL = "YES"; 204 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 205 | "$(inherited)" 206 | ); 207 | SWIFT_VERSION = "5.0"; 208 | TARGET_NAME = "BxRefreshableScrollView"; 209 | TVOS_DEPLOYMENT_TARGET = "9.0"; 210 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 211 | }; 212 | name = "Debug"; 213 | }; 214 | "OBJ_25" = { 215 | isa = "XCBuildConfiguration"; 216 | buildSettings = { 217 | ENABLE_TESTABILITY = "YES"; 218 | FRAMEWORK_SEARCH_PATHS = ( 219 | "$(inherited)", 220 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 221 | ); 222 | HEADER_SEARCH_PATHS = ( 223 | "$(inherited)" 224 | ); 225 | INFOPLIST_FILE = "BxRefreshableScrollView.xcodeproj/BxRefreshableScrollView_Info.plist"; 226 | IPHONEOS_DEPLOYMENT_TARGET = "9.0"; 227 | LD_RUNPATH_SEARCH_PATHS = ( 228 | "$(inherited)", 229 | "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx" 230 | ); 231 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 232 | OTHER_CFLAGS = ( 233 | "$(inherited)" 234 | ); 235 | OTHER_LDFLAGS = ( 236 | "$(inherited)" 237 | ); 238 | OTHER_SWIFT_FLAGS = ( 239 | "$(inherited)" 240 | ); 241 | PRODUCT_BUNDLE_IDENTIFIER = "BxRefreshableScrollView"; 242 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 243 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 244 | SKIP_INSTALL = "YES"; 245 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 246 | "$(inherited)" 247 | ); 248 | SWIFT_VERSION = "5.0"; 249 | TARGET_NAME = "BxRefreshableScrollView"; 250 | TVOS_DEPLOYMENT_TARGET = "9.0"; 251 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 252 | }; 253 | name = "Release"; 254 | }; 255 | "OBJ_26" = { 256 | isa = "PBXSourcesBuildPhase"; 257 | files = ( 258 | "OBJ_27", 259 | "OBJ_28", 260 | "OBJ_29" 261 | ); 262 | }; 263 | "OBJ_27" = { 264 | isa = "PBXBuildFile"; 265 | fileRef = "OBJ_11"; 266 | }; 267 | "OBJ_28" = { 268 | isa = "PBXBuildFile"; 269 | fileRef = "OBJ_12"; 270 | }; 271 | "OBJ_29" = { 272 | isa = "PBXBuildFile"; 273 | fileRef = "OBJ_13"; 274 | }; 275 | "OBJ_3" = { 276 | isa = "XCBuildConfiguration"; 277 | buildSettings = { 278 | CLANG_ENABLE_OBJC_ARC = "YES"; 279 | COMBINE_HIDPI_IMAGES = "YES"; 280 | COPY_PHASE_STRIP = "NO"; 281 | DEBUG_INFORMATION_FORMAT = "dwarf"; 282 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 283 | ENABLE_NS_ASSERTIONS = "YES"; 284 | GCC_OPTIMIZATION_LEVEL = "0"; 285 | GCC_PREPROCESSOR_DEFINITIONS = ( 286 | "$(inherited)", 287 | "SWIFT_PACKAGE=1", 288 | "DEBUG=1" 289 | ); 290 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 291 | ONLY_ACTIVE_ARCH = "YES"; 292 | OTHER_SWIFT_FLAGS = ( 293 | "$(inherited)", 294 | "-DXcode" 295 | ); 296 | PRODUCT_NAME = "$(TARGET_NAME)"; 297 | SDKROOT = "macosx"; 298 | SUPPORTED_PLATFORMS = ( 299 | "macosx", 300 | "iphoneos", 301 | "iphonesimulator", 302 | "appletvos", 303 | "appletvsimulator", 304 | "watchos", 305 | "watchsimulator" 306 | ); 307 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 308 | "$(inherited)", 309 | "SWIFT_PACKAGE", 310 | "DEBUG" 311 | ); 312 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 313 | USE_HEADERMAP = "NO"; 314 | }; 315 | name = "Debug"; 316 | }; 317 | "OBJ_30" = { 318 | isa = "PBXFrameworksBuildPhase"; 319 | files = ( 320 | ); 321 | }; 322 | "OBJ_32" = { 323 | isa = "XCConfigurationList"; 324 | buildConfigurations = ( 325 | "OBJ_33", 326 | "OBJ_34" 327 | ); 328 | defaultConfigurationIsVisible = "0"; 329 | defaultConfigurationName = "Release"; 330 | }; 331 | "OBJ_33" = { 332 | isa = "XCBuildConfiguration"; 333 | buildSettings = { 334 | LD = "/usr/bin/true"; 335 | OTHER_SWIFT_FLAGS = ( 336 | "-swift-version", 337 | "5", 338 | "-I", 339 | "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2", 340 | "-sdk", 341 | "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk", 342 | "-package-description-version", 343 | "5.3.0" 344 | ); 345 | SWIFT_VERSION = "5.0"; 346 | }; 347 | name = "Debug"; 348 | }; 349 | "OBJ_34" = { 350 | isa = "XCBuildConfiguration"; 351 | buildSettings = { 352 | LD = "/usr/bin/true"; 353 | OTHER_SWIFT_FLAGS = ( 354 | "-swift-version", 355 | "5", 356 | "-I", 357 | "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2", 358 | "-sdk", 359 | "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk", 360 | "-package-description-version", 361 | "5.3.0" 362 | ); 363 | SWIFT_VERSION = "5.0"; 364 | }; 365 | name = "Release"; 366 | }; 367 | "OBJ_35" = { 368 | isa = "PBXSourcesBuildPhase"; 369 | files = ( 370 | "OBJ_36" 371 | ); 372 | }; 373 | "OBJ_36" = { 374 | isa = "PBXBuildFile"; 375 | fileRef = "OBJ_6"; 376 | }; 377 | "OBJ_38" = { 378 | isa = "XCConfigurationList"; 379 | buildConfigurations = ( 380 | "OBJ_39", 381 | "OBJ_40" 382 | ); 383 | defaultConfigurationIsVisible = "0"; 384 | defaultConfigurationName = "Release"; 385 | }; 386 | "OBJ_39" = { 387 | isa = "XCBuildConfiguration"; 388 | buildSettings = { 389 | }; 390 | name = "Debug"; 391 | }; 392 | "OBJ_4" = { 393 | isa = "XCBuildConfiguration"; 394 | buildSettings = { 395 | CLANG_ENABLE_OBJC_ARC = "YES"; 396 | COMBINE_HIDPI_IMAGES = "YES"; 397 | COPY_PHASE_STRIP = "YES"; 398 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 399 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 400 | GCC_OPTIMIZATION_LEVEL = "s"; 401 | GCC_PREPROCESSOR_DEFINITIONS = ( 402 | "$(inherited)", 403 | "SWIFT_PACKAGE=1" 404 | ); 405 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 406 | OTHER_SWIFT_FLAGS = ( 407 | "$(inherited)", 408 | "-DXcode" 409 | ); 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | SDKROOT = "macosx"; 412 | SUPPORTED_PLATFORMS = ( 413 | "macosx", 414 | "iphoneos", 415 | "iphonesimulator", 416 | "appletvos", 417 | "appletvsimulator", 418 | "watchos", 419 | "watchsimulator" 420 | ); 421 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 422 | "$(inherited)", 423 | "SWIFT_PACKAGE" 424 | ); 425 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 426 | USE_HEADERMAP = "NO"; 427 | }; 428 | name = "Release"; 429 | }; 430 | "OBJ_40" = { 431 | isa = "XCBuildConfiguration"; 432 | buildSettings = { 433 | }; 434 | name = "Release"; 435 | }; 436 | "OBJ_41" = { 437 | isa = "PBXTargetDependency"; 438 | target = "BxRefreshableScrollView::BxRefreshableScrollViewTests"; 439 | }; 440 | "OBJ_43" = { 441 | isa = "XCConfigurationList"; 442 | buildConfigurations = ( 443 | "OBJ_44", 444 | "OBJ_45" 445 | ); 446 | defaultConfigurationIsVisible = "0"; 447 | defaultConfigurationName = "Release"; 448 | }; 449 | "OBJ_44" = { 450 | isa = "XCBuildConfiguration"; 451 | buildSettings = { 452 | CLANG_ENABLE_MODULES = "YES"; 453 | EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES"; 454 | FRAMEWORK_SEARCH_PATHS = ( 455 | "$(inherited)", 456 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 457 | ); 458 | HEADER_SEARCH_PATHS = ( 459 | "$(inherited)" 460 | ); 461 | INFOPLIST_FILE = "BxRefreshableScrollView.xcodeproj/BxRefreshableScrollViewTests_Info.plist"; 462 | IPHONEOS_DEPLOYMENT_TARGET = "14.0"; 463 | LD_RUNPATH_SEARCH_PATHS = ( 464 | "$(inherited)", 465 | "@loader_path/../Frameworks", 466 | "@loader_path/Frameworks" 467 | ); 468 | MACOSX_DEPLOYMENT_TARGET = "10.15"; 469 | OTHER_CFLAGS = ( 470 | "$(inherited)" 471 | ); 472 | OTHER_LDFLAGS = ( 473 | "$(inherited)" 474 | ); 475 | OTHER_SWIFT_FLAGS = ( 476 | "$(inherited)" 477 | ); 478 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 479 | "$(inherited)" 480 | ); 481 | SWIFT_VERSION = "5.0"; 482 | TARGET_NAME = "BxRefreshableScrollViewTests"; 483 | TVOS_DEPLOYMENT_TARGET = "9.0"; 484 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 485 | }; 486 | name = "Debug"; 487 | }; 488 | "OBJ_45" = { 489 | isa = "XCBuildConfiguration"; 490 | buildSettings = { 491 | CLANG_ENABLE_MODULES = "YES"; 492 | EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES"; 493 | FRAMEWORK_SEARCH_PATHS = ( 494 | "$(inherited)", 495 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 496 | ); 497 | HEADER_SEARCH_PATHS = ( 498 | "$(inherited)" 499 | ); 500 | INFOPLIST_FILE = "BxRefreshableScrollView.xcodeproj/BxRefreshableScrollViewTests_Info.plist"; 501 | IPHONEOS_DEPLOYMENT_TARGET = "14.0"; 502 | LD_RUNPATH_SEARCH_PATHS = ( 503 | "$(inherited)", 504 | "@loader_path/../Frameworks", 505 | "@loader_path/Frameworks" 506 | ); 507 | MACOSX_DEPLOYMENT_TARGET = "10.15"; 508 | OTHER_CFLAGS = ( 509 | "$(inherited)" 510 | ); 511 | OTHER_LDFLAGS = ( 512 | "$(inherited)" 513 | ); 514 | OTHER_SWIFT_FLAGS = ( 515 | "$(inherited)" 516 | ); 517 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 518 | "$(inherited)" 519 | ); 520 | SWIFT_VERSION = "5.0"; 521 | TARGET_NAME = "BxRefreshableScrollViewTests"; 522 | TVOS_DEPLOYMENT_TARGET = "9.0"; 523 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 524 | }; 525 | name = "Release"; 526 | }; 527 | "OBJ_46" = { 528 | isa = "PBXSourcesBuildPhase"; 529 | files = ( 530 | "OBJ_47", 531 | "OBJ_48" 532 | ); 533 | }; 534 | "OBJ_47" = { 535 | isa = "PBXBuildFile"; 536 | fileRef = "OBJ_16"; 537 | }; 538 | "OBJ_48" = { 539 | isa = "PBXBuildFile"; 540 | fileRef = "OBJ_17"; 541 | }; 542 | "OBJ_49" = { 543 | isa = "PBXFrameworksBuildPhase"; 544 | files = ( 545 | "OBJ_50" 546 | ); 547 | }; 548 | "OBJ_5" = { 549 | isa = "PBXGroup"; 550 | children = ( 551 | "OBJ_6", 552 | "OBJ_7", 553 | "OBJ_14", 554 | "OBJ_18", 555 | "OBJ_21" 556 | ); 557 | path = ""; 558 | sourceTree = ""; 559 | }; 560 | "OBJ_50" = { 561 | isa = "PBXBuildFile"; 562 | fileRef = "BxRefreshableScrollView::BxRefreshableScrollView::Product"; 563 | }; 564 | "OBJ_51" = { 565 | isa = "PBXTargetDependency"; 566 | target = "BxRefreshableScrollView::BxRefreshableScrollView"; 567 | }; 568 | "OBJ_6" = { 569 | isa = "PBXFileReference"; 570 | explicitFileType = "sourcecode.swift"; 571 | path = "Package.swift"; 572 | sourceTree = ""; 573 | }; 574 | "OBJ_7" = { 575 | isa = "PBXGroup"; 576 | children = ( 577 | "OBJ_8" 578 | ); 579 | name = "Sources"; 580 | path = ""; 581 | sourceTree = "SOURCE_ROOT"; 582 | }; 583 | "OBJ_8" = { 584 | isa = "PBXGroup"; 585 | children = ( 586 | "OBJ_9", 587 | "OBJ_10", 588 | "OBJ_11", 589 | "OBJ_12", 590 | "OBJ_13" 591 | ); 592 | name = "BxRefreshableScrollView"; 593 | path = "Sources/BxRefreshableScrollView"; 594 | sourceTree = "SOURCE_ROOT"; 595 | }; 596 | "OBJ_9" = { 597 | isa = "PBXFileReference"; 598 | path = "BxRefreshableScrollView.h"; 599 | sourceTree = ""; 600 | }; 601 | }; 602 | rootObject = "OBJ_1"; 603 | } 604 | --------------------------------------------------------------------------------