├── .gitignore ├── AxisSheetExample ├── AxisSheetExample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── AxisSheet.xcscheme ├── Shared │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── AxisSheetExampleApp.swift │ ├── ContentView.swift │ └── Views │ │ ├── SheetConstants.swift │ │ ├── SheetControls.swift │ │ └── SheetSlider.swift └── macOS │ └── macOS.entitlements ├── LICENSE ├── Markdown ├── AxisSheet.png ├── bottom.png ├── leading.png ├── top.png └── trailing.png ├── Package.swift ├── README.md ├── Sources └── AxisSheet │ ├── Private │ ├── Extensions │ │ └── Animation+Extensions.swift │ └── RoundCorner.swift │ └── Public │ ├── AxisSheet.swift │ ├── Constants │ ├── ASBackgroundConstant.swift │ ├── ASConstant.swift │ └── ASHeaderConstant.swift │ └── Extensions │ └── View+Extensions.swift └── Tests └── AxisSheetTests └── AxisSheetTests.swift /.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 | -------------------------------------------------------------------------------- /AxisSheetExample/AxisSheetExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4BDB51E927BC72570039E2AC /* AxisSheetExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB51D927BC72560039E2AC /* AxisSheetExampleApp.swift */; }; 11 | 4BDB51EA27BC72570039E2AC /* AxisSheetExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB51D927BC72560039E2AC /* AxisSheetExampleApp.swift */; }; 12 | 4BDB51ED27BC72570039E2AC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4BDB51DB27BC72570039E2AC /* Assets.xcassets */; }; 13 | 4BDB51EE27BC72570039E2AC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4BDB51DB27BC72570039E2AC /* Assets.xcassets */; }; 14 | 4BDB51FB27BC72BA0039E2AC /* AxisSheet in Frameworks */ = {isa = PBXBuildFile; productRef = 4BDB51FA27BC72BA0039E2AC /* AxisSheet */; }; 15 | 4BDB51FD27BC72BE0039E2AC /* AxisSheet in Frameworks */ = {isa = PBXBuildFile; productRef = 4BDB51FC27BC72BE0039E2AC /* AxisSheet */; }; 16 | 4BDB520E27BC75490039E2AC /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB520A27BC75490039E2AC /* ContentView.swift */; }; 17 | 4BDB520F27BC75490039E2AC /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB520A27BC75490039E2AC /* ContentView.swift */; }; 18 | 4BDB521027BC75490039E2AC /* SheetControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB520B27BC75490039E2AC /* SheetControls.swift */; }; 19 | 4BDB521127BC75490039E2AC /* SheetControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB520B27BC75490039E2AC /* SheetControls.swift */; }; 20 | 4BDB521227BC75490039E2AC /* SheetConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB520C27BC75490039E2AC /* SheetConstants.swift */; }; 21 | 4BDB521327BC75490039E2AC /* SheetConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB520C27BC75490039E2AC /* SheetConstants.swift */; }; 22 | 4BDB521427BC75490039E2AC /* SheetSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB520D27BC75490039E2AC /* SheetSlider.swift */; }; 23 | 4BDB521527BC75490039E2AC /* SheetSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDB520D27BC75490039E2AC /* SheetSlider.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 4BDB51D927BC72560039E2AC /* AxisSheetExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AxisSheetExampleApp.swift; sourceTree = ""; }; 28 | 4BDB51DB27BC72570039E2AC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 29 | 4BDB51E027BC72570039E2AC /* AxisSheetExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AxisSheetExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 4BDB51E627BC72570039E2AC /* AxisSheetExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AxisSheetExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 4BDB51E827BC72570039E2AC /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; 32 | 4BDB51F827BC72750039E2AC /* AxisSheet */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = AxisSheet; path = ..; sourceTree = ""; }; 33 | 4BDB520A27BC75490039E2AC /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 34 | 4BDB520B27BC75490039E2AC /* SheetControls.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SheetControls.swift; sourceTree = ""; }; 35 | 4BDB520C27BC75490039E2AC /* SheetConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SheetConstants.swift; sourceTree = ""; }; 36 | 4BDB520D27BC75490039E2AC /* SheetSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SheetSlider.swift; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | 4BDB51DD27BC72570039E2AC /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | 4BDB51FB27BC72BA0039E2AC /* AxisSheet in Frameworks */, 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | 4BDB51E327BC72570039E2AC /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | 4BDB51FD27BC72BE0039E2AC /* AxisSheet in Frameworks */, 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | /* End PBXFrameworksBuildPhase section */ 57 | 58 | /* Begin PBXGroup section */ 59 | 4B39AB7B27BE2A47001D3347 /* Views */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 4BDB520C27BC75490039E2AC /* SheetConstants.swift */, 63 | 4BDB520B27BC75490039E2AC /* SheetControls.swift */, 64 | 4BDB520D27BC75490039E2AC /* SheetSlider.swift */, 65 | ); 66 | path = Views; 67 | sourceTree = ""; 68 | }; 69 | 4BDB51D327BC72560039E2AC = { 70 | isa = PBXGroup; 71 | children = ( 72 | 4BDB51F727BC72750039E2AC /* Packages */, 73 | 4BDB51D827BC72560039E2AC /* Shared */, 74 | 4BDB51E727BC72570039E2AC /* macOS */, 75 | 4BDB51E127BC72570039E2AC /* Products */, 76 | 4BDB51F927BC72BA0039E2AC /* Frameworks */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 4BDB51D827BC72560039E2AC /* Shared */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 4BDB51D927BC72560039E2AC /* AxisSheetExampleApp.swift */, 84 | 4BDB520A27BC75490039E2AC /* ContentView.swift */, 85 | 4B39AB7B27BE2A47001D3347 /* Views */, 86 | 4BDB51DB27BC72570039E2AC /* Assets.xcassets */, 87 | ); 88 | path = Shared; 89 | sourceTree = ""; 90 | }; 91 | 4BDB51E127BC72570039E2AC /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 4BDB51E027BC72570039E2AC /* AxisSheetExample.app */, 95 | 4BDB51E627BC72570039E2AC /* AxisSheetExample.app */, 96 | ); 97 | name = Products; 98 | sourceTree = ""; 99 | }; 100 | 4BDB51E727BC72570039E2AC /* macOS */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 4BDB51E827BC72570039E2AC /* macOS.entitlements */, 104 | ); 105 | path = macOS; 106 | sourceTree = ""; 107 | }; 108 | 4BDB51F727BC72750039E2AC /* Packages */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 4BDB51F827BC72750039E2AC /* AxisSheet */, 112 | ); 113 | name = Packages; 114 | sourceTree = ""; 115 | }; 116 | 4BDB51F927BC72BA0039E2AC /* Frameworks */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | ); 120 | name = Frameworks; 121 | sourceTree = ""; 122 | }; 123 | /* End PBXGroup section */ 124 | 125 | /* Begin PBXNativeTarget section */ 126 | 4BDB51DF27BC72570039E2AC /* AxisSheetExample (iOS) */ = { 127 | isa = PBXNativeTarget; 128 | buildConfigurationList = 4BDB51F127BC72570039E2AC /* Build configuration list for PBXNativeTarget "AxisSheetExample (iOS)" */; 129 | buildPhases = ( 130 | 4BDB51DC27BC72570039E2AC /* Sources */, 131 | 4BDB51DD27BC72570039E2AC /* Frameworks */, 132 | 4BDB51DE27BC72570039E2AC /* Resources */, 133 | ); 134 | buildRules = ( 135 | ); 136 | dependencies = ( 137 | ); 138 | name = "AxisSheetExample (iOS)"; 139 | packageProductDependencies = ( 140 | 4BDB51FA27BC72BA0039E2AC /* AxisSheet */, 141 | ); 142 | productName = "AxisSheetExample (iOS)"; 143 | productReference = 4BDB51E027BC72570039E2AC /* AxisSheetExample.app */; 144 | productType = "com.apple.product-type.application"; 145 | }; 146 | 4BDB51E527BC72570039E2AC /* AxisSheetExample (macOS) */ = { 147 | isa = PBXNativeTarget; 148 | buildConfigurationList = 4BDB51F427BC72570039E2AC /* Build configuration list for PBXNativeTarget "AxisSheetExample (macOS)" */; 149 | buildPhases = ( 150 | 4BDB51E227BC72570039E2AC /* Sources */, 151 | 4BDB51E327BC72570039E2AC /* Frameworks */, 152 | 4BDB51E427BC72570039E2AC /* Resources */, 153 | ); 154 | buildRules = ( 155 | ); 156 | dependencies = ( 157 | ); 158 | name = "AxisSheetExample (macOS)"; 159 | packageProductDependencies = ( 160 | 4BDB51FC27BC72BE0039E2AC /* AxisSheet */, 161 | ); 162 | productName = "AxisSheetExample (macOS)"; 163 | productReference = 4BDB51E627BC72570039E2AC /* AxisSheetExample.app */; 164 | productType = "com.apple.product-type.application"; 165 | }; 166 | /* End PBXNativeTarget section */ 167 | 168 | /* Begin PBXProject section */ 169 | 4BDB51D427BC72560039E2AC /* Project object */ = { 170 | isa = PBXProject; 171 | attributes = { 172 | BuildIndependentTargetsInParallel = 1; 173 | LastSwiftUpdateCheck = 1320; 174 | LastUpgradeCheck = 1320; 175 | TargetAttributes = { 176 | 4BDB51DF27BC72570039E2AC = { 177 | CreatedOnToolsVersion = 13.2.1; 178 | }; 179 | 4BDB51E527BC72570039E2AC = { 180 | CreatedOnToolsVersion = 13.2.1; 181 | }; 182 | }; 183 | }; 184 | buildConfigurationList = 4BDB51D727BC72560039E2AC /* Build configuration list for PBXProject "AxisSheetExample" */; 185 | compatibilityVersion = "Xcode 13.0"; 186 | developmentRegion = en; 187 | hasScannedForEncodings = 0; 188 | knownRegions = ( 189 | en, 190 | Base, 191 | ); 192 | mainGroup = 4BDB51D327BC72560039E2AC; 193 | productRefGroup = 4BDB51E127BC72570039E2AC /* Products */; 194 | projectDirPath = ""; 195 | projectRoot = ""; 196 | targets = ( 197 | 4BDB51DF27BC72570039E2AC /* AxisSheetExample (iOS) */, 198 | 4BDB51E527BC72570039E2AC /* AxisSheetExample (macOS) */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | 4BDB51DE27BC72570039E2AC /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | 4BDB51ED27BC72570039E2AC /* Assets.xcassets in Resources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | 4BDB51E427BC72570039E2AC /* Resources */ = { 213 | isa = PBXResourcesBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | 4BDB51EE27BC72570039E2AC /* Assets.xcassets in Resources */, 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | }; 220 | /* End PBXResourcesBuildPhase section */ 221 | 222 | /* Begin PBXSourcesBuildPhase section */ 223 | 4BDB51DC27BC72570039E2AC /* Sources */ = { 224 | isa = PBXSourcesBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | 4BDB520E27BC75490039E2AC /* ContentView.swift in Sources */, 228 | 4BDB521027BC75490039E2AC /* SheetControls.swift in Sources */, 229 | 4BDB521227BC75490039E2AC /* SheetConstants.swift in Sources */, 230 | 4BDB521427BC75490039E2AC /* SheetSlider.swift in Sources */, 231 | 4BDB51E927BC72570039E2AC /* AxisSheetExampleApp.swift in Sources */, 232 | ); 233 | runOnlyForDeploymentPostprocessing = 0; 234 | }; 235 | 4BDB51E227BC72570039E2AC /* Sources */ = { 236 | isa = PBXSourcesBuildPhase; 237 | buildActionMask = 2147483647; 238 | files = ( 239 | 4BDB520F27BC75490039E2AC /* ContentView.swift in Sources */, 240 | 4BDB521127BC75490039E2AC /* SheetControls.swift in Sources */, 241 | 4BDB521327BC75490039E2AC /* SheetConstants.swift in Sources */, 242 | 4BDB521527BC75490039E2AC /* SheetSlider.swift in Sources */, 243 | 4BDB51EA27BC72570039E2AC /* AxisSheetExampleApp.swift in Sources */, 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | /* End PBXSourcesBuildPhase section */ 248 | 249 | /* Begin XCBuildConfiguration section */ 250 | 4BDB51EF27BC72570039E2AC /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ALWAYS_SEARCH_USER_PATHS = NO; 254 | CLANG_ANALYZER_NONNULL = YES; 255 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 256 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 257 | CLANG_CXX_LIBRARY = "libc++"; 258 | CLANG_ENABLE_MODULES = YES; 259 | CLANG_ENABLE_OBJC_ARC = YES; 260 | CLANG_ENABLE_OBJC_WEAK = YES; 261 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 262 | CLANG_WARN_BOOL_CONVERSION = YES; 263 | CLANG_WARN_COMMA = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 266 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 267 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 268 | CLANG_WARN_EMPTY_BODY = YES; 269 | CLANG_WARN_ENUM_CONVERSION = YES; 270 | CLANG_WARN_INFINITE_RECURSION = YES; 271 | CLANG_WARN_INT_CONVERSION = YES; 272 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 273 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 274 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 276 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 277 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 278 | CLANG_WARN_STRICT_PROTOTYPES = YES; 279 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 280 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | COPY_PHASE_STRIP = NO; 284 | DEBUG_INFORMATION_FORMAT = dwarf; 285 | ENABLE_STRICT_OBJC_MSGSEND = YES; 286 | ENABLE_TESTABILITY = YES; 287 | GCC_C_LANGUAGE_STANDARD = gnu11; 288 | GCC_DYNAMIC_NO_PIC = NO; 289 | GCC_NO_COMMON_BLOCKS = YES; 290 | GCC_OPTIMIZATION_LEVEL = 0; 291 | GCC_PREPROCESSOR_DEFINITIONS = ( 292 | "DEBUG=1", 293 | "$(inherited)", 294 | ); 295 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 296 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 297 | GCC_WARN_UNDECLARED_SELECTOR = YES; 298 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 299 | GCC_WARN_UNUSED_FUNCTION = YES; 300 | GCC_WARN_UNUSED_VARIABLE = YES; 301 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 302 | MTL_FAST_MATH = YES; 303 | ONLY_ACTIVE_ARCH = YES; 304 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 305 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 306 | }; 307 | name = Debug; 308 | }; 309 | 4BDB51F027BC72570039E2AC /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | ALWAYS_SEARCH_USER_PATHS = NO; 313 | CLANG_ANALYZER_NONNULL = YES; 314 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 315 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 316 | CLANG_CXX_LIBRARY = "libc++"; 317 | CLANG_ENABLE_MODULES = YES; 318 | CLANG_ENABLE_OBJC_ARC = YES; 319 | CLANG_ENABLE_OBJC_WEAK = YES; 320 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 321 | CLANG_WARN_BOOL_CONVERSION = YES; 322 | CLANG_WARN_COMMA = YES; 323 | CLANG_WARN_CONSTANT_CONVERSION = YES; 324 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 325 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 326 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 327 | CLANG_WARN_EMPTY_BODY = YES; 328 | CLANG_WARN_ENUM_CONVERSION = YES; 329 | CLANG_WARN_INFINITE_RECURSION = YES; 330 | CLANG_WARN_INT_CONVERSION = YES; 331 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 332 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 333 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 334 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 335 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 336 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 337 | CLANG_WARN_STRICT_PROTOTYPES = YES; 338 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 339 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 340 | CLANG_WARN_UNREACHABLE_CODE = YES; 341 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 342 | COPY_PHASE_STRIP = NO; 343 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 344 | ENABLE_NS_ASSERTIONS = NO; 345 | ENABLE_STRICT_OBJC_MSGSEND = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu11; 347 | GCC_NO_COMMON_BLOCKS = YES; 348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 350 | GCC_WARN_UNDECLARED_SELECTOR = YES; 351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | MTL_ENABLE_DEBUG_INFO = NO; 355 | MTL_FAST_MATH = YES; 356 | SWIFT_COMPILATION_MODE = wholemodule; 357 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 358 | }; 359 | name = Release; 360 | }; 361 | 4BDB51F227BC72570039E2AC /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 365 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 366 | CODE_SIGN_STYLE = Automatic; 367 | CURRENT_PROJECT_VERSION = 1; 368 | DEVELOPMENT_TEAM = SM6445X39C; 369 | ENABLE_PREVIEWS = YES; 370 | GENERATE_INFOPLIST_FILE = YES; 371 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 372 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 373 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 374 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 375 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 376 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 377 | LD_RUNPATH_SEARCH_PATHS = ( 378 | "$(inherited)", 379 | "@executable_path/Frameworks", 380 | ); 381 | MARKETING_VERSION = 1.0; 382 | PRODUCT_BUNDLE_IDENTIFIER = com.devstore.AxisSheetExample; 383 | PRODUCT_NAME = AxisSheetExample; 384 | SDKROOT = iphoneos; 385 | SWIFT_EMIT_LOC_STRINGS = YES; 386 | SWIFT_VERSION = 5.0; 387 | TARGETED_DEVICE_FAMILY = "1,2"; 388 | }; 389 | name = Debug; 390 | }; 391 | 4BDB51F327BC72570039E2AC /* Release */ = { 392 | isa = XCBuildConfiguration; 393 | buildSettings = { 394 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 395 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 396 | CODE_SIGN_STYLE = Automatic; 397 | CURRENT_PROJECT_VERSION = 1; 398 | DEVELOPMENT_TEAM = SM6445X39C; 399 | ENABLE_PREVIEWS = YES; 400 | GENERATE_INFOPLIST_FILE = YES; 401 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 402 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 403 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 404 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 405 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 406 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 407 | LD_RUNPATH_SEARCH_PATHS = ( 408 | "$(inherited)", 409 | "@executable_path/Frameworks", 410 | ); 411 | MARKETING_VERSION = 1.0; 412 | PRODUCT_BUNDLE_IDENTIFIER = com.devstore.AxisSheetExample; 413 | PRODUCT_NAME = AxisSheetExample; 414 | SDKROOT = iphoneos; 415 | SWIFT_EMIT_LOC_STRINGS = YES; 416 | SWIFT_VERSION = 5.0; 417 | TARGETED_DEVICE_FAMILY = "1,2"; 418 | VALIDATE_PRODUCT = YES; 419 | }; 420 | name = Release; 421 | }; 422 | 4BDB51F527BC72570039E2AC /* Debug */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 426 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 427 | CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; 428 | CODE_SIGN_STYLE = Automatic; 429 | COMBINE_HIDPI_IMAGES = YES; 430 | CURRENT_PROJECT_VERSION = 1; 431 | DEVELOPMENT_TEAM = SM6445X39C; 432 | ENABLE_HARDENED_RUNTIME = YES; 433 | ENABLE_PREVIEWS = YES; 434 | GENERATE_INFOPLIST_FILE = YES; 435 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 436 | LD_RUNPATH_SEARCH_PATHS = ( 437 | "$(inherited)", 438 | "@executable_path/../Frameworks", 439 | ); 440 | MACOSX_DEPLOYMENT_TARGET = 11.0; 441 | MARKETING_VERSION = 1.0; 442 | PRODUCT_BUNDLE_IDENTIFIER = com.devstore.AxisSheetExample; 443 | PRODUCT_NAME = AxisSheetExample; 444 | SDKROOT = macosx; 445 | SWIFT_EMIT_LOC_STRINGS = YES; 446 | SWIFT_VERSION = 5.0; 447 | }; 448 | name = Debug; 449 | }; 450 | 4BDB51F627BC72570039E2AC /* Release */ = { 451 | isa = XCBuildConfiguration; 452 | buildSettings = { 453 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 454 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 455 | CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; 456 | CODE_SIGN_STYLE = Automatic; 457 | COMBINE_HIDPI_IMAGES = YES; 458 | CURRENT_PROJECT_VERSION = 1; 459 | DEVELOPMENT_TEAM = SM6445X39C; 460 | ENABLE_HARDENED_RUNTIME = YES; 461 | ENABLE_PREVIEWS = YES; 462 | GENERATE_INFOPLIST_FILE = YES; 463 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 464 | LD_RUNPATH_SEARCH_PATHS = ( 465 | "$(inherited)", 466 | "@executable_path/../Frameworks", 467 | ); 468 | MACOSX_DEPLOYMENT_TARGET = 11.0; 469 | MARKETING_VERSION = 1.0; 470 | PRODUCT_BUNDLE_IDENTIFIER = com.devstore.AxisSheetExample; 471 | PRODUCT_NAME = AxisSheetExample; 472 | SDKROOT = macosx; 473 | SWIFT_EMIT_LOC_STRINGS = YES; 474 | SWIFT_VERSION = 5.0; 475 | }; 476 | name = Release; 477 | }; 478 | /* End XCBuildConfiguration section */ 479 | 480 | /* Begin XCConfigurationList section */ 481 | 4BDB51D727BC72560039E2AC /* Build configuration list for PBXProject "AxisSheetExample" */ = { 482 | isa = XCConfigurationList; 483 | buildConfigurations = ( 484 | 4BDB51EF27BC72570039E2AC /* Debug */, 485 | 4BDB51F027BC72570039E2AC /* Release */, 486 | ); 487 | defaultConfigurationIsVisible = 0; 488 | defaultConfigurationName = Release; 489 | }; 490 | 4BDB51F127BC72570039E2AC /* Build configuration list for PBXNativeTarget "AxisSheetExample (iOS)" */ = { 491 | isa = XCConfigurationList; 492 | buildConfigurations = ( 493 | 4BDB51F227BC72570039E2AC /* Debug */, 494 | 4BDB51F327BC72570039E2AC /* Release */, 495 | ); 496 | defaultConfigurationIsVisible = 0; 497 | defaultConfigurationName = Release; 498 | }; 499 | 4BDB51F427BC72570039E2AC /* Build configuration list for PBXNativeTarget "AxisSheetExample (macOS)" */ = { 500 | isa = XCConfigurationList; 501 | buildConfigurations = ( 502 | 4BDB51F527BC72570039E2AC /* Debug */, 503 | 4BDB51F627BC72570039E2AC /* Release */, 504 | ); 505 | defaultConfigurationIsVisible = 0; 506 | defaultConfigurationName = Release; 507 | }; 508 | /* End XCConfigurationList section */ 509 | 510 | /* Begin XCSwiftPackageProductDependency section */ 511 | 4BDB51FA27BC72BA0039E2AC /* AxisSheet */ = { 512 | isa = XCSwiftPackageProductDependency; 513 | productName = AxisSheet; 514 | }; 515 | 4BDB51FC27BC72BE0039E2AC /* AxisSheet */ = { 516 | isa = XCSwiftPackageProductDependency; 517 | productName = AxisSheet; 518 | }; 519 | /* End XCSwiftPackageProductDependency section */ 520 | }; 521 | rootObject = 4BDB51D427BC72560039E2AC /* Project object */; 522 | } 523 | -------------------------------------------------------------------------------- /AxisSheetExample/AxisSheetExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AxisSheetExample/AxisSheetExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AxisSheetExample/AxisSheetExample.xcodeproj/xcshareddata/xcschemes/AxisSheet.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /AxisSheetExample/Shared/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.278", 9 | "green" : "0.475", 10 | "red" : "0.969" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AxisSheetExample/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | }, 93 | { 94 | "idiom" : "mac", 95 | "scale" : "1x", 96 | "size" : "16x16" 97 | }, 98 | { 99 | "idiom" : "mac", 100 | "scale" : "2x", 101 | "size" : "16x16" 102 | }, 103 | { 104 | "idiom" : "mac", 105 | "scale" : "1x", 106 | "size" : "32x32" 107 | }, 108 | { 109 | "idiom" : "mac", 110 | "scale" : "2x", 111 | "size" : "32x32" 112 | }, 113 | { 114 | "idiom" : "mac", 115 | "scale" : "1x", 116 | "size" : "128x128" 117 | }, 118 | { 119 | "idiom" : "mac", 120 | "scale" : "2x", 121 | "size" : "128x128" 122 | }, 123 | { 124 | "idiom" : "mac", 125 | "scale" : "1x", 126 | "size" : "256x256" 127 | }, 128 | { 129 | "idiom" : "mac", 130 | "scale" : "2x", 131 | "size" : "256x256" 132 | }, 133 | { 134 | "idiom" : "mac", 135 | "scale" : "1x", 136 | "size" : "512x512" 137 | }, 138 | { 139 | "idiom" : "mac", 140 | "scale" : "2x", 141 | "size" : "512x512" 142 | } 143 | ], 144 | "info" : { 145 | "author" : "xcode", 146 | "version" : 1 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /AxisSheetExample/Shared/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AxisSheetExample/Shared/AxisSheetExampleApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AxisSheetExampleApp.swift 3 | // AxisSheetExample 4 | // 5 | // Created by jasu on 2022/02/16. 6 | // Copyright (c) 2022 jasu All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | @main 12 | struct AxisSheetExampleApp: App { 13 | var body: some Scene { 14 | WindowGroup { 15 | ContentView() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AxisSheetExample/Shared/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // AxisSheetExample 4 | // 5 | // Created by jasu on 2022/02/14. 6 | // Copyright (c) 2022 jasu All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import AxisSheet 11 | 12 | struct ContentView: View { 13 | 14 | @State private var isPresented: Bool = false 15 | #if os(iOS) 16 | @State private var constants = ASConstant() 17 | #else 18 | @State private var constants = ASConstant(size: 300, header: ASHeaderConstant(size: 50)) 19 | #endif 20 | @State private var isCustomHeader: Bool = false 21 | 22 | private var customHeader: some View { 23 | Rectangle().fill(Color.red.opacity(0.5)) 24 | .overlay( 25 | HStack { 26 | Text("Header") 27 | .frame(width: 160) 28 | .foregroundColor(.white) 29 | .rotationEffect(getHeaderAngle()) 30 | } 31 | ) 32 | } 33 | 34 | var body: some View { 35 | VStack(spacing: 0) { 36 | SheetControls(isPresented: $isPresented, 37 | constants: $constants, 38 | isCustomHeader: $isCustomHeader) 39 | .padding() 40 | ZStack { 41 | VStack { 42 | Text("AxisSheet") 43 | .font(.largeTitle) 44 | .fontWeight(.semibold) 45 | Text("for SwiftUI") 46 | .font(.headline) 47 | .opacity(0.5) 48 | } 49 | .foregroundColor(.accentColor) 50 | .offset(getOffset()) 51 | if !isCustomHeader { 52 | SheetConstants(constants: $constants) 53 | .axisSheet(isPresented: $isPresented, constants: constants) 54 | // /// or 55 | // AxisSheet(isPresented: $isPresented, constants: constants) { 56 | // SheetConstants(constants: $constants) 57 | // } 58 | }else { 59 | SheetConstants(constants: $constants) 60 | .axisSheet(isPresented: $isPresented, constants: constants) { 61 | customHeader 62 | } 63 | // /// or 64 | // AxisSheet(isPresented: $isPresented, constants: constants, header: { 65 | // customHeader 66 | // }, content: { 67 | // SheetConstants(constants: $constants) 68 | // }) 69 | } 70 | } 71 | .background(Color.blue.opacity(0.26)) 72 | .animation(.easeOut(duration: 0.2), value: constants) 73 | } 74 | } 75 | 76 | private func getHeaderAngle() -> Angle { 77 | switch constants.axisMode { 78 | case .top, .bottom: return Angle(degrees: 0) 79 | case .leading: return Angle(degrees: 90) 80 | case .trailing: return Angle(degrees: -90) 81 | } 82 | } 83 | 84 | private func getOffset() -> CGSize { 85 | guard constants.presentationMode == .minimize else { 86 | return .zero 87 | } 88 | switch constants.axisMode { 89 | case .top: return CGSize(width: 0, height: constants.header.size) 90 | case .bottom: return CGSize(width: 0, height: -constants.header.size) 91 | case .leading: return CGSize(width: constants.header.size, height: 0) 92 | case .trailing: return CGSize(width: -constants.header.size, height: 0) 93 | } 94 | } 95 | } 96 | 97 | struct ContentView_Previews: PreviewProvider { 98 | static var previews: some View { 99 | ContentView() 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /AxisSheetExample/Shared/Views/SheetConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SheetConstants.swift 3 | // AxisSheetExample 4 | // 5 | // Created by jasu on 2022/02/16. 6 | // Copyright (c) 2022 jasu All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import AxisSheet 11 | 12 | struct SheetConstants: View { 13 | 14 | @Binding var constants: ASConstant 15 | 16 | init(constants: Binding) { 17 | _constants = constants 18 | #if os(iOS) 19 | UITableView.appearance().backgroundColor = .clear 20 | #endif 21 | } 22 | 23 | var content: some View { 24 | Group { 25 | Section(header: Text("Header").foregroundColor(.accentColor)) { 26 | SheetSlider(title: "size", value: $constants.header.size, range: 24...70) 27 | SheetSlider(title: "shortAxis", value: $constants.header.shortAxis, range: 0...10) 28 | SheetSlider(title: "longAxis", value: $constants.header.longAxis, range: 0...80) 29 | SheetSlider(title: "radius", value: $constants.header.cornerRadius, range: 0...(constants.header.size / 2)) 30 | ColorPicker("foregroundColor", selection: $constants.header.color) 31 | ColorPicker("backgroundColor", selection: $constants.header.backgroundColor) 32 | } 33 | 34 | Section(header: Text("Content").foregroundColor(.accentColor)) { 35 | SheetSlider(title: "size", value: $constants.size, range: 200...500) 36 | } 37 | 38 | Section(header: Text("Background").foregroundColor(.accentColor)) { 39 | Toggle("disabled", isOn: $constants.background.disabled) 40 | .toggleStyle(SwitchToggleStyle(tint: .accentColor)) 41 | ColorPicker("color", selection: $constants.background.color) 42 | } 43 | } 44 | .foregroundColor(Color.white) 45 | .listRowBackground(Color.clear) 46 | } 47 | var body: some View { 48 | ZStack { 49 | #if os(iOS) 50 | Form { 51 | content 52 | } 53 | #else 54 | ScrollView { 55 | Form { 56 | content 57 | } 58 | .padding() 59 | } 60 | #endif 61 | } 62 | .background( 63 | ZStack { 64 | Color.gray 65 | Color.black.opacity(0.75) 66 | } 67 | ) 68 | } 69 | } 70 | 71 | struct SheetConstants_Previews: PreviewProvider { 72 | static var previews: some View { 73 | SheetConstants(constants: .constant(ASConstant())) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /AxisSheetExample/Shared/Views/SheetControls.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SheetControls.swift 3 | // AxisSheetExample 4 | // 5 | // Created by jasu on 2022/02/16. 6 | // Copyright (c) 2022 jasu All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import AxisSheet 11 | 12 | struct SheetControls: View { 13 | 14 | @Binding var isPresented: Bool 15 | @Binding var constants: ASConstant 16 | @Binding var isCustomHeader: Bool 17 | 18 | var body: some View { 19 | HStack { 20 | Toggle("", isOn: $isPresented) 21 | .toggleStyle(SwitchToggleStyle(tint: .accentColor)) 22 | .labelsHidden() 23 | VStack(alignment: .trailing) { 24 | Picker("", selection: $constants.axisMode) { 25 | Image(systemName: "rectangle.bottomthird.inset.filled").tag(ASAxisMode.bottom) 26 | Image(systemName: "rectangle.rightthird.inset.filled").tag(ASAxisMode.trailing) 27 | Image(systemName: "rectangle.leadingthird.inset.filled").tag(ASAxisMode.leading) 28 | Image(systemName: "rectangle.topthird.inset.filled").tag(ASAxisMode.top) 29 | } 30 | Picker("", selection: $constants.presentationMode) { 31 | Text("Minimize").tag(ASPresentationMode.minimize) 32 | Text("Hide").tag(ASPresentationMode.hide) 33 | } 34 | Picker("", selection: $isCustomHeader) { 35 | Text("Normal").tag(false) 36 | Text("Custom Header").tag(true) 37 | } 38 | } 39 | .pickerStyle(.segmented) 40 | .labelsHidden() 41 | } 42 | } 43 | } 44 | 45 | struct SheetControls_Previews: PreviewProvider { 46 | static var previews: some View { 47 | SheetControls(isPresented: .constant(true), 48 | constants: .constant(ASConstant()), 49 | isCustomHeader: .constant(false)) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AxisSheetExample/Shared/Views/SheetSlider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SheetSlider.swift 3 | // AxisSheetExample 4 | // 5 | // Created by jasu on 2022/02/16. 6 | // Copyright (c) 2022 jasu All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct SheetSlider: View { 12 | 13 | let title: String 14 | @Binding var value: CGFloat 15 | let range: ClosedRange 16 | 17 | var body: some View { 18 | VStack(alignment: .trailing, spacing: 0) { 19 | Text("\(value, specifier: "%.2f")") 20 | .font(.caption) 21 | .opacity(0.5) 22 | HStack { 23 | Text(title) 24 | Slider(value: $value, in: range) 25 | } 26 | } 27 | } 28 | } 29 | 30 | struct SheetSlider_Previews: PreviewProvider { 31 | static var previews: some View { 32 | SheetSlider(title: "Slider", value: .constant(0.5), range: 0.0...3.0) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AxisSheetExample/macOS/macOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 jasu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Markdown/AxisSheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasudev/AxisSheet/e577c37a7ee184f7018c85f0bf35baccbaa4c950/Markdown/AxisSheet.png -------------------------------------------------------------------------------- /Markdown/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasudev/AxisSheet/e577c37a7ee184f7018c85f0bf35baccbaa4c950/Markdown/bottom.png -------------------------------------------------------------------------------- /Markdown/leading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasudev/AxisSheet/e577c37a7ee184f7018c85f0bf35baccbaa4c950/Markdown/leading.png -------------------------------------------------------------------------------- /Markdown/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasudev/AxisSheet/e577c37a7ee184f7018c85f0bf35baccbaa4c950/Markdown/top.png -------------------------------------------------------------------------------- /Markdown/trailing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasudev/AxisSheet/e577c37a7ee184f7018c85f0bf35baccbaa4c950/Markdown/trailing.png -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.5 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: "AxisSheet", 8 | platforms: [ 9 | .iOS(.v14), 10 | .macOS(.v11) 11 | ], 12 | products: [ 13 | // Products define the executables and libraries a package produces, and make them visible to other packages. 14 | .library( 15 | name: "AxisSheet", 16 | targets: ["AxisSheet"]), 17 | ], 18 | dependencies: [ 19 | // Dependencies declare other packages that this package depends on. 20 | // .package(url: /* package url */, from: "1.0.0"), 21 | ], 22 | targets: [ 23 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 24 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 25 | .target( 26 | name: "AxisSheet", 27 | dependencies: []), 28 | .testTarget( 29 | name: "AxisSheetTests", 30 | dependencies: ["AxisSheet"]), 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **AxisSheet for SwiftUI** 2 | It is a library that handles the sheet view in 4 directions (.top, .bottom, .leading, .trailing) according to the axis mode. It supports iOS and macOS. 3 | 4 | [![Platforms](https://img.shields.io/badge/Platforms-iOS%20%7C%20macOS-blue?style=flat-square)](https://developer.apple.com/macOS) 5 | [![iOS](https://img.shields.io/badge/iOS-14.0-blue.svg)](https://developer.apple.com/iOS) 6 | [![macOS](https://img.shields.io/badge/macOS-11.0-blue.svg)](https://developer.apple.com/macOS) 7 | [![instagram](https://img.shields.io/badge/instagram-@dev.fabula-orange.svg?style=flat-square)](https://www.instagram.com/dev.fabula) 8 | [![SPM](https://img.shields.io/badge/SPM-compatible-red?style=flat-square)](https://developer.apple.com/documentation/swift_packages/package/) 9 | [![MIT](https://img.shields.io/badge/licenses-MIT-red.svg)](https://opensource.org/licenses/MIT) 10 | 11 | ## Screenshot 12 | |Example|Bottom|Trailing| 13 | |:---:|:---:|:---:| 14 | |||| 15 | 16 | https://user-images.githubusercontent.com/1617304/154444398-f0ff79c1-f482-4d56-8e0d-93587b49db4c.mp4 17 | 18 | ## Example 19 | [https://fabulaapp.page.link/228](https://fabulaapp.page.link/228) 20 | 21 | ## Usages 22 | 1. How to use the default header views. 23 | ```swift 24 | AxisSheet(isPresented: $isPresented, constants: constants) { 25 | Text("Content View") 26 | } 27 | 28 | /// or 29 | 30 | Text("Content View") 31 | .axisSheet(isPresented: $isPresented, constants: constants) 32 | ``` 33 | 2. How to use custom header views. 34 | ```swift 35 | AxisSheet(isPresented: $isPresented, constants: constants, header: { 36 | Rectangle().fill(Color.red.opacity(0.5)) 37 | .overlay(Text("Header")) 38 | }, content: { 39 | Text("Content View") 40 | }) 41 | 42 | /// or 43 | 44 | Text("Content View") 45 | .axisSheet(isPresented: $isPresented, constants: constants) { 46 | Rectangle().fill(Color.red.opacity(0.5)) 47 | .overlay(Text("Header")) 48 | } 49 | ``` 50 | ## Swift Package Manager 51 | The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. Once you have your Swift package set up, adding AxisSheet as a dependency is as easy as adding it to the dependencies value of your Package.swift. 52 | 53 | ```swift 54 | dependencies: [ 55 | .package(url: "https://github.com/jasudev/AxisSheet.git", .branch("main")) 56 | ] 57 | ``` 58 | 59 | ## Contact 60 | instagram : [@dev.fabula](https://www.instagram.com/dev.fabula) 61 | email : [dev.fabula@gmail.com](mailto:dev.fabula@gmail.com) 62 | 63 | ## License 64 | AxisSheet is available under the MIT license. See the [LICENSE](LICENSE) file for more info. 65 | -------------------------------------------------------------------------------- /Sources/AxisSheet/Private/Extensions/Animation+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Animation+Extensions.swift 3 | // AxisSheet 4 | // 5 | // Created by jasu on 2022/02/14. 6 | // Copyright (c) 2022 jasu All rights reserved. 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 furnished 13 | // to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 23 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | import SwiftUI 27 | 28 | extension Animation { 29 | 30 | /// Spring animation used by AxisSheet. 31 | static var axisSheetAnimation: Animation { 32 | self.spring(response: 0.24, dampingFraction: 1, blendDuration: 1) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/AxisSheet/Private/RoundCorner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RoundCorner.swift 3 | // AxisSheet 4 | // 5 | // Created by jasu on 2022/02/14. 6 | // Copyright (c) 2022 jasu All rights reserved. 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 furnished 13 | // to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 23 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | import SwiftUI 27 | 28 | /// A shape that rounds only certain edges. 29 | struct RoundCorner: InsettableShape { 30 | var tl: CGFloat = 0.0 31 | var tr: CGFloat = 0.0 32 | var bl: CGFloat = 0.0 33 | var br: CGFloat = 0.0 34 | var cornerRadius: CGFloat = 0 35 | 36 | func path(in rect: CGRect) -> Path { 37 | var path = Path() 38 | let w = rect.size.width 39 | let h = rect.size.height 40 | 41 | let tr = min(min(self.tr, h/2), w/2) 42 | let tl = min(min(self.tl, h/2), w/2) 43 | let bl = min(min(self.bl, h/2), w/2) 44 | let br = min(min(self.br, h/2), w/2) 45 | 46 | path.move(to: CGPoint(x: w / 2.0 + cornerRadius, y: cornerRadius)) 47 | path.addLine(to: CGPoint(x: w - tr + cornerRadius, y: cornerRadius)) 48 | path.addArc(center: CGPoint(x: w - tr + cornerRadius, y: tr + cornerRadius), 49 | radius: tr, 50 | startAngle: Angle(degrees: -90), 51 | endAngle: Angle(degrees: 0), 52 | clockwise: false) 53 | path.addLine(to: CGPoint(x: w + cornerRadius, y: h - br + cornerRadius)) 54 | path.addArc(center: CGPoint(x: w - br + cornerRadius, y: h - br + cornerRadius), 55 | radius: br, 56 | startAngle: Angle(degrees: 0), 57 | endAngle: Angle(degrees: 90), 58 | clockwise: false) 59 | path.addLine(to: CGPoint(x: bl + cornerRadius, y: h + cornerRadius)) 60 | path.addArc(center: CGPoint(x: bl + cornerRadius, y: h - bl + cornerRadius), 61 | radius: bl, startAngle: Angle(degrees: 90), 62 | endAngle: Angle(degrees: 180), 63 | clockwise: false) 64 | path.addLine(to: CGPoint(x: cornerRadius, y: tl + cornerRadius)) 65 | path.addArc(center: CGPoint(x: tl + cornerRadius, y: tl + cornerRadius), 66 | radius: tl, 67 | startAngle: Angle(degrees: 180), 68 | endAngle: Angle(degrees: 270), 69 | clockwise: false) 70 | path.closeSubpath() 71 | return path 72 | } 73 | 74 | func inset(by amount: CGFloat) -> some InsettableShape { 75 | var shape = self 76 | shape.cornerRadius += amount 77 | return shape 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Sources/AxisSheet/Public/AxisSheet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AxisSheet.swift 3 | // AxisSheet 4 | // 5 | // Created by jasu on 2022/02/14. 6 | // Copyright (c) 2022 jasu All rights reserved. 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 furnished 13 | // to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 23 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | import SwiftUI 27 | 28 | /// A component that handles the sheet view in 4 directions (.top, .bottom, .leading, .trailing) according to the `ASAxisMode`. 29 | /// 30 | /// How to use the default header views: 31 | /// 32 | /// AxisSheet(isPresented: $isPresented, constants: constants) { 33 | /// Text("Content View") 34 | /// } 35 | /// /// or 36 | /// Text("Content View") 37 | /// .axisSheet(isPresented: $isPresented, constants: constants) 38 | /// 39 | /// How to use custom header views: 40 | /// 41 | /// AxisSheet(isPresented: $isPresented, constants: constants, header: { 42 | /// Rectangle().fill(Color.red.opacity(0.5)) 43 | /// .overlay(Text("Header")) 44 | /// }, content: { 45 | /// Text("Content View") 46 | /// }) 47 | /// /// or 48 | /// Text("Content View") 49 | /// .axisSheet(isPresented: $isPresented, constants: constants) { 50 | /// Rectangle().fill(Color.red.opacity(0.5)) 51 | /// .overlay(Text("Header")) 52 | /// } 53 | /// 54 | public struct AxisSheet: View where Header: View, Content: View { 55 | 56 | /// Indicates whether a content is currently presented. 57 | @Binding var isPresented: Bool 58 | 59 | /// The component status information. 60 | var constants: ASConstant 61 | 62 | /// The content of the header. 63 | private var header: (() -> Header)? = nil 64 | 65 | /// A view builder that creates content. 66 | @ViewBuilder private var content: () -> Content 67 | 68 | /// The total translation from the start of the drag gesture to the current event of the drag gesture. 69 | @GestureState private var translation: CGFloat = 0 70 | 71 | /// A value to restrict close. 72 | private let limitGap: CGFloat = 30 73 | 74 | //MARK: - property 75 | private var dragGesture: some Gesture { 76 | return DragGesture().updating(self.$translation) { value, state, _ in 77 | let value = getTranslationValue(value) 78 | switch constants.axisMode { 79 | case .bottom, .trailing: if alpha == 0 && value > 0 { return } 80 | case .top, .leading: if alpha == 0 && value < 0 { return } 81 | } 82 | state = value 83 | } 84 | .onEnded { value in 85 | if isPresented { 86 | switch constants.axisMode { 87 | case .top, .leading: 88 | guard -getTranslationValue(value) > limitGap else { return } 89 | case .bottom, .trailing: 90 | guard getTranslationValue(value) > limitGap else { return } 91 | } 92 | } 93 | self.isPresented = getPresentedValue(value) 94 | } 95 | } 96 | 97 | /// The position value according to the gesture. 98 | private var offset: CGFloat { 99 | var value: CGFloat = 0 100 | if !isPresented { 101 | if constants.presentationMode == .minimize { 102 | value = constants.size 103 | }else { 104 | value = constants.size + constants.header.size 105 | } 106 | } 107 | switch constants.axisMode { 108 | case .top, .leading: return -max(value - self.translation, 0) 109 | case .bottom, .trailing: return max(value + self.translation, 0) 110 | } 111 | } 112 | 113 | /// Transparency value based on position value. 114 | private var alpha: CGFloat { 115 | var value = 1.0 - abs(offset) / (constants.size) 116 | value = max(value, 0.0) 117 | value = min(value, 1.0) 118 | return value 119 | } 120 | 121 | /// Returns a shape with rounded corners according to the AxisMode. 122 | private var cornerShape: some Shape { 123 | let radius = constants.header.cornerRadius 124 | switch constants.axisMode { 125 | case .top: return RoundCorner(bl: radius, br: radius) 126 | case .bottom: return RoundCorner(tl: radius, tr: radius) 127 | case .leading: return RoundCorner(tr: radius, br: radius) 128 | case .trailing: return RoundCorner(tl: radius, bl: radius) 129 | } 130 | } 131 | 132 | /// Header view. 133 | private var headerView: some View { 134 | let header = constants.header 135 | return ZStack { 136 | switch constants.axisMode { 137 | case .top, .bottom: 138 | ZStack { 139 | Rectangle() 140 | .fill(header.backgroundColor) 141 | if let header = self.header { 142 | header() 143 | }else { 144 | Capsule() 145 | .fill(header.color) 146 | .frame(width: header.longAxis, height: header.shortAxis) 147 | } 148 | } 149 | .frame(height: header.size) 150 | case .leading, .trailing: 151 | ZStack { 152 | Rectangle() 153 | .fill(header.backgroundColor) 154 | if let header = self.header { 155 | header() 156 | }else { 157 | Capsule() 158 | .fill(header.color) 159 | .frame(width: header.shortAxis, height: header.longAxis) 160 | } 161 | } 162 | .frame(width: constants.header.size) 163 | } 164 | } 165 | .clipShape(cornerShape) 166 | .shadow(color: Color.black.opacity(0.1), radius: 6, x: 0, y: 0) 167 | .highPriorityGesture(dragGesture) 168 | .opacity(constants.presentationMode == .minimize ? 1 : alpha == 0 ? 0 : 1) 169 | .onTapGesture { 170 | isPresented.toggle() 171 | } 172 | } 173 | 174 | /// Content view. 175 | private var contentView: some View { 176 | #if os(iOS) 177 | ZStack { 178 | Color.clear 179 | self.content() 180 | } 181 | .opacity(alpha) 182 | #else 183 | GeometryReader { proxy in 184 | ZStack { 185 | Color.clear 186 | self.content() 187 | } 188 | .disabled(alpha == 0) 189 | /// Handled as a contentShape due to a bug where the disabled modifier was not properly applied on macOS. 190 | .contentShape(Rectangle().size(CGSize(width: proxy.size.width, 191 | height: proxy.size.height * (alpha == 0 ? 0 : 1)))) 192 | } 193 | #endif 194 | } 195 | 196 | public var body: some View { 197 | let background = constants.background 198 | ZStack { 199 | background.color 200 | .opacity(background.disabled ? 0 : alpha) 201 | .edgesIgnoringSafeArea(.all) 202 | .animation(.linear(duration: 0.2), value: offset) 203 | .animation(.linear(duration: 0.2), value: background.disabled) 204 | .highPriorityGesture(dragGesture) 205 | .onTapGesture { 206 | isPresented = false 207 | } 208 | getContent() 209 | .animation(.axisSheetAnimation, value: isPresented) 210 | } 211 | .animation(.axisSheetAnimation, value: alpha) 212 | .clipped() 213 | } 214 | 215 | //MARK: - method 216 | /// Returns a content view according to the `ASAxisMode`. 217 | /// - Returns: A content view. 218 | private func getContent() -> some View { 219 | let contentSize = constants.size + constants.header.size 220 | return GeometryReader { proxy in 221 | switch constants.axisMode { 222 | case .top: 223 | VStack(spacing: 0) { 224 | self.contentView 225 | self.headerView 226 | } 227 | .frame(width: proxy.size.width, height: contentSize) 228 | .frame(height: proxy.size.height, alignment: .top) 229 | .offset(y: offset) 230 | case .bottom: 231 | VStack(spacing: 0) { 232 | self.headerView 233 | self.contentView 234 | } 235 | .frame(width: proxy.size.width, height: contentSize) 236 | .frame(height: proxy.size.height, alignment: .bottom) 237 | .offset(y: offset) 238 | case .leading: 239 | HStack(spacing: 0) { 240 | self.contentView 241 | self.headerView 242 | } 243 | .frame(width: contentSize, height: proxy.size.height) 244 | .frame(width: proxy.size.width, alignment: .leading) 245 | .offset(x: offset) 246 | case .trailing: 247 | HStack(spacing: 0) { 248 | self.headerView 249 | self.contentView 250 | } 251 | .frame(width: contentSize, height: proxy.size.height) 252 | .frame(width: proxy.size.width, alignment: .trailing) 253 | .offset(x: offset) 254 | } 255 | } 256 | } 257 | 258 | /// Returns the isPresented value according to the drag gesture. 259 | /// - Parameter value: DragGesture.Value. `CGFloat` 260 | /// - Returns: Whether the content is exposed. 261 | private func getPresentedValue(_ value: DragGesture.Value) -> Bool { 262 | switch constants.axisMode { 263 | case .top, .leading: return getTranslationValue(value) > 0 264 | case .bottom, .trailing: return getTranslationValue(value) < 0 265 | } 266 | } 267 | 268 | /// Returns the value of the gesture according to the `ASAxisMode`. 269 | /// - Parameter value: DragGesture.Value `CGFloat` 270 | /// - Returns: The horizontal and vertical values of the gesture according to the `ASAxisMode`. 271 | private func getTranslationValue(_ value: DragGesture.Value) -> CGFloat { 272 | switch constants.axisMode { 273 | case .top, .bottom: return value.translation.height 274 | case .leading, .trailing: return value.translation.width 275 | } 276 | } 277 | } 278 | 279 | public extension AxisSheet where Header == EmptyView, Content : View { 280 | 281 | /// Initializes `AxisSheet` 282 | /// - Parameters: 283 | /// - isPresented: Indicates whether a content is currently presented. 284 | /// - constants: The component status information. 285 | /// - content: A view builder that creates content. 286 | init(isPresented: Binding, constants: ASConstant = .init(), @ViewBuilder content: @escaping () -> Content) { 287 | _isPresented = isPresented 288 | self.constants = constants 289 | self.content = content 290 | } 291 | } 292 | 293 | public extension AxisSheet where Header : View, Content : View { 294 | 295 | /// Initializes `AxisSheet` 296 | /// - Parameters: 297 | /// - isPresented: Indicates whether a content is currently presented. 298 | /// - constants: The component status information. 299 | /// - header: The content of the header. 300 | /// - content: A view builder that creates content. 301 | init(isPresented: Binding, constants: ASConstant = .init(), @ViewBuilder header: @escaping () -> Header, @ViewBuilder content: @escaping () -> Content) { 302 | _isPresented = isPresented 303 | self.constants = constants 304 | self.header = header 305 | self.content = content 306 | } 307 | } 308 | 309 | struct AxisSheet_Previews: PreviewProvider { 310 | static var previews: some View { 311 | AxisSheet(isPresented: .constant(true)) { 312 | Text("AxisSheet") 313 | } 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /Sources/AxisSheet/Public/Constants/ASBackgroundConstant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ASBackgroundConstant.swift 3 | // AxisSheet 4 | // 5 | // Created by jasu on 2022/02/15. 6 | // Copyright (c) 2022 jasu All rights reserved. 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 furnished 13 | // to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 23 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | import SwiftUI 27 | 28 | /// The component background status information. 29 | public struct ASBackgroundConstant: Equatable { 30 | 31 | /// The translucent background color of the component. 32 | public var color: Color 33 | 34 | /// Disable the background. 35 | public var disabled: Bool 36 | 37 | /// Initializes `ASBackgroundConstant` 38 | /// - Parameters: 39 | /// - color: The translucent background color of the component. The default value is `.black.opacity(0.3)` 40 | /// - disabled: Disable the background. The default value is `false` 41 | public init(color: Color = .black.opacity(0.3), disabled: Bool = false) { 42 | self.color = color 43 | self.disabled = disabled 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Sources/AxisSheet/Public/Constants/ASConstant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ASConstant.swift 3 | // AxisSheet 4 | // 5 | // Created by jasu on 2022/02/14. 6 | // Copyright (c) 2022 jasu All rights reserved. 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 furnished 13 | // to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 23 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | import SwiftUI 27 | 28 | /// The axis mode of the component. 29 | public enum ASAxisMode { 30 | case top 31 | case bottom 32 | case leading 33 | case trailing 34 | } 35 | 36 | /// The mode of whether to expose the component when the isPresented value is false. 37 | public enum ASPresentationMode { 38 | case hide 39 | case minimize 40 | } 41 | 42 | /// The component status information. 43 | public struct ASConstant: Equatable { 44 | 45 | /// The axis mode of the component. 46 | public var axisMode: ASAxisMode 47 | 48 | /// The size of the content. 49 | public var size: CGFloat 50 | 51 | /// The mode of whether to expose the component when the isPresented value is false. 52 | public var presentationMode: ASPresentationMode 53 | 54 | /// The header status information. 55 | public var header: ASHeaderConstant 56 | 57 | /// The component background status information. 58 | public var background: ASBackgroundConstant 59 | 60 | /// Initializes `ASConstant` 61 | /// - Parameters: 62 | /// - axisMode: The axis mode of the component. The default value is `.bottom` 63 | /// - size: The size of the content. The default value is `200` 64 | /// - presentationMode: The mode of whether to expose the component when the isPresented value is false. The default value is `.minimize` 65 | /// - header: The header status information. 66 | /// - background: The component background status information. 67 | public init(axisMode: ASAxisMode = .bottom, 68 | size: CGFloat = 200, 69 | presentationMode: ASPresentationMode = .minimize, 70 | header: ASHeaderConstant = .init(), 71 | background: ASBackgroundConstant = .init()) { 72 | self.axisMode = axisMode 73 | self.size = size 74 | self.presentationMode = presentationMode 75 | self.header = header 76 | self.background = background 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Sources/AxisSheet/Public/Constants/ASHeaderConstant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ASHeaderConstant.swift 3 | // AxisSheet 4 | // 5 | // Created by jasu on 2022/02/14. 6 | // Copyright (c) 2022 jasu All rights reserved. 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 furnished 13 | // to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 23 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | import SwiftUI 27 | 28 | /// The header status information. 29 | public struct ASHeaderConstant: Equatable { 30 | 31 | /// The size of the header. 32 | public var size: CGFloat 33 | 34 | /// The short axis size of the handle icon. 35 | public var shortAxis: CGFloat 36 | 37 | /// The long axis size of the handle icon. 38 | public var longAxis: CGFloat 39 | 40 | /// The round value of both corners. 41 | public var cornerRadius: CGFloat 42 | 43 | /// The color of the handle icon. 44 | public var color: Color 45 | 46 | /// The background color of the header. 47 | public var backgroundColor: Color 48 | 49 | 50 | /// Initializes `ASHeaderConstant` 51 | /// - Parameters: 52 | /// - size: The size of the header. The default value is `42` 53 | /// - shortAxis: The short axis size of the handle icon. The default value is `4` 54 | /// - longAxis: The long axis size of the handle icon. The default value is `36` 55 | /// - cornerRadius: The round value of both corners. The default value is `21` 56 | /// - color: The color of the handle icon. The default value is `.accentColor` 57 | /// - backgroundColor: The background color of the header. The default value is `.black.opacity(0.8)` 58 | public init(size: CGFloat = 42, 59 | shortAxis: CGFloat = 4, 60 | longAxis: CGFloat = 36, 61 | cornerRadius: CGFloat = 21, 62 | color: Color = .accentColor, 63 | backgroundColor: Color = .black.opacity(0.8)) { 64 | self.size = size 65 | self.shortAxis = shortAxis 66 | self.longAxis = longAxis 67 | self.cornerRadius = cornerRadius 68 | self.color = color 69 | self.backgroundColor = backgroundColor 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Sources/AxisSheet/Public/Extensions/View+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // View+Extensions.swift 3 | // AxisSheet 4 | // 5 | // Created by jasu on 2022/02/17. 6 | // Copyright (c) 2022 jasu All rights reserved. 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 furnished 13 | // to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 19 | // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 23 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | import SwiftUI 27 | 28 | public extension View { 29 | 30 | func axisSheet(isPresented: Binding, 31 | constants: ASConstant = .init()) -> some View { 32 | AxisSheet(isPresented: isPresented, constants: constants) { 33 | self 34 | } 35 | } 36 | 37 | func axisSheet(isPresented: Binding, 38 | constants: ASConstant = .init(), 39 | header: @escaping () -> Header) -> some View { 40 | AxisSheet(isPresented: isPresented, constants: constants, header: header) { 41 | self 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tests/AxisSheetTests/AxisSheetTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import AxisSheet 3 | 4 | final class AxisSheetTests: XCTestCase { 5 | func testExample() throws { 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(AxisSheet().text, "Hello, World!") 10 | } 11 | } 12 | --------------------------------------------------------------------------------