├── .gitignore ├── AFViewHelper.podspec ├── LICENSE ├── README.md ├── Screenshot.png ├── Sources ├── Info-iOS.plist ├── Info-tvOS.plist ├── InspectableButton.swift ├── InspectableView.swift ├── ViewAnimation.swift ├── ViewAutoLayout.swift ├── ViewControllerAutoLayout.swift ├── ViewEffects.swift └── ViewHelper.h ├── ViewHelper.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ ├── ViewHelper iOS.xcscheme │ └── ViewHelper tvOS.xcscheme ├── ViewHelperDemo iOS ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── Main.storyboard └── ViewController.swift └── ViewHelperDemo tvOS ├── AppDelegate.swift ├── Assets.xcassets ├── App Icon & Top Shelf Image.brandassets │ ├── App Icon - Large.imagestack │ │ ├── Back.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Front.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ └── Middle.imagestacklayer │ │ │ ├── Content.imageset │ │ │ └── Contents.json │ │ │ └── Contents.json │ ├── App Icon - Small.imagestack │ │ ├── Back.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Front.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ └── Middle.imagestacklayer │ │ │ ├── Content.imageset │ │ │ └── Contents.json │ │ │ └── Contents.json │ ├── Contents.json │ ├── Top Shelf Image Wide.imageset │ │ └── Contents.json │ └── Top Shelf Image.imageset │ │ └── Contents.json ├── Contents.json └── LaunchImage.launchimage │ └── Contents.json ├── Base.lproj └── Main.storyboard ├── Info.plist ├── TableViewController.swift └── ViewController.swift /.gitignore: -------------------------------------------------------------------------------- 1 | <<<<<<< HEAD 2 | .DS_Store 3 | *.swp 4 | *~.nib 5 | 6 | build/ 7 | 8 | *.pbxuser 9 | *.perspective 10 | *.perspectivev3 11 | 12 | *.mode1v3 13 | *.mode2v3 14 | 15 | project.xcworkspace/ 16 | xcuserdata 17 | ======= 18 | # CocoaPods 19 | # 20 | # We recommend against adding the Pods directory to your .gitignore. However 21 | # you should judge for yourself, the pros and cons are mentioned at: 22 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 23 | # 24 | # Pods/ 25 | 26 | >>>>>>> 920e0fd8315bafeb029a22d2ea768b71317fabcb 27 | -------------------------------------------------------------------------------- /AFViewHelper.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'AFViewHelper' 3 | s.version = '4.2.4' 4 | s.license = 'MIT' 5 | s.summary = 'Autolayout and Animation UIVIew Extension for Swift 3.0.' 6 | s.homepage = 'https://github.com/melvitax/ViewHelper' 7 | s.author = { 'Melvin Rivera' => 'melvitax@gmail.com' } 8 | s.source = { :git => 'https://github.com/melvitax/ViewHelper.git', :tag => s.version.to_s } 9 | s.description = <<-DESC 10 | Autolayout and Animation UIVIew Extension for Swift 3.0. Includes InspectableView for setting basic view attributes. 11 | DESC 12 | s.social_media_url = 'https://twitter.com/melvitax' 13 | s.framework = 'QuartzCore' 14 | 15 | s.platforms = { :ios => '9.0', :tvos => '9.0' } 16 | s.ios.deployment_target = "9.0" 17 | s.tvos.deployment_target = "10.0" 18 | 19 | s.xcconfig = { 'SWIFT_VERSION' => '3.0' } 20 | 21 | s.source_files = "Sources/**/*.{h,swift}" 22 | 23 | end 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Melvin Rivera 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ViewHelper 2 | 3 | [![Version](https://img.shields.io/cocoapods/v/AFViewHelper.svg?style=flat)](http://cocoapods.org/pods/AFViewHelper) 4 | [![License](https://img.shields.io/cocoapods/l/AFViewHelper.svg?style=flat)](http://cocoapods.org/pods/AFViewHelper) 5 | [![Platform](https://img.shields.io/cocoapods/p/AFViewHelper.svg?style=flat)](http://cocoapods.org/pods/AFViewHelper) 6 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 7 | 8 | 9 | Autolayout and View Animation Helper for Swift 3.0. 10 | Mimimum requirements: Swift 3 and IOS 9 11 | Supported: IOS and Apple TV 12 | 13 | 14 | ![Sample Project Screenshot](https://raw.githubusercontent.com/melvitax/ViewHelper/master/Screenshot.png?raw=true "Sample Project Screenshot") 15 | 16 | 17 | ## Animations 18 | 19 | ```swift 20 | // Required 21 | view.animate(.Shake, curve: .EaseInOutBack) 22 | // With optionals 23 | view.animate(.Shake, curve: .EaseInOutBack, duration: 0.8, delay: 0, force: 1, damping: 0.7,velocity: 1, fromRotation: 0, fromScale: 1.5, fromX: 0, fromY: 0) 24 | ``` 25 | 26 | ## Auto Layout 27 | 28 | ```swift 29 | let box = UIView(autoLayout:true) 30 | view.addSubview(box) 31 | box.backgroundColor = UIColor.redColor() 32 | box.width(100) 33 | box.height(100) 34 | box.center(to: view) 35 | view.layoutIfNeeded() 36 | ``` 37 | 38 | ### Chainable functions 39 | 40 | 100 pixel view pinned to the center of another view 41 | 42 | ```swift 43 | view.width(100).height(100).center(to: view) 44 | ``` 45 | 46 | ### Compression & Hugging 47 | 48 | ```swift 49 | view.horizontalCompressionPriority(UILayoutPriorityDefaultHigh) 50 | view.horizontalHuggingPriority(UILayoutPriorityDefaultLow) 51 | ``` 52 | 53 | ### NSLayoutConstraints 54 | 55 | You can have access to the NSLayoutConstraints by using pin() or applyAttribute. 56 | 57 | ```swift 58 | // Pinning to an item 59 | let widthConstraint = view.pin(.Width, to: view, attribute: .Height, constant: 0, multiplier: 0.5, relation: .LessThanOrEqual) 60 | ``` 61 | 62 | ```swift 63 | // Applying an attribute 64 | let widthConstraint = view.applyAttribute(.Width, constant: 100, multiplier: 0.5, relation: .Equal) 65 | ``` 66 | 67 | ## UIView Extension 68 | 69 | ### Prepping for Auto Layout 70 | 71 | If a view is already in place with frames, prepForAutoLayout() will remove it from view, enable Auto Layout and place back in view. 72 | 73 | ```swift 74 | view.prepForAutoLayout() 75 | ``` 76 | 77 | ### Prepping for Animation 78 | 79 | If a view uses auto layout but you need to animate it using frames, prepForAnimation() will remove from view, disable auto layout and place back in view. 80 | 81 | ```swift 82 | view.prepForAnimation() 83 | ``` 84 | 85 | ### Instantiate 86 | 87 | Instantiates a new UIView with Auto Layout 88 | 89 | ```swift 90 | convenience init(autoLayout: Bool = true) 91 | ``` 92 | 93 | ### Position 94 | 95 | #### Origin 96 | 97 | Returns the frame's origin 98 | 99 | ```swift 100 | origin() -> CGPoint 101 | ``` 102 | 103 | Pins the frame's top and left sides using Auto Layout or frames 104 | 105 | ```swift 106 | origin(constant: CGPoint) -> UIView 107 | ``` 108 | Pins left and top sides to another view using Auto Layout 109 | 110 | ```swift 111 | origin(to to:AnyObject, constant: CGPoint = CGPoint(x: 0, y: 0), multiplier:CGFloat = 1) -> UIView 112 | ``` 113 | #### Left 114 | 115 | Returns the min x point 116 | 117 | ```swift 118 | left() -> CGFloat 119 | ``` 120 | 121 | Pins the left side using Auto Layout or frames 122 | 123 | ```swift 124 | left(constant: CGFloat) -> UIView 125 | ``` 126 | 127 | Pins left side to another view using Auto Layout 128 | 129 | ```swift 130 | left(to to:AnyObject, attribute: NSLayoutAttribute = .Left, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 131 | ``` 132 | 133 | #### Leading 134 | 135 | Returns the leading side value 136 | 137 | ```swift 138 | leading() -> CGFloat 139 | ``` 140 | 141 | Pins the leading side using Auto Layout or frames 142 | 143 | ```swift 144 | leading(constant: CGFloat) -> UIView 145 | ``` 146 | 147 | Pins the leading side to another view using Auto Layout 148 | 149 | ```swift 150 | leading(to to:AnyObject, attribute: NSLayoutAttribute = .Leading, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 151 | ``` 152 | #### Right 153 | 154 | Returns the max x point 155 | 156 | ```swift 157 | right() -> CGFloat 158 | ``` 159 | 160 | Pins the right side using Auto Layout or frames 161 | 162 | ```swift 163 | right(constant: CGFloat) -> UIView 164 | ``` 165 | 166 | Pins the right side to another view using Auto Layout 167 | 168 | ```swift 169 | right(to to:AnyObject, attribute: NSLayoutAttribute = .Right, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 170 | ``` 171 | #### Trailing 172 | 173 | Returns the trailing side value 174 | 175 | ```swift 176 | trailing() -> CGFloat 177 | ``` 178 | 179 | Pins the trailing side using Auto Layout or frames 180 | 181 | ```swift 182 | trailing(constant: CGFloat) -> UIView 183 | ``` 184 | 185 | Pins the trailing side to another view using Auto Layout 186 | 187 | ```swift 188 | trailing(to to:AnyObject, attribute: NSLayoutAttribute = .Trailing, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 189 | ``` 190 | 191 | #### Top 192 | 193 | Returns the top side value 194 | 195 | ```swift 196 | top() -> CGFloat 197 | ``` 198 | 199 | Pins the top side using Auto Layout or frames 200 | 201 | ```swift 202 | top(constant: CGFloat) -> UIView 203 | ``` 204 | 205 | Pins the trailing side to another view using Auto Layout 206 | 207 | ```swift 208 | top(to to:AnyObject, attribute: NSLayoutAttribute = .Top, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 209 | ``` 210 | 211 | #### Bottom 212 | 213 | Returns the bottom side value 214 | 215 | ```swift 216 | bottom() -> CGFloat 217 | ``` 218 | 219 | Pins the bottom side using Auto Layout or frames 220 | 221 | ```swift 222 | bottom(constant: CGFloat) -> UIView 223 | ``` 224 | 225 | Pins the bottom side to another view using Auto Layout 226 | 227 | ```swift 228 | bottom(to to:AnyObject, attribute: NSLayoutAttribute = .Bottom, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 229 | ``` 230 | 231 | #### Center 232 | 233 | Pins the center to it's superview using Auto Layout or frames 234 | 235 | ```swift 236 | center(constant: CGPoint = CGPoint(x: 0, y: 0)) -> UIView 237 | ``` 238 | 239 | Pins the center point to another view using Auto Layout 240 | 241 | ```swift 242 | center(to to:AnyObject, constant:CGSize = CGSize(width: 0, height: 0), multiplier:CGFloat = 1) -> UIView 243 | ``` 244 | 245 | #### Center X 246 | 247 | Returns the center X 248 | 249 | ```swift 250 | centerX() -> CGFloat 251 | ``` 252 | 253 | Pins the center X using Auto Layout or frames 254 | 255 | ```swift 256 | centerX(constant: CGFloat = 0) -> UIView 257 | ``` 258 | 259 | Pins the center X to another view using Auto Layout 260 | 261 | ```swift 262 | centerX(to to:AnyObject, attribute: NSLayoutAttribute = .CenterX, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 263 | ``` 264 | 265 | #### Center Y 266 | 267 | Returns the center Y 268 | 269 | ```swift 270 | centerY() -> CGFloat 271 | ``` 272 | 273 | Pins the center Y using Auto Layout or frames 274 | 275 | ```swift 276 | centerY(constant: CGFloat = 0) -> UIView 277 | ``` 278 | 279 | Pins the center Y to another view using Auto Layout 280 | 281 | ```swift 282 | centerY(to to:AnyObject, attribute: NSLayoutAttribute = .CenterY, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 283 | ``` 284 | 285 | ### Compression and Hugging Priority 286 | 287 | #### Compression Priority 288 | 289 | Returns the Compression Resistance Priority for Horizontal Axis using Auto Layout 290 | 291 | ```swift 292 | horizontalCompressionPriority() -> UILayoutPriority 293 | ``` 294 | 295 | Sets the Compression Resistance Priority for Horizontal Axis using Auto Layout 296 | 297 | ```swift 298 | horizontalCompressionPriority(priority: UILayoutPriority) -> UIView 299 | ``` 300 | 301 | Returns the Compression Resistance Priority for Vertical Axis using Auto Layout 302 | 303 | ```swift 304 | verticalCompressionPriority() -> UILayoutPriority 305 | ``` 306 | 307 | Sets the Compression Resistance Priority for Vertical Axis using Auto Layout 308 | 309 | ```swift 310 | verticalCompressionPriority(priority: UILayoutPriority) -> UIView 311 | ``` 312 | 313 | #### Hugging Priority 314 | 315 | Returns the Content Hugging Priority for Horizontal Axis using Auto Layout 316 | 317 | ```swift 318 | func horizontalHuggingPriority() -> UILayoutPriority 319 | ``` 320 | 321 | Sets the Content Hugging Priority for Horizontal Axis using Auto Layout 322 | 323 | ```swift 324 | horizontalHuggingPriority(priority: UILayoutPriority) -> UIView 325 | ``` 326 | 327 | Returns the Content Hugging Priority for Vertical Axis using Auto Layout 328 | 329 | ```swift 330 | verticalHuggingPriority() -> UILayoutPriority 331 | ``` 332 | 333 | Sets the Content Hugging Priority for Vertical Axis using Auto Layout 334 | 335 | ```swift 336 | verticalHuggingPriority(priority: UILayoutPriority) -> UIView 337 | ``` 338 | 339 | ### Size 340 | 341 | #### Size 342 | 343 | Returns the frame size 344 | 345 | ```swift 346 | size() -> CGSize 347 | ``` 348 | 349 | Sets the frame size using Auto Layout or frames 350 | 351 | ```swift 352 | size(constant: CGSize) -> UIView 353 | ``` 354 | 355 | Pins the size to another view using Auto Layout 356 | 357 | ```swift 358 | size(to to:AnyObject, constant: CGSize = CGSize(width: 0, height: 0), multiplier:CGFloat = 1) -> UIView 359 | ``` 360 | 361 | #### Width 362 | 363 | Returns the frame width 364 | 365 | ```swift 366 | width() -> CGFloat 367 | ``` 368 | 369 | Sets the frame width using Auto Layout or frames 370 | 371 | ```swift 372 | width(constant: CGFloat) -> UIView 373 | ``` 374 | 375 | Pins the width to another view using Auto Layout 376 | 377 | ```swift 378 | width(to to:AnyObject, attribute: NSLayoutAttribute = .Width, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 379 | ``` 380 | 381 | #### Height 382 | 383 | Returns the frame height 384 | 385 | ```swift 386 | height() -> CGFloat 387 | ``` 388 | 389 | Sets the frame height using Auto Layout or frames 390 | 391 | ```swift 392 | eight(constant: CGFloat) -> UIView 393 | ``` 394 | 395 | Pins the height to another view using Auto Layout 396 | 397 | ```swift 398 | height(to to:AnyObject, attribute: NSLayoutAttribute = .Height, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView 399 | ``` 400 | 401 | #### Minimum Size 402 | 403 | Returns the minimum size using Auto Layout 404 | 405 | ```swift 406 | minSize() -> CGSize? 407 | ``` 408 | 409 | Sets the minimum size using Auto Layout 410 | 411 | ```swift 412 | minSize(constant:CGSize) -> UIView 413 | ``` 414 | 415 | Pins the minimum size to another view using Auto Layout 416 | 417 | ```swift 418 | minSize(to to:AnyObject, constant:CGSize = CGSize(width: 0, height: 0), multiplier:CGFloat = 1) 419 | ``` 420 | 421 | #### Minimum Width 422 | 423 | Returns the minimum width using Auto Layout 424 | 425 | ```swift 426 | minWidth() -> CGFloat? 427 | ``` 428 | 429 | Sets the minimum width using Auto Layout 430 | 431 | ```swift 432 | minWidth(constant:CGFloat) -> UIView 433 | ``` 434 | 435 | Pins the minimum width to another view using Auto Layout 436 | 437 | ```swift 438 | minWidth(to to:AnyObject, attribute: NSLayoutAttribute = .Width, constant:CGFloat = 0, multiplier:CGFloat = 1) -> UIView 439 | ``` 440 | 441 | #### Minimum Height 442 | 443 | Returns the minimum height using Auto Layout 444 | 445 | ```swift 446 | minHeight() -> CGFloat? 447 | ``` 448 | 449 | Sets the minimum height using Auto Layout 450 | 451 | ```swift 452 | minHeight(constant:CGFloat) -> UIView 453 | ``` 454 | 455 | Pins the minimum height to another view using Auto Layout 456 | 457 | ```swift 458 | minHeight(to to:AnyObject, attribute: NSLayoutAttribute = .Height, constant:CGFloat = 0, multiplier:CGFloat = 1) -> UIView 459 | ``` 460 | 461 | #### Maximum Size 462 | 463 | Returns the maximun size using Auto Layout 464 | 465 | ```swift 466 | maxSize() -> CGSize? 467 | ``` 468 | 469 | Sets the maximun size using Auto Layout 470 | 471 | ```swift 472 | maxSize(constant:CGSize) -> UIView 473 | ``` 474 | 475 | Pins the maximun size to another view using Auto Layout 476 | 477 | ```swift 478 | maxSize(to to:AnyObject, constant:CGSize = CGSize(width: 0, height: 0), multiplier:CGFloat = 1) -> UIView 479 | ``` 480 | 481 | #### Maximum Width 482 | 483 | Returns the maximun width using Auto Layout 484 | 485 | ```swift 486 | maxWidth() -> CGFloat? 487 | ``` 488 | 489 | Sets the maximun width using Auto Layout 490 | 491 | ```swift 492 | maxWidth(constant:CGFloat) -> UIView 493 | ``` 494 | 495 | Pins the maximun width to another view using Auto Layout 496 | 497 | ```swift 498 | maxWidth(to to:AnyObject, attribute: NSLayoutAttribute = .Width, constant:CGFloat = 0, multiplier:CGFloat = 1) -> UIView 499 | ``` 500 | 501 | #### Maximum Height 502 | 503 | Returns the maximun height using Auto Layout 504 | 505 | ```swift 506 | maxHeight() -> CGFloat? 507 | ``` 508 | 509 | Sets the maximun height using Auto Layout 510 | 511 | ```swift 512 | maxHeight(constant:CGFloat) -> UIView 513 | ``` 514 | 515 | Pins the maximun height to another view using Auto Layout 516 | 517 | ```swift 518 | maxHeight(to to:AnyObject, attribute: NSLayoutAttribute = .Height, constant:CGFloat = 0, multiplier:CGFloat = 1) -> UIView 519 | ``` 520 | 521 | ### Smallest and Largest Size 522 | 523 | Returns the length of the smallest side 524 | 525 | ```swift 526 | smallestSideLength() -> CGFloat 527 | ``` 528 | 529 | Returns the length of the largest side 530 | 531 | ```swift 532 | largestSideLength() -> CGFloat 533 | ``` 534 | 535 | ### AutoLayout state 536 | 537 | Prepares the view for a frame based animation by removing the view, enabling translatesAutoresizingMaskIntoConstraints and re-adding the view to it's superview 538 | 539 | ```swift 540 | prepForAnimation() 541 | ``` 542 | 543 | Prepares the view for Auto Layout by removing the view, disabling translatesAutoresizingMaskIntoConstraints and re-adding the view to it's superview 544 | 545 | ```swift 546 | prepForAutoLayout() 547 | ``` 548 | 549 | ### Pin and Apply 550 | 551 | Pins an attribute to another view 552 | 553 | ```swift 554 | pin(pinAttribute:NSLayoutAttribute, to:AnyObject? = nil, attribute:NSLayoutAttribute, constant:CGFloat = 0, multiplier:CGFloat = 1, relation:NSLayoutRelation = .Equal) -> NSLayoutConstraint? 555 | ``` 556 | 557 | Applies an attribute to the view 558 | 559 | ```swift 560 | applyAttribute(attribute:NSLayoutAttribute, constant:CGFloat = 0, multiplier: CGFloat = 1, relation:NSLayoutRelation = .Equal) -> NSLayoutConstraint 561 | ``` 562 | 563 | ### Removing Constraints 564 | 565 | Removes all attached constraints recursevely 566 | 567 | ```swift 568 | removeAttachedConstraintsRecursevely() -> UIView 569 | ``` 570 | 571 | Removes a constraint recursevely 572 | 573 | ```swift 574 | removeConstraintRecursevely(constraint:NSLayoutConstraint) -> UIView 575 | ``` 576 | 577 | ### Direction 578 | 579 | Returns true if layout direction is left to right 580 | 581 | ```swift 582 | layoutDirectionIsLeftToRight() -> Bool 583 | ``` 584 | 585 | ## UIView Effects Extension 586 | 587 | ### Border 588 | 589 | The layer border color 590 | 591 | ```swift 592 | var borderColor: UIColor 593 | ``` 594 | 595 | The layer border width 596 | 597 | ```swift 598 | var borderWidth: CGFloat 599 | ``` 600 | 601 | Sets layer border with a dash pattern 602 | 603 | ```swift 604 | borderWithDashPattern(lineDashPattern: [Int], borderWidth: CGFloat, borderColor: UIColor, cornerRadius: CGFloat?) -> UIView 605 | ``` 606 | 607 | ### Rounded Corners 608 | 609 | The layer corner radius 610 | 611 | ```swift 612 | var cornerRadius: CGFloat 613 | ``` 614 | 615 | Creates a circle by rounding the corners to half the size of the width, sets border color and width 616 | 617 | ```swift 618 | roundCornersToCircle(borderColor: UIColor?, borderWidth: CGFloat?) -> UIView 619 | ``` 620 | 621 | Creates a circle by rounding the corners to hald the size of the width 622 | 623 | ```swift 624 | roundCorners(cornerRadius: CGFloat, borderColor: UIColor?, borderWidth: CGFloat?) -> UIView 625 | ``` 626 | 627 | ### Shadow 628 | 629 | The shadow color of the layer 630 | 631 | ```swift 632 | var shadowColor: UIColor 633 | ``` 634 | 635 | The shadow offset of the layer 636 | 637 | ```swift 638 | var shadowOffset:CGSize 639 | ``` 640 | 641 | The shadow opacity of the layer 642 | 643 | ```swift 644 | var shadowOpacity:Float 645 | ``` 646 | 647 | The shadow radius of the layer 648 | 649 | ```swift 650 | var shadowRadius:CGFloat 651 | ``` 652 | 653 | Sets shadow of the layer including the color, offset, radius, opacity and mask. 654 | 655 | ```swift 656 | shadow(color: UIColor = UIColor.blackColor(), offset: CGSize = CGSize(width: 0, height: 0), radius: CGFloat = 6, opacity: Float = 1, isMasked: Bool = false) -> UIView 657 | ``` 658 | 659 | ### Gradient 660 | 661 | Sets a gradient color layer 662 | 663 | ```swift 664 | setGradient(colors: [UIColor], isHorizontal:Bool = false) -> UIView 665 | ``` 666 | 667 | Animates colors of a gradient layer 668 | 669 | ```swift 670 | animateGradientToColors(colors: [UIColor], duration: CFTimeInterval = 3) -> UIView 671 | ``` 672 | 673 | Sets a gradient layer mask 674 | 675 | ```swift 676 | setGradientMask(alphas:[CGFloat], isHorizontal:Bool = false) -> UIView 677 | ``` 678 | 679 | 680 | ## UIViewController Extension 681 | 682 | ### Direction 683 | 684 | Returns true if layout direction is left to right 685 | 686 | ```swift 687 | layoutDirectionIsLeftToRight() -> Bool 688 | ``` 689 | 690 | Returns true if horizontal size class is compact 691 | 692 | ```swift 693 | horizontalSizeClassIsCompact() -> Bool 694 | ``` 695 | 696 | Returns true if vertical size class is compact 697 | 698 | ```swift 699 | verticalSizeClassIsCompact() -> Bool 700 | ``` 701 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melvitax/ViewHelper/9c68f699d19effc0b9c005d2c7d389d0769cea2e/Screenshot.png -------------------------------------------------------------------------------- /Sources/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sources/Info-tvOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sources/InspectableButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InspectableButton.swift 3 | // ViewHelper: Version 4.2.4 4 | // Created by Melvin Rivera on 6/28/16. 5 | // https://github.com/melvitax/ViewHelper 6 | // 7 | 8 | import Foundation 9 | import Foundation 10 | import UIKit 11 | import QuartzCore 12 | 13 | @IBDesignable open class InspectableButton : UIButton { 14 | 15 | 16 | // MARK: Border 17 | 18 | /** 19 | The layer border color 20 | */ 21 | @IBInspectable override public var borderColor: UIColor { 22 | get { 23 | return layer.borderColor == nil ? UIColor.clear : UIColor(cgColor: layer.borderColor!) 24 | } 25 | set { 26 | layer.borderColor = newValue.cgColor 27 | } 28 | } 29 | 30 | /** 31 | The layer border width 32 | */ 33 | @IBInspectable override public var borderWidth: CGFloat { 34 | get { 35 | return layer.borderWidth 36 | } 37 | set { 38 | layer.borderWidth = newValue 39 | } 40 | } 41 | 42 | 43 | // MARK: Corner Radius 44 | 45 | /** 46 | The layer corner radius 47 | */ 48 | @IBInspectable override public var cornerRadius: CGFloat { 49 | get { 50 | return layer.cornerRadius 51 | } 52 | set { 53 | layer.cornerRadius = newValue 54 | layer.masksToBounds = newValue > 0 55 | setupView() 56 | } 57 | } 58 | 59 | 60 | // MARK: Shadow 61 | 62 | /** 63 | The shadow color of the layer 64 | */ 65 | @IBInspectable override public var shadowColor: UIColor { 66 | get { 67 | return layer.shadowColor == nil ? UIColor.clear : UIColor(cgColor: layer.shadowColor!) 68 | } 69 | set { 70 | layer.shadowColor = newValue.cgColor 71 | } 72 | } 73 | 74 | 75 | /** 76 | The shadow offset of the layer 77 | */ 78 | @IBInspectable override public var shadowOffset:CGSize { 79 | get { 80 | return layer.shadowOffset 81 | } 82 | set { 83 | layer.shadowOffset = newValue 84 | } 85 | } 86 | 87 | /** 88 | The shadow opacity of the layer 89 | 90 | - Returns: Float 91 | */ 92 | @IBInspectable override public var shadowOpacity:Float { 93 | get { 94 | return layer.shadowOpacity 95 | } 96 | set { 97 | layer.shadowOpacity = newValue 98 | } 99 | } 100 | 101 | /** 102 | The shadow radius of the layer 103 | 104 | - Returns: CGFloat 105 | */ 106 | @IBInspectable override public var shadowRadius:CGFloat { 107 | get { 108 | return layer.shadowRadius 109 | } 110 | set { 111 | layer.shadowRadius = newValue 112 | } 113 | } 114 | 115 | // MARK: Inspectable properties 116 | 117 | @IBInspectable var startColor: UIColor? { 118 | didSet{ 119 | setupView() 120 | } 121 | } 122 | 123 | @IBInspectable var endColor: UIColor? { 124 | didSet{ 125 | setupView() 126 | } 127 | } 128 | 129 | @IBInspectable var isHorizontal: Bool = false { 130 | didSet{ 131 | setupView() 132 | } 133 | } 134 | 135 | 136 | // MARK: Internal functions 137 | 138 | fileprivate func setupView(){ 139 | guard (startColor != nil) && (endColor != nil) else { 140 | return 141 | } 142 | let colors = [startColor!.cgColor, endColor!.cgColor] 143 | gradientLayer.colors = colors 144 | gradientLayer.cornerRadius = cornerRadius 145 | if (isHorizontal){ 146 | gradientLayer.endPoint = CGPoint(x: 1, y: 0) 147 | } else { 148 | gradientLayer.endPoint = CGPoint(x: 0, y: 1) 149 | } 150 | self.setNeedsDisplay() 151 | } 152 | 153 | // Helper to return the main layer as CAGradientLayer 154 | var gradientLayer: CAGradientLayer { 155 | return layer as! CAGradientLayer 156 | } 157 | 158 | 159 | // MARK: Overrides ****************************************** 160 | 161 | override open class var layerClass:AnyClass{ 162 | return CAGradientLayer.self 163 | } 164 | 165 | override init(frame: CGRect) { 166 | super.init(frame: frame) 167 | setupView() 168 | } 169 | 170 | required public init(coder aDecoder: NSCoder) { 171 | super.init(coder: aDecoder)! 172 | setupView() 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /Sources/InspectableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InspectableView.swift 3 | // ViewHelper: Version 4.2.4 4 | // Created by Melvin Rivera on 7/24/14. 5 | // https://github.com/melvitax/ViewHelper 6 | // 7 | 8 | 9 | import Foundation 10 | import UIKit 11 | import QuartzCore 12 | 13 | @IBDesignable open class InspectableView :UIView { 14 | 15 | 16 | // MARK: Border 17 | 18 | /** 19 | The layer border color 20 | */ 21 | @IBInspectable override public var borderColor: UIColor { 22 | get { 23 | return layer.borderColor == nil ? UIColor.clear : UIColor(cgColor: layer.borderColor!) 24 | } 25 | set { 26 | layer.borderColor = newValue.cgColor 27 | } 28 | } 29 | 30 | /** 31 | The layer border width 32 | */ 33 | @IBInspectable override public var borderWidth: CGFloat { 34 | get { 35 | return layer.borderWidth 36 | } 37 | set { 38 | layer.borderWidth = newValue 39 | } 40 | } 41 | 42 | 43 | // MARK: Corner Radius 44 | 45 | /** 46 | The layer corner radius 47 | */ 48 | @IBInspectable override public var cornerRadius: CGFloat { 49 | get { 50 | return layer.cornerRadius 51 | } 52 | set { 53 | layer.cornerRadius = newValue 54 | layer.masksToBounds = newValue > 0 55 | setupView() 56 | } 57 | } 58 | 59 | 60 | // MARK: Shadow 61 | 62 | /** 63 | The shadow color of the layer 64 | */ 65 | @IBInspectable override public var shadowColor: UIColor { 66 | get { 67 | return layer.shadowColor == nil ? UIColor.clear : UIColor(cgColor: layer.shadowColor!) 68 | } 69 | set { 70 | layer.shadowColor = newValue.cgColor 71 | } 72 | } 73 | 74 | 75 | /** 76 | The shadow offset of the layer 77 | */ 78 | @IBInspectable override public var shadowOffset:CGSize { 79 | get { 80 | return layer.shadowOffset 81 | } 82 | set { 83 | layer.shadowOffset = newValue 84 | } 85 | } 86 | 87 | /** 88 | The shadow opacity of the layer 89 | 90 | - Returns: Float 91 | */ 92 | @IBInspectable override public var shadowOpacity:Float { 93 | get { 94 | return layer.shadowOpacity 95 | } 96 | set { 97 | layer.shadowOpacity = newValue 98 | } 99 | } 100 | 101 | /** 102 | The shadow radius of the layer 103 | 104 | - Returns: CGFloat 105 | */ 106 | @IBInspectable override public var shadowRadius:CGFloat { 107 | get { 108 | return layer.shadowRadius 109 | } 110 | set { 111 | layer.shadowRadius = newValue 112 | } 113 | } 114 | 115 | // MARK: Inspectable properties 116 | 117 | @IBInspectable var startColor: UIColor = UIColor.white { 118 | didSet{ 119 | setupView() 120 | } 121 | } 122 | 123 | @IBInspectable var endColor: UIColor = UIColor.black { 124 | didSet{ 125 | setupView() 126 | } 127 | } 128 | 129 | @IBInspectable var isHorizontal: Bool = false { 130 | didSet{ 131 | setupView() 132 | } 133 | } 134 | 135 | 136 | // MARK: Internal functions 137 | 138 | fileprivate func setupView(){ 139 | let colors = [startColor.cgColor, endColor.cgColor] 140 | gradientLayer.colors = colors 141 | gradientLayer.cornerRadius = cornerRadius 142 | if (isHorizontal){ 143 | gradientLayer.endPoint = CGPoint(x: 1, y: 0) 144 | } else { 145 | gradientLayer.endPoint = CGPoint(x: 0, y: 1) 146 | } 147 | self.setNeedsDisplay() 148 | } 149 | 150 | // Helper to return the main layer as CAGradientLayer 151 | var gradientLayer: CAGradientLayer { 152 | return layer as! CAGradientLayer 153 | } 154 | 155 | 156 | // MARK: Overrides ****************************************** 157 | 158 | override open class var layerClass:AnyClass{ 159 | return CAGradientLayer.self 160 | } 161 | 162 | override init(frame: CGRect) { 163 | super.init(frame: frame) 164 | setupView() 165 | } 166 | 167 | required public init(coder aDecoder: NSCoder) { 168 | super.init(coder: aDecoder)! 169 | setupView() 170 | } 171 | 172 | open override func prepareForInterfaceBuilder() { 173 | setupView() 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /Sources/ViewAnimation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewAnimation.swift 3 | // ViewHelper: Version 4.2.4 4 | // Created by Melvin Rivera on 11/23/15. 5 | // https://github.com/melvitax/ViewHelper 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | /** 12 | A preset animation behavior. 13 | */ 14 | public enum AnimationType { 15 | case slideLeft, slideRight, slideDown, slideUp, squeezeLeft, squeezeRight, squeezeDown, squeezeUp, fadeIn, fadeOut, fadeOutIn, fadeInLeft, fadeInRight, fadeInDown, fadeInUp, zoomIn, zoomOut, fall, shake, pop, flipX, flipY, morph, squeeze, flash, wobble, swing 16 | static let allValues = [shake, pop, morph, squeeze, wobble, swing, flipX, flipY, fall, squeezeLeft, squeezeRight, squeezeDown, squeezeUp, slideLeft, slideRight, slideDown, slideUp, fadeIn, fadeOut, fadeOutIn, fadeInLeft, fadeInRight, fadeInDown, fadeInUp, zoomIn, zoomOut, flash] 17 | var description: String { 18 | get { 19 | return String(describing: self) 20 | } 21 | } 22 | } 23 | 24 | /** 25 | Easing curve to be used in animation. 26 | */ 27 | public enum AnimationEasingCurve { 28 | case easeIn, easeOut, easeInOut, linear, easeInSine, easeOutSine, easeInOutSine, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, easeInQuint, easeOutQuint, easeInOutQuint, easeInExpo, easeOutExpo, easeInOutExpo, easeInCirc, easeOutCirc, easeInOutCirc, easeInBack, easeOutBack, easeInOutBack, spring 29 | static let allValues = [easeIn, easeOut, easeInOut, linear, easeInSine, easeOutSine, easeInOutSine, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, easeInQuint, easeOutQuint, easeInOutQuint, easeInExpo, easeOutExpo, easeInOutExpo, easeInCirc, easeOutCirc, easeInOutCirc, easeInBack, easeOutBack, easeInOutBack, spring] 30 | var timingFunction:CAMediaTimingFunction { 31 | switch self { 32 | case .easeIn: return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) 33 | case .easeOut: return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 34 | case .easeInOut: return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 35 | case .linear: return CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 36 | case .easeInSine: return CAMediaTimingFunction(controlPoints: 0.47, 0, 0.745, 0.715) 37 | case .easeOutSine: return CAMediaTimingFunction(controlPoints: 0.39, 0.575, 0.565, 1) 38 | case .easeInOutSine: return CAMediaTimingFunction(controlPoints: 0.445, 0.05, 0.55, 0.95) 39 | case .easeInQuad: return CAMediaTimingFunction(controlPoints: 0.55, 0.085, 0.68, 0.53) 40 | case .easeOutQuad: return CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) 41 | case .easeInOutQuad: return CAMediaTimingFunction(controlPoints: 0.455, 0.03, 0.515, 0.955) 42 | case .easeInCubic: return CAMediaTimingFunction(controlPoints: 0.55, 0.055, 0.675, 0.19) 43 | case .easeOutCubic: return CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) 44 | case .easeInOutCubic: return CAMediaTimingFunction(controlPoints: 0.645, 0.045, 0.355, 1) 45 | case .easeInQuart: return CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22) 46 | case .easeOutQuart: return CAMediaTimingFunction(controlPoints: 0.165, 0.84, 0.44, 1) 47 | case .easeInOutQuart: return CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) 48 | case .easeInQuint: return CAMediaTimingFunction(controlPoints: 0.755, 0.05, 0.855, 0.06) 49 | case .easeOutQuint: return CAMediaTimingFunction(controlPoints: 0.23, 1, 0.32, 1) 50 | case .easeInOutQuint: return CAMediaTimingFunction(controlPoints: 0.86, 0, 0.07, 1) 51 | case .easeInExpo: return CAMediaTimingFunction(controlPoints: 0.95, 0.05, 0.795, 0.035) 52 | case .easeOutExpo: return CAMediaTimingFunction(controlPoints: 0.19, 1, 0.22, 1) 53 | case .easeInOutExpo: return CAMediaTimingFunction(controlPoints: 1, 0, 0, 1) 54 | case .easeInCirc: return CAMediaTimingFunction(controlPoints: 0.6, 0.04, 0.98, 0.335) 55 | case .easeOutCirc: return CAMediaTimingFunction(controlPoints: 0.075, 0.82, 0.165, 1) 56 | case .easeInOutCirc: return CAMediaTimingFunction(controlPoints: 0.785, 0.135, 0.15, 0.86) 57 | case .easeInBack: return CAMediaTimingFunction(controlPoints: 0.6, -0.28, 0.735, 0.045) 58 | case .easeOutBack: return CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.275) 59 | case .easeInOutBack: return CAMediaTimingFunction(controlPoints: 0.68, -0.55, 0.265, 1.55) 60 | case .spring: return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(1/3), 1, 1) 61 | } 62 | } 63 | var animationOption:UIViewAnimationOptions { 64 | switch self { 65 | case .easeIn: return UIViewAnimationOptions.curveEaseIn 66 | case .easeOut: return UIViewAnimationOptions.curveEaseOut 67 | case .easeInOut: return UIViewAnimationOptions() 68 | default: return UIViewAnimationOptions.curveLinear 69 | } 70 | } 71 | var description: String { 72 | get { 73 | return String(describing: self) 74 | } 75 | } 76 | } 77 | 78 | public extension UIView { 79 | 80 | typealias AnimationCompletionHandler = () -> Void 81 | 82 | /** 83 | Animates using a predermined animation type and provides optional properties for customization. 84 | 85 | - Parameter animationType: The Animation type to use. 86 | - Parameter curve: The animation easing curve. 87 | - Parameter duration: The duration of the animation. 88 | - Parameter delay: The delay before animation begins. 89 | - Parameter force: The force of the movement. 90 | - Parameter damping: The damping of the force. 91 | - Parameter velocity: The velocity of the movement. 92 | - Parameter distance: The distance that it travels, like in the case of SlideLeft 93 | - Parameter fromRotation: The starting rotation. 94 | - Parameter fromScale: The starting scale. 95 | - Parameter fromX: The starting x offset. 96 | - Parameter fromY: The starting y offset. 97 | - Parameter completion: The completion handler that runs after animation is complete. 98 | */ 99 | 100 | func animate(_ animationType:AnimationType, curve:AnimationEasingCurve, duration:CGFloat = 1, delay:CGFloat = 0, force:CGFloat = 1, damping:CGFloat = 0.7, velocity:CGFloat = 0.7, distance:CGFloat = 300.0, fromRotation:CGFloat = 0, fromScale:CGFloat = 1, fromX:CGFloat = 0, fromY:CGFloat = 0, completion: AnimationCompletionHandler? = nil) 101 | { 102 | var scaleX = fromScale 103 | var scaleY = fromScale 104 | var opacity:CGFloat = 0 105 | let repeatCount:Float = 1 106 | var rotate = fromRotation 107 | var x = fromX 108 | var y = fromY 109 | 110 | var animateFromInitialState = true 111 | 112 | alpha = 0.99 113 | 114 | switch animationType { 115 | case .slideLeft: 116 | x = distance*force 117 | case .slideRight: 118 | x = -distance*force 119 | case .slideDown: 120 | y = -distance*force 121 | case .slideUp: 122 | y = distance*force 123 | case .squeezeLeft: 124 | x = distance 125 | scaleX = 3*force 126 | case .squeezeRight: 127 | x = -distance 128 | scaleX = 3*force 129 | case .squeezeDown: 130 | y = -distance 131 | scaleY = 3*force 132 | case .squeezeUp: 133 | y = distance 134 | scaleY = 3*force 135 | case .fadeIn: 136 | opacity = 0 137 | case .fadeOut: 138 | animateFromInitialState = false 139 | opacity = 0 140 | case .fadeOutIn: 141 | let animation = CABasicAnimation() 142 | animation.keyPath = "opacity" 143 | animation.fromValue = 1 144 | animation.toValue = 0 145 | animation.timingFunction = curve.timingFunction 146 | animation.duration = CFTimeInterval(duration) 147 | animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 148 | animation.autoreverses = true 149 | layer.add(animation, forKey: "fade") 150 | case .fadeInLeft: 151 | opacity = 0 152 | x = distance*force 153 | case .fadeInRight: 154 | x = -distance*force 155 | opacity = 0 156 | case .fadeInDown: 157 | y = -distance*force 158 | opacity = 0 159 | case .fadeInUp: 160 | y = distance*force 161 | opacity = 0 162 | case .zoomIn: 163 | opacity = 0 164 | scaleX = 2*force 165 | scaleY = 2*force 166 | case .zoomOut: 167 | animateFromInitialState = false 168 | opacity = 0 169 | scaleX = 2*force 170 | scaleY = 2*force 171 | case .fall: 172 | animateFromInitialState = false 173 | rotate = 15 * CGFloat(M_PI/180) 174 | y = distance*force 175 | case .shake: 176 | let animation = CAKeyframeAnimation() 177 | animation.keyPath = "position.x" 178 | animation.values = [0, 30*force, -30*force, 30*force, 0] 179 | animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 180 | animation.timingFunction = curve.timingFunction 181 | animation.duration = CFTimeInterval(duration) 182 | animation.isAdditive = true 183 | animation.repeatCount = repeatCount 184 | animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 185 | layer.add(animation, forKey: "shake") 186 | case .pop: 187 | let animation = CAKeyframeAnimation() 188 | animation.keyPath = "transform.scale" 189 | animation.values = [0, 0.2*force, -0.2*force, 0.2*force, 0] 190 | animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 191 | animation.timingFunction = curve.timingFunction 192 | animation.duration = CFTimeInterval(duration) 193 | animation.isAdditive = true 194 | animation.repeatCount = repeatCount 195 | animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 196 | layer.add(animation, forKey: "pop") 197 | case .flipX: 198 | rotate = 0 199 | scaleX = 1 200 | scaleY = 1 201 | var perspective = CATransform3DIdentity 202 | perspective.m34 = -1.0 / layer.frame.size.width/2 203 | 204 | let animation = CABasicAnimation() 205 | animation.keyPath = "transform" 206 | animation.fromValue = NSValue(caTransform3D: 207 | CATransform3DMakeRotation(0, 0, 0, 0)) 208 | animation.toValue = NSValue(caTransform3D: 209 | CATransform3DConcat(perspective, CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0))) 210 | animation.duration = CFTimeInterval(duration) 211 | animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 212 | animation.timingFunction = curve.timingFunction 213 | layer.add(animation, forKey: "3d") 214 | case .flipY: 215 | var perspective = CATransform3DIdentity 216 | perspective.m34 = -1.0 / layer.frame.size.width/2 217 | 218 | let animation = CABasicAnimation() 219 | animation.keyPath = "transform" 220 | animation.fromValue = NSValue(caTransform3D: 221 | CATransform3DMakeRotation(0, 0, 0, 0)) 222 | animation.toValue = NSValue(caTransform3D: 223 | CATransform3DConcat(perspective,CATransform3DMakeRotation(CGFloat(M_PI), 1, 0, 0))) 224 | animation.duration = CFTimeInterval(duration) 225 | animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 226 | animation.timingFunction = curve.timingFunction 227 | layer.add(animation, forKey: "3d") 228 | case .morph: 229 | let morphX = CAKeyframeAnimation() 230 | morphX.keyPath = "transform.scale.x" 231 | morphX.values = [1, 1.3*force, 0.7, 1.3*force, 1] 232 | morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 233 | morphX.timingFunction = curve.timingFunction 234 | morphX.duration = CFTimeInterval(duration) 235 | morphX.repeatCount = repeatCount 236 | morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 237 | layer.add(morphX, forKey: "morphX") 238 | 239 | let morphY = CAKeyframeAnimation() 240 | morphY.keyPath = "transform.scale.y" 241 | morphY.values = [1, 0.7, 1.3*force, 0.7, 1] 242 | morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 243 | morphY.timingFunction = curve.timingFunction 244 | morphY.duration = CFTimeInterval(duration) 245 | morphY.repeatCount = repeatCount 246 | morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 247 | layer.add(morphY, forKey: "morphY") 248 | case .squeeze: 249 | let morphX = CAKeyframeAnimation() 250 | morphX.keyPath = "transform.scale.x" 251 | morphX.values = [1, 1.5*force, 0.5, 1.5*force, 1] 252 | morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 253 | morphX.timingFunction = curve.timingFunction 254 | morphX.duration = CFTimeInterval(duration) 255 | morphX.repeatCount = repeatCount 256 | morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 257 | layer.add(morphX, forKey: "morphX") 258 | 259 | let morphY = CAKeyframeAnimation() 260 | morphY.keyPath = "transform.scale.y" 261 | morphY.values = [1, 0.5, 1, 0.5, 1] 262 | morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 263 | morphY.timingFunction = curve.timingFunction 264 | morphY.duration = CFTimeInterval(duration) 265 | morphY.repeatCount = repeatCount 266 | morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 267 | layer.add(morphY, forKey: "morphY") 268 | case .flash: 269 | let animation = CABasicAnimation() 270 | animation.keyPath = "opacity" 271 | animation.fromValue = 1 272 | animation.toValue = 0 273 | animation.duration = CFTimeInterval(duration) 274 | animation.repeatCount = repeatCount * 2.0 275 | animation.autoreverses = true 276 | animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 277 | layer.add(animation, forKey: "flash") 278 | case .wobble: 279 | let animation = CAKeyframeAnimation() 280 | animation.keyPath = "transform.rotation" 281 | animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] 282 | animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 283 | animation.duration = CFTimeInterval(duration) 284 | animation.isAdditive = true 285 | animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 286 | layer.add(animation, forKey: "wobble") 287 | 288 | let x = CAKeyframeAnimation() 289 | x.keyPath = "position.x" 290 | x.values = [0, 30*force, -30*force, 30*force, 0] 291 | x.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 292 | x.timingFunction = curve.timingFunction 293 | x.duration = CFTimeInterval(duration) 294 | x.isAdditive = true 295 | x.repeatCount = repeatCount 296 | x.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 297 | layer.add(x, forKey: "x") 298 | case .swing: 299 | let animation = CAKeyframeAnimation() 300 | animation.keyPath = "transform.rotation" 301 | animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] 302 | animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] 303 | animation.duration = CFTimeInterval(duration) 304 | animation.isAdditive = true 305 | animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) 306 | layer.add(animation, forKey: "swing") 307 | } 308 | 309 | if animateFromInitialState { 310 | let translate = CGAffineTransform(translationX: x, y: y) 311 | let scale = CGAffineTransform(scaleX: scaleX, y: scaleY) 312 | let rotate = CGAffineTransform(rotationAngle: rotate) 313 | let translateAndScale = translate.concatenating(scale) 314 | self.transform = rotate.concatenating(translateAndScale) 315 | alpha = opacity 316 | } 317 | 318 | UIView.animate( withDuration: TimeInterval(duration), 319 | delay: TimeInterval(delay), 320 | usingSpringWithDamping: damping, 321 | initialSpringVelocity: velocity, 322 | options: [curve.animationOption, UIViewAnimationOptions.allowUserInteraction], 323 | animations: { [weak self] in 324 | if let _self = self { 325 | if animateFromInitialState { 326 | _self.transform = CGAffineTransform.identity 327 | _self.alpha = 1 328 | } else { 329 | let translate = CGAffineTransform(translationX: x, y: y) 330 | let scale = CGAffineTransform(scaleX: scaleX, y: scaleY) 331 | let rotate = CGAffineTransform(rotationAngle: rotate) 332 | let translateAndScale = translate.concatenating(scale) 333 | _self.transform = rotate.concatenating(translateAndScale) 334 | _self.alpha = opacity 335 | } 336 | } 337 | }, completion: { finished in 338 | completion?() 339 | }) 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /Sources/ViewAutoLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewAutoLayout.swift 3 | // ViewHelper: Version 4.2.4 4 | // Created by Melvin Rivera on 11/5/15. 5 | // https://github.com/melvitax/ViewHelper 6 | // 7 | 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public extension UIView { 13 | 14 | // MARK: Init 15 | 16 | /** 17 | Instantiates a new UIView with Auto Layout 18 | 19 | - Parameter autoLayout Enables Auto Layout. 20 | - Returns: self 21 | */ 22 | convenience init(autoLayout: Bool = true) 23 | { 24 | self.init(frame:CGRect.zero) 25 | self.translatesAutoresizingMaskIntoConstraints = !(autoLayout) 26 | } 27 | 28 | // MARK: Position 29 | 30 | /** 31 | Returns the frame's origin 32 | */ 33 | 34 | func origin() -> CGPoint { return frame.origin } 35 | 36 | /** 37 | Sets the frame's top and left sides using Auto Layout or frames 38 | 39 | - Parameter constant: The CGPoint to ise as the origin 40 | - Returns: self 41 | */ 42 | func origin(_ constant: CGPoint) -> UIView { 43 | if translatesAutoresizingMaskIntoConstraints { 44 | frame.origin = constant 45 | return self 46 | } else { 47 | return origin(to: superview!, constant: constant) 48 | } 49 | } 50 | /** 51 | Pins left and top sides to another view using Auto Layout 52 | 53 | - Parameter to: The view to pin to 54 | - Parameter constant: The offset to use after multiplication is done. 55 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 56 | - Returns: self UIView 57 | */ 58 | func origin(to:AnyObject, constant: CGPoint = CGPoint(x: 0, y: 0), multiplier:CGFloat = 1) -> UIView { 59 | var constraints = [NSLayoutConstraint]() 60 | if let left = pin(.left, to: to, attribute: .left, constant: constant.x, multiplier: multiplier) { 61 | constraints.append(left) 62 | } 63 | if let top = pin(.top, to: to, attribute: .top, constant: constant.y, multiplier: multiplier) { 64 | constraints.append(top) 65 | } 66 | return self 67 | } 68 | 69 | /** 70 | Returns the frame minimum x point 71 | */ 72 | func left() -> CGFloat { return frame.origin.x } 73 | 74 | /** 75 | Sets the frame left side using Auto Layout or frames 76 | 77 | - Parameter constant: The value to use. 78 | - Returns: self 79 | */ 80 | func left(_ constant: CGFloat) -> UIView { 81 | if translatesAutoresizingMaskIntoConstraints { 82 | frame.origin.x = constant 83 | return self 84 | } else { 85 | return left(to: superview!, attribute: .left, constant: constant) 86 | } 87 | } 88 | 89 | /** 90 | Pins left side to another view using Auto Layout 91 | 92 | - Parameter to: The view to pin to 93 | - Parameter attribute: The attribute to pin to 94 | - Parameter constant: The offset to use after multiplication is done. 95 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 96 | - Returns: self 97 | */ 98 | func left(to:AnyObject, attribute: NSLayoutAttribute = .left, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 99 | _ = pin(.left, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 100 | return self 101 | } 102 | 103 | /** 104 | Returns the frame leading value 105 | */ 106 | func leading() -> CGFloat { return layoutDirectionIsLeftToRight() ? left() : right() } 107 | 108 | /** 109 | Sets the frame leading side using Auto Layout or frames 110 | 111 | - Parameter constant: The value to use. 112 | - Returns: self 113 | */ 114 | func leading(_ constant: CGFloat) -> UIView { 115 | if translatesAutoresizingMaskIntoConstraints { 116 | return layoutDirectionIsLeftToRight() ? left(constant) : right(constant) 117 | } else { 118 | return leading(to: superview!, attribute: .leading, constant: constant) 119 | } 120 | } 121 | 122 | /** 123 | Pins the frame leading side to another view using Auto Layout 124 | 125 | - Parameter to: The view to pin to 126 | - Parameter attribute: The attribute to pin to 127 | - Parameter constant: The offset to use after multiplication is done. 128 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 129 | - Returns: self 130 | */ 131 | func leading(to:AnyObject, attribute: NSLayoutAttribute = .leading, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 132 | _ = pin(.leading, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 133 | return self 134 | } 135 | 136 | /** 137 | Returns the frame max x point 138 | */ 139 | func right() -> CGFloat { return frame.origin.x + frame.size.width } 140 | 141 | /** 142 | Sets the frame right side using Auto Layout or frames 143 | 144 | - Parameter constant: The value to use. 145 | - Returns: self 146 | */ 147 | func right(_ constant: CGFloat) -> UIView { 148 | if translatesAutoresizingMaskIntoConstraints { 149 | return left(constant - width()) 150 | } else { 151 | return right(to: superview!, attribute: .right, constant: constant) 152 | } 153 | } 154 | /** 155 | Pins the frame right side to another view using Auto Layout 156 | 157 | - Parameter to: The view to pin to 158 | - Parameter attribute: The attribute to pin to 159 | - Parameter constant: The offset to use after multiplication is done. 160 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 161 | - Returns: self 162 | */ 163 | func right(to:AnyObject, attribute: NSLayoutAttribute = .right, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 164 | _ = pin(.right, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 165 | return self 166 | } 167 | 168 | /** 169 | Returns the frame trailing value 170 | */ 171 | func trailing() -> CGFloat { return layoutDirectionIsLeftToRight() ? right() : left() } 172 | 173 | /** 174 | Sets the frame trailing side using Auto Layout or frames 175 | 176 | - Parameter constant: The value to use 177 | - Returns: self UIView 178 | */ 179 | func trailing(_ constant: CGFloat) -> UIView { 180 | if translatesAutoresizingMaskIntoConstraints { 181 | return layoutDirectionIsLeftToRight() ? right(constant) : left(constant) 182 | } else { 183 | return trailing(to: superview!, attribute: .trailing, constant: constant) 184 | } 185 | } 186 | 187 | /** 188 | Pins the frame trailing side to another view using Auto Layout 189 | 190 | - Parameter to: The view to pin to 191 | - Parameter attribute: The attribute to pin to 192 | - Parameter constant: The offset to use after multiplication is done. 193 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 194 | - Returns: self 195 | */ 196 | func trailing(to:AnyObject, attribute: NSLayoutAttribute = .trailing, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 197 | _ = pin(.trailing, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 198 | return self 199 | } 200 | 201 | /** 202 | Returns the frame top value 203 | */ 204 | func top() -> CGFloat { return frame.origin.y } 205 | 206 | /** 207 | Sets the frame top side using Auto Layout or frames 208 | 209 | - Parameter constant: The value to use. 210 | - Returns: self 211 | */ 212 | func top(_ constant: CGFloat) -> UIView { 213 | if translatesAutoresizingMaskIntoConstraints { 214 | frame.origin.y = constant 215 | return self 216 | } else { 217 | return top(to: superview!, attribute: .top, constant: constant) 218 | } 219 | } 220 | 221 | /** 222 | Pins the frame trailing side to another view using Auto Layout 223 | 224 | - Parameter to: The view to pin to 225 | - Parameter attribute: The attribute to pin to 226 | - Parameter constant: The offset to use after multiplication is done. 227 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 228 | - Returns: self 229 | */ 230 | func top(to:AnyObject, attribute: NSLayoutAttribute = .top, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 231 | _ = pin(.top, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 232 | return self 233 | } 234 | 235 | /** 236 | Returns the frame bottom value 237 | */ 238 | func bottom() -> CGFloat { return top() + height() } 239 | 240 | /** 241 | Sets the frame bottom side using Auto Layout or frames 242 | 243 | - Parameter constant: The value to use. 244 | - Returns: self 245 | */ 246 | func bottom(_ constant: CGFloat) -> UIView { 247 | if translatesAutoresizingMaskIntoConstraints { 248 | return top(constant - height()) 249 | } else { 250 | return bottom(to: superview!, attribute: .bottom, constant: constant) 251 | } 252 | } 253 | /** 254 | Pins the frame bottom side to another view using Auto Layout 255 | 256 | - Parameter to: The view to pin to 257 | - Parameter attribute: The attribute to pin to 258 | - Parameter constant: The offset to use after multiplication is done. 259 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 260 | - Returns: self 261 | */ 262 | func bottom(to:AnyObject, attribute: NSLayoutAttribute = .bottom, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 263 | _ = pin(.bottom, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 264 | return self 265 | } 266 | 267 | /** 268 | Sets the center to it's superview using Auto Layout or frames 269 | 270 | - Parameter constant: The value to use. 271 | - Returns: self 272 | */ 273 | func center(_ constant: CGPoint = CGPoint(x: 0, y: 0)) -> UIView { 274 | if translatesAutoresizingMaskIntoConstraints { 275 | center = constant 276 | } else { 277 | _ = centerX(constant.x).centerY(constant.y) 278 | } 279 | return self 280 | } 281 | 282 | /** 283 | Pins the center point to another view using Auto Layout 284 | 285 | - Parameter to: The view to pin to 286 | - Parameter constant: The offset to use after multiplication is done. 287 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 288 | - Returns: self 289 | */ 290 | func center(to:AnyObject, constant:CGSize = CGSize(width: 0, height: 0), multiplier:CGFloat = 1) -> UIView { 291 | var constraints = [NSLayoutConstraint]() 292 | if let centerX = pin(.centerX, to: superview!, attribute: .centerX, constant: constant.width, multiplier: multiplier) { 293 | constraints.append(centerX) 294 | } 295 | if let centerY = pin(.centerY, to: superview!, attribute: .centerY, constant: constant.height, multiplier: multiplier) { 296 | constraints.append(centerY) 297 | } 298 | return self 299 | } 300 | 301 | /** 302 | Returns the center X 303 | */ 304 | func centerX() -> CGFloat { return center.x } 305 | 306 | /** 307 | Sets the center X using Auto Layout or frames 308 | 309 | - Parameter constant: The value to use. 310 | - Returns: self 311 | */ 312 | func centerX(_ constant: CGFloat = 0) -> UIView { 313 | if translatesAutoresizingMaskIntoConstraints { 314 | center = CGPoint(x: superview!.width()/2 + constant , y: center.y) 315 | } else { 316 | _ = pin(.centerX, to: superview!, attribute: .centerX, constant: constant) 317 | } 318 | return self 319 | } 320 | 321 | /** 322 | Pins the center X to another view using Auto Layout 323 | 324 | - Parameter to: The view to pin to 325 | - Parameter attribute: The attribute to pin to 326 | - Parameter constant: The offset to use after multiplication is done. 327 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 328 | - Returns: self 329 | */ 330 | func centerX(to:AnyObject, attribute: NSLayoutAttribute = .centerX, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 331 | _ = pin(.centerX, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 332 | return self 333 | } 334 | 335 | /** 336 | Returns the center Y 337 | */ 338 | func centerY() -> CGFloat { return center.y } 339 | 340 | /** 341 | Sets the center Y using Auto Layout or frames 342 | 343 | - Parameter constant: The value to use. 344 | - Returns: self 345 | */ 346 | func centerY(_ constant: CGFloat = 0) -> UIView { 347 | if translatesAutoresizingMaskIntoConstraints { 348 | center = CGPoint(x: superview!.center.x, y: CGFloat(superview!.height()/2) + constant) 349 | } else { 350 | _ = pin(.centerY, to: superview!, attribute: .centerY, constant: constant) 351 | } 352 | return self 353 | } 354 | 355 | /** 356 | Pins the center Y to another view using Auto Layout 357 | 358 | - Parameter to: The view to pin to 359 | - Parameter attribute: The attribute to pin to 360 | - Parameter constant: The offset to use after multiplication is done. 361 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 362 | - Returns: self 363 | */ 364 | func centerY(to:AnyObject, attribute: NSLayoutAttribute = .centerY, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 365 | _ = pin(.centerY, to: superview!, attribute: attribute, constant: constant) 366 | return self 367 | } 368 | 369 | // MARK: Compression and Hugging Priority 370 | 371 | /** 372 | Returns the Compression Resistance Priority for Horizontal Axis using Auto Layout 373 | */ 374 | func horizontalCompressionPriority() -> UILayoutPriority { return contentCompressionResistancePriority(for: .horizontal) } 375 | 376 | /** 377 | Sets the Compression Resistance Priority for Horizontal Axis using Auto Layout 378 | 379 | - Returns: self 380 | */ 381 | func horizontalCompressionPriority(_ priority: UILayoutPriority) -> UIView { 382 | if !translatesAutoresizingMaskIntoConstraints { 383 | setContentCompressionResistancePriority(priority, for: .horizontal) 384 | } 385 | return self 386 | } 387 | 388 | /** 389 | Returns the Compression Resistance Priority for Vertical Axis using Auto Layout 390 | */ 391 | func verticalCompressionPriority() -> UILayoutPriority { return contentCompressionResistancePriority(for: .vertical) } 392 | 393 | /** 394 | Sets the Compression Resistance Priority for Vertical Axis using Auto Layout 395 | 396 | - Returns: self 397 | */ 398 | func verticalCompressionPriority(_ priority: UILayoutPriority) -> UIView { 399 | if !translatesAutoresizingMaskIntoConstraints { 400 | setContentCompressionResistancePriority(priority, for: .vertical) 401 | } 402 | return self 403 | } 404 | 405 | /** 406 | Returns the Content Hugging Priority for Horizontal Axis using Auto Layout 407 | */ 408 | func horizontalHuggingPriority() -> UILayoutPriority { return contentHuggingPriority(for: .horizontal) } 409 | 410 | /** 411 | Sets the Content Hugging Priority for Horizontal Axis using Auto Layout 412 | 413 | - Returns: self 414 | */ 415 | func horizontalHuggingPriority(_ priority: UILayoutPriority) -> UIView { 416 | if !translatesAutoresizingMaskIntoConstraints { 417 | setContentHuggingPriority(priority, for: .horizontal) 418 | } 419 | return self 420 | } 421 | 422 | /** 423 | Returns the Content Hugging Priority for Vertical Axis using Auto Layout 424 | */ 425 | func verticalHuggingPriority() -> UILayoutPriority { return contentHuggingPriority(for: .vertical) } 426 | 427 | /** 428 | Sets the Content Hugging Priority for Vertical Axis using Auto Layout 429 | 430 | - Returns: self 431 | */ 432 | func verticalHuggingPriority(_ priority: UILayoutPriority) -> UIView { 433 | if !translatesAutoresizingMaskIntoConstraints { 434 | setContentHuggingPriority(priority, for: .vertical) 435 | } 436 | return self 437 | } 438 | 439 | 440 | // MARK: Size 441 | 442 | /** 443 | Returns the frame size 444 | */ 445 | func size() -> CGSize { return frame.size } 446 | 447 | /** 448 | Sets the frame size using Auto Layout or frames 449 | 450 | - Parameter constant: The value to use. 451 | - Returns: self UIView 452 | */ 453 | func size(_ constant: CGSize) -> UIView { 454 | if translatesAutoresizingMaskIntoConstraints { 455 | frame.size = constant 456 | } else { 457 | _ = applyAttribute(.width, constant: constant.width) 458 | _ = applyAttribute(.height, constant: constant.height) 459 | } 460 | return self 461 | } 462 | 463 | /** 464 | Pins the size to another view using Auto Layout 465 | 466 | - Parameter to: The view to pin to 467 | - Parameter constant: The offset to use after multiplication is done. 468 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 469 | - Returns: self 470 | */ 471 | func size(to:AnyObject, constant: CGSize = CGSize(width: 0, height: 0), multiplier:CGFloat = 1) -> UIView { 472 | if !translatesAutoresizingMaskIntoConstraints { 473 | var constraints = [NSLayoutConstraint]() 474 | if let width = pin(.width, to: to, attribute: .width, constant: constant.width, multiplier: multiplier) { 475 | constraints.append(width) 476 | } 477 | if let height = pin(.height, to: to, attribute: .height, constant: constant.height, multiplier: multiplier) { 478 | constraints.append(height) 479 | } 480 | } 481 | return self 482 | } 483 | 484 | /** 485 | Returns the frame width 486 | */ 487 | func width() -> CGFloat { return frame.size.width } 488 | 489 | /** 490 | Sets the frame width using Auto Layout or frames 491 | 492 | - Parameter constant: The value to use. 493 | - Returns: self 494 | */ 495 | func width(_ constant: CGFloat) -> UIView { 496 | if translatesAutoresizingMaskIntoConstraints { 497 | frame.size.width = constant 498 | } else { 499 | _ = applyAttribute(.width, constant: constant) 500 | } 501 | return self 502 | } 503 | 504 | /** 505 | Pins the width to another view using Auto Layout 506 | 507 | - Parameter to: The view to pin to 508 | - Parameter attribute: The attribute to pin to 509 | - Parameter constant: The offset to use after multiplication is done. 510 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 511 | - Returns: self 512 | */ 513 | func width(to:AnyObject, attribute: NSLayoutAttribute = .width, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 514 | if !translatesAutoresizingMaskIntoConstraints { 515 | _ = pin(.width, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 516 | } 517 | return self 518 | } 519 | 520 | /** 521 | Returns the frame height 522 | */ 523 | func height() -> CGFloat { return frame.size.height } 524 | 525 | /** 526 | Sets the frame height using Auto Layout or frames 527 | 528 | - Parameter constant: The value to use. 529 | - Returns: self UIView 530 | */ 531 | func height(_ constant: CGFloat) -> UIView { 532 | if translatesAutoresizingMaskIntoConstraints { 533 | frame.size.height = constant 534 | } else { 535 | _ = applyAttribute(.height, constant: constant) 536 | } 537 | return self 538 | } 539 | 540 | /** 541 | Pins the height to another view using Auto Layout 542 | 543 | - Parameter to: The view to pin to 544 | - Parameter attribute: The attribute to pin to 545 | - Parameter constant: The offset to use after multiplication is done. 546 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 547 | - Returns: self 548 | */ 549 | func height(to:AnyObject, attribute: NSLayoutAttribute = .height, constant: CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 550 | if !translatesAutoresizingMaskIntoConstraints { 551 | _ = pin(.height, to: to, attribute: attribute, constant: constant, multiplier: multiplier) 552 | } 553 | return self 554 | } 555 | 556 | /** 557 | Returns the minimum size using Auto Layout 558 | */ 559 | func minSize() -> CGSize? { 560 | if !translatesAutoresizingMaskIntoConstraints { 561 | if let minWidth = minWidth() { 562 | if let minHeight = minHeight() { 563 | return CGSize(width: minWidth, height: minHeight) 564 | } 565 | } 566 | } 567 | return nil 568 | } 569 | 570 | /** 571 | Sets the minimum size using Auto Layout 572 | 573 | - Parameter constant: The value to use. 574 | - Returns: self 575 | */ 576 | func minSize(_ constant:CGSize) -> UIView { 577 | if !translatesAutoresizingMaskIntoConstraints { 578 | _ = applyAttribute(.width, constant: constant.width, multiplier: 1, relation: .greaterThanOrEqual) 579 | _ = applyAttribute(.height, constant: constant.height, multiplier: 1, relation: .greaterThanOrEqual) 580 | } 581 | return self 582 | } 583 | 584 | /** 585 | Pins the minimum size to another view using Auto Layout 586 | 587 | - Parameter to: The view to pin to 588 | - Parameter constant: The offset to use after multiplication is done. 589 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 590 | - Returns: self 591 | */ 592 | func minSize(to:AnyObject, constant:CGSize = CGSize(width: 0, height: 0), multiplier:CGFloat = 1) -> UIView { 593 | if !translatesAutoresizingMaskIntoConstraints { 594 | var constraints = [NSLayoutConstraint]() 595 | if let width = pin(.width, to: to, attribute: .width, constant: constant.width, multiplier: multiplier, relation: .greaterThanOrEqual) { 596 | constraints.append(width) 597 | } 598 | if let height = pin(.width, to: to, attribute: .height, constant: constant.height, multiplier: multiplier, relation: .greaterThanOrEqual) { 599 | constraints.append(height) 600 | } 601 | } 602 | return self 603 | } 604 | 605 | /** 606 | Returns the minimum width using Auto Layout 607 | */ 608 | func minWidth() -> CGFloat? { 609 | if !translatesAutoresizingMaskIntoConstraints { 610 | for constrain in constraints { 611 | if constrain.firstAttribute == .width && constrain.firstItem as! NSObject == self && constrain.secondItem == nil && constrain.relation == .greaterThanOrEqual { 612 | return constrain.constant 613 | } 614 | } 615 | } 616 | return nil 617 | } 618 | 619 | /** 620 | Sets the minimum width using Auto Layout 621 | 622 | - Parameter constant: The value to use. 623 | - Returns: self 624 | */ 625 | func minWidth(_ constant:CGFloat) -> UIView { 626 | if !translatesAutoresizingMaskIntoConstraints { 627 | _ = applyAttribute(.width, constant: constant, multiplier: 1, relation: .greaterThanOrEqual) 628 | } 629 | return self 630 | } 631 | 632 | /** 633 | Pins the minimum width to another view using Auto Layout 634 | 635 | - Parameter to: The view to pin to 636 | - Parameter attribute: The attribute to pin to 637 | - Parameter constant: The offset to use after multiplication is done. 638 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 639 | - Returns: self 640 | */ 641 | func minWidth(to:AnyObject, attribute: NSLayoutAttribute = .width, constant:CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 642 | if !translatesAutoresizingMaskIntoConstraints { 643 | _ = pin(.width, to: to, attribute: attribute, constant: constant, multiplier: multiplier, relation: .greaterThanOrEqual) 644 | } 645 | return self 646 | } 647 | 648 | /** 649 | Returns the minimum height using Auto Layout 650 | */ 651 | func minHeight() -> CGFloat? { 652 | if !translatesAutoresizingMaskIntoConstraints { 653 | for constrain in constraints { 654 | if constrain.firstAttribute == .height && constrain.firstItem as! NSObject == self && constrain.secondItem == nil && constrain.relation == .greaterThanOrEqual { 655 | return constrain.constant 656 | } 657 | } 658 | } 659 | return nil 660 | } 661 | 662 | /** 663 | Sets the minimum height using Auto Layout 664 | 665 | - Parameter constant: The value to use. 666 | - Returns: self 667 | */ 668 | func minHeight(_ constant:CGFloat) -> UIView { 669 | if !translatesAutoresizingMaskIntoConstraints { 670 | _ = applyAttribute(.height, constant: constant, multiplier: 1, relation: .greaterThanOrEqual) 671 | } 672 | return self 673 | } 674 | 675 | /** 676 | Pins the minimum height to another view using Auto Layout 677 | 678 | - Parameter to: The view to pin to 679 | - Parameter attribute: The attribute to pin to 680 | - Parameter constant: The offset to use after multiplication is done. 681 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 682 | - Returns: self 683 | */ 684 | func minHeight(to:AnyObject, attribute: NSLayoutAttribute = .height, constant:CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 685 | if !translatesAutoresizingMaskIntoConstraints { 686 | _ = pin(.height, to: to, attribute: attribute, constant: constant, multiplier: multiplier, relation: .greaterThanOrEqual) 687 | } 688 | return self 689 | } 690 | 691 | /** 692 | Returns the maximun size using Auto Layout 693 | */ 694 | func maxSize() -> CGSize? { 695 | if !translatesAutoresizingMaskIntoConstraints { 696 | if let maxWidth = maxWidth() { 697 | if let maxHeight = maxHeight() { 698 | return CGSize(width: maxWidth, height: maxHeight) 699 | } 700 | } 701 | } 702 | return nil 703 | } 704 | 705 | /** 706 | Sets the maximun size using Auto Layout 707 | 708 | - Parameter constant: The value to use. 709 | - Returns: self 710 | */ 711 | func maxSize(_ constant:CGSize) -> UIView { 712 | if !translatesAutoresizingMaskIntoConstraints { 713 | _ = applyAttribute(.width, constant: constant.width, multiplier: 1, relation: .lessThanOrEqual) 714 | _ = applyAttribute(.height, constant: constant.height, multiplier: 1, relation: .lessThanOrEqual) 715 | } 716 | return self 717 | } 718 | 719 | /** 720 | Pins the maximun size to another view using Auto Layout 721 | 722 | - Parameter to: The view to pin to 723 | - Parameter constant: The offset to use after multiplication is done. 724 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 725 | - Returns: self 726 | */ 727 | func maxSize(to:AnyObject, constant:CGSize = CGSize(width: 0, height: 0), multiplier:CGFloat = 1) -> UIView { 728 | if !translatesAutoresizingMaskIntoConstraints { 729 | var constraints = [NSLayoutConstraint]() 730 | if let width = pin(.width, to: to, attribute: .width, constant: constant.width, multiplier: multiplier, relation: .lessThanOrEqual) { 731 | constraints.append(width) 732 | } 733 | if let height = pin(.width, to: to, attribute: .height, constant: constant.height, multiplier: multiplier, relation: .lessThanOrEqual) { 734 | constraints.append(height) 735 | } 736 | } 737 | return self 738 | } 739 | 740 | /** 741 | Returns the maximun width using Auto Layout 742 | */ 743 | func maxWidth() -> CGFloat? { 744 | if !translatesAutoresizingMaskIntoConstraints { 745 | for constrain in constraints { 746 | if constrain.firstAttribute == .width && constrain.firstItem as! NSObject == self && constrain.secondItem == nil && constrain.relation == .lessThanOrEqual { 747 | return constrain.constant 748 | } 749 | } 750 | } 751 | return nil 752 | } 753 | 754 | /** 755 | Sets the maximun width using Auto Layout 756 | 757 | - Parameter constant: The value to use. 758 | - Returns: self 759 | */ 760 | func maxWidth(_ constant:CGFloat) -> UIView { 761 | if !translatesAutoresizingMaskIntoConstraints { 762 | _ = applyAttribute(.width, constant: constant, multiplier: 1, relation: .lessThanOrEqual) 763 | } 764 | return self 765 | } 766 | 767 | /** 768 | Pins the maximun width to another view using Auto Layout 769 | 770 | - Parameter to: The view to pin to 771 | - Parameter attribute: The attribute to pin to 772 | - Parameter constant: The offset to use after multiplication is done. 773 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 774 | - Returns: self 775 | */ 776 | func maxWidth(to:AnyObject, attribute: NSLayoutAttribute = .width, constant:CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 777 | if !translatesAutoresizingMaskIntoConstraints { 778 | _ = pin(.width, to: to, attribute: attribute, constant: constant, multiplier: multiplier, relation: .lessThanOrEqual) 779 | } 780 | return self 781 | } 782 | 783 | /** 784 | Returns the maximun height using Auto Layout 785 | */ 786 | func maxHeight() -> CGFloat? { 787 | if !translatesAutoresizingMaskIntoConstraints { 788 | for constrain in constraints { 789 | if constrain.firstAttribute == .height && constrain.firstItem as! NSObject == self && constrain.secondItem == nil && constrain.relation == .lessThanOrEqual { 790 | return constrain.constant 791 | } 792 | } 793 | } 794 | return nil 795 | } 796 | 797 | /** 798 | Sets the maximun height using Auto Layout 799 | 800 | - Parameter constant: The value to use. 801 | - Returns: self 802 | */ 803 | func maxHeight(_ constant:CGFloat) -> UIView { 804 | if !translatesAutoresizingMaskIntoConstraints { 805 | _ = applyAttribute(.height, constant: constant, multiplier: 1, relation: .lessThanOrEqual) 806 | } 807 | return self 808 | } 809 | 810 | /** 811 | Pins the maximun height to another view using Auto Layout 812 | 813 | - Parameter to: The view to pin to 814 | - Parameter attribute: The attribute to pin to 815 | - Parameter constant: The offset to use after multiplication is done. 816 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 817 | - Returns: self 818 | */ 819 | func maxHeight(to:AnyObject, attribute: NSLayoutAttribute = .height, constant:CGFloat = 0, multiplier:CGFloat = 1) -> UIView { 820 | if !translatesAutoresizingMaskIntoConstraints { 821 | _ = pin(.height, to: to, attribute: attribute, constant: constant, multiplier: multiplier, relation: .lessThanOrEqual) 822 | } 823 | return self 824 | } 825 | 826 | /** 827 | Returns the length of the smallest side 828 | */ 829 | func smallestSideLength() -> CGFloat 830 | { 831 | return min(width(), height()) 832 | } 833 | 834 | /** 835 | Returns the length of the largest side 836 | */ 837 | func largestSideLength() -> CGFloat 838 | { 839 | return max(width(), height()) 840 | } 841 | 842 | 843 | // MARK: AutoLayout state 844 | 845 | /** 846 | Prepares the view for a frame based animation by removing the view, enabling translatesAutoresizingMaskIntoConstraints and re-adding the view to it's superview 847 | */ 848 | func prepForAnimation() 849 | { 850 | if superview != nil { 851 | let aSuperview = superview! 852 | removeFromSuperview() 853 | translatesAutoresizingMaskIntoConstraints = true 854 | aSuperview.addSubview(self) 855 | } 856 | } 857 | 858 | /** 859 | Prepares the view for Auto Layout by removing the view, disabling translatesAutoresizingMaskIntoConstraints and re-adding the view to it's superview 860 | */ 861 | func prepForAutoLayout() 862 | { 863 | if superview != nil { 864 | let aSuperview = superview! 865 | removeFromSuperview() 866 | translatesAutoresizingMaskIntoConstraints = false 867 | aSuperview.addSubview(self) 868 | } 869 | } 870 | 871 | 872 | // MARK: Pin and Apply 873 | 874 | /** 875 | Pins an attribute to another view 876 | 877 | - Parameter pinAttribute: The View's attribut to pin 878 | - Parameter to: The view to pin to 879 | - Parameter attribute: The Attribute to pin to 880 | - Parameter constant: The offset to use after multiplication is done. 881 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 882 | - Parameter relation: The Relation to use 883 | - Returns: NSLayoutConstraint 884 | */ 885 | func pin(_ pinAttribute:NSLayoutAttribute, to:AnyObject? = nil, attribute:NSLayoutAttribute, constant:CGFloat = 0, multiplier:CGFloat = 1, relation:NSLayoutRelation = .equal) -> NSLayoutConstraint? { 886 | if !translatesAutoresizingMaskIntoConstraints { 887 | if self.superview == nil { 888 | print("WARNING: No superview found for pinning") 889 | return nil 890 | } 891 | var superview: UIView! 892 | if (to != nil) { 893 | superview = to is UIView ? commonSuperviewWithView(to! as! UIView)! : self.superview 894 | } else { 895 | superview = self.superview 896 | } 897 | let constraint = NSLayoutConstraint(item: self, attribute: pinAttribute, relatedBy: relation, toItem: to, attribute: attribute, multiplier: multiplier, constant: constant) 898 | superview?.addConstraint(constraint) 899 | return constraint 900 | } 901 | return nil 902 | } 903 | 904 | /** 905 | Applies an attribute to the view 906 | 907 | - Parameter attribute: Attribute to apply 908 | - Parameter constant: The offset to use after multiplication is done. 909 | - Parameter multiplier: The multiplier to use, i.e. 0.5 is half. 910 | - Parameter relation: The Relation to use 911 | - Returns: NSLayoutConstraint 912 | */ 913 | func applyAttribute(_ attribute:NSLayoutAttribute, constant:CGFloat = 0, multiplier: CGFloat = 1, relation:NSLayoutRelation = .equal) -> NSLayoutConstraint { 914 | let constraint = NSLayoutConstraint(item: self, attribute: attribute, relatedBy: relation, toItem: nil, attribute: .notAnAttribute, multiplier: multiplier, constant: constant) 915 | addConstraint(constraint) 916 | return constraint 917 | } 918 | 919 | // MARK: Removing Constraints 920 | 921 | /** 922 | Removes all attached constraints recursevely 923 | 924 | - Returns: self 925 | */ 926 | func removeAttachedConstraintsRecursevely() -> UIView 927 | { 928 | for constraint in constraints { 929 | print("constraint \(constraint)") 930 | _ = removeConstraintRecursevely(constraint ) 931 | } 932 | for constraint in superview!.constraints { 933 | let firstView = constraint.firstItem as! UIView 934 | if let _ = constraint.secondItem as? UIView { 935 | if firstView == self { 936 | _ = firstView.removeConstraintRecursevely(constraint ) 937 | } 938 | } 939 | } 940 | return self 941 | } 942 | 943 | /** 944 | Removes a constraint recursevely 945 | 946 | - Returns: self 947 | */ 948 | func removeConstraintRecursevely(_ constraint:NSLayoutConstraint) -> UIView 949 | { 950 | let firstView = constraint.firstItem as! UIView 951 | if constraint.secondItem != nil { 952 | var commonSuperview = firstView.commonSuperviewWithView(constraint.secondItem as! UIView) 953 | var constraintFound = false 954 | while constraintFound == false { 955 | for _ in commonSuperview!.constraints { 956 | constraintFound = true 957 | } 958 | if constraintFound == true { 959 | commonSuperview!.removeConstraint(constraint) 960 | return self 961 | } 962 | commonSuperview = commonSuperview?.superview 963 | } 964 | } else { 965 | constraint.firstItem.removeConstraint(constraint) 966 | } 967 | return self 968 | } 969 | 970 | 971 | // MARK: Direction 972 | 973 | /** 974 | Returns true if layout direction is left to right 975 | */ 976 | func layoutDirectionIsLeftToRight() -> Bool { 977 | if #available(iOS 10.0, *) { 978 | return (self.effectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirection.leftToRight) 979 | } else { 980 | // TODO: Figure out how to implemet this in IOS9. For now, we wil force left to right layout 981 | return true 982 | } 983 | } 984 | 985 | 986 | 987 | // MARK: Private 988 | 989 | /** 990 | Finds the nearest common superview 991 | 992 | - Returns: UIVIew? 993 | */ 994 | fileprivate func commonSuperviewWithView(_ view:UIView) -> UIView? 995 | { 996 | var commonSuperview: UIView? = nil 997 | var checkView: UIView? = self 998 | repeat { 999 | if view.isDescendant(of: checkView!) { 1000 | commonSuperview = checkView! 1001 | } 1002 | checkView = checkView!.superview 1003 | } while (checkView) != nil 1004 | return commonSuperview 1005 | } 1006 | 1007 | } 1008 | -------------------------------------------------------------------------------- /Sources/ViewControllerAutoLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewControllerAutoLayout.swift 3 | // ViewHelper: Version 4.2.4 4 | // Created by Melvin Rivera on 11/5/15. 5 | // https://github.com/melvitax/ViewHelper 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | public extension UIViewController { 12 | 13 | 14 | /** 15 | Returns true if horizontal size class is compact 16 | */ 17 | func horizontalSizeClassIsCompact() -> Bool 18 | { 19 | return traitCollection.horizontalSizeClass == .compact; 20 | } 21 | 22 | /** 23 | Returns true if vertical size class is compact 24 | */ 25 | func verticalSizeClassIsCompact() -> Bool 26 | { 27 | return traitCollection.verticalSizeClass == .compact; 28 | } 29 | 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Sources/ViewEffects.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewEffects.swift 3 | // ViewHelper: Version 4.2.4 4 | // Created by Melvin Rivera on 7/2/14. 5 | // https://github.com/melvitax/ViewHelper 6 | // 7 | 8 | import UIKit 9 | import QuartzCore 10 | 11 | 12 | 13 | @IBDesignable public extension UIView { 14 | 15 | // MARK: Border 16 | 17 | /** 18 | The layer border color 19 | */ 20 | var borderColor: UIColor { 21 | get { 22 | return layer.borderColor == nil ? UIColor.clear : UIColor(cgColor: layer.borderColor!) 23 | } 24 | set { 25 | layer.borderColor = newValue.cgColor 26 | } 27 | } 28 | 29 | /** 30 | The layer border width 31 | */ 32 | var borderWidth: CGFloat { 33 | get { 34 | return layer.borderWidth 35 | } 36 | set { 37 | layer.borderWidth = newValue 38 | } 39 | } 40 | 41 | 42 | /** 43 | Sets layer border with a dash pattern 44 | 45 | - Parameter lineDashPattern: The dash pattern applied to the shape’s path when stroked. 46 | - Parameter borderWidth: The width of the border. 47 | - Parameter borderColor: The color of the border. 48 | - Parameter cornerRadius: The radius of each corner oval. 49 | - Returns: self 50 | */ 51 | func borderWithDashPattern(_ lineDashPattern: [Int], borderWidth: CGFloat, borderColor: UIColor, cornerRadius: CGFloat?) -> UIView { 52 | let strokeLayer = CAShapeLayer() 53 | strokeLayer.strokeColor = borderColor.cgColor 54 | strokeLayer.fillColor = nil 55 | strokeLayer.lineWidth = borderWidth 56 | strokeLayer.lineDashPattern = lineDashPattern as [NSNumber]? 57 | if cornerRadius != nil { 58 | strokeLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius!).cgPath 59 | } else { 60 | strokeLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: self.cornerRadius).cgPath 61 | } 62 | 63 | strokeLayer.frame = bounds 64 | layer.addSublayer(strokeLayer) 65 | return self 66 | } 67 | 68 | 69 | // MARK: Rounded Corners 70 | 71 | /** 72 | The layer corner radius 73 | */ 74 | var cornerRadius: CGFloat { 75 | get { 76 | return layer.cornerRadius 77 | } 78 | set { 79 | layer.cornerRadius = newValue 80 | layer.masksToBounds = newValue > 0 81 | } 82 | } 83 | 84 | /** 85 | Creates a circle by rounding the corners to half the size of the width, sets border color and width 86 | 87 | - Parameter borderColor: The border color. 88 | - Parameter borderWidth: The border width. 89 | - Returns: self 90 | */ 91 | func roundCornersToCircle(borderColor: UIColor = UIColor.clear, borderWidth: CGFloat = 0) -> UIView { 92 | cornerRadius = width()/2 93 | self.borderWidth = borderWidth 94 | self.borderColor = borderColor 95 | return self 96 | } 97 | 98 | /** 99 | Rounding the corners, sets border color and width 100 | 101 | - Parameter cornerRadius: The radius of each corner oval. 102 | - Parameter borderColor: The border color. 103 | - Parameter borderWidth: The border width. 104 | - Returns: self 105 | */ 106 | func roundCorners(_ cornerRadius: CGFloat, borderColor: UIColor?, borderWidth: CGFloat?) -> UIView { 107 | self.cornerRadius = cornerRadius 108 | if borderWidth != nil { 109 | self.borderWidth = borderWidth! 110 | } 111 | if borderColor != nil { 112 | self.borderColor = borderColor! 113 | } 114 | return self 115 | } 116 | 117 | 118 | // MARK: Shadow 119 | 120 | /** 121 | The shadow color of the layer 122 | */ 123 | var shadowColor: UIColor { 124 | get { 125 | return layer.shadowColor == nil ? UIColor.clear : UIColor(cgColor: layer.shadowColor!) 126 | } 127 | set { 128 | layer.shadowColor = newValue.cgColor 129 | } 130 | } 131 | 132 | 133 | /** 134 | The offset (in points) of the layer’s shadow. 135 | */ 136 | var shadowOffset:CGSize { 137 | get { 138 | return layer.shadowOffset 139 | } 140 | set { 141 | layer.shadowOffset = newValue 142 | } 143 | } 144 | 145 | /** 146 | The shadow opacity of the layer 147 | */ 148 | var shadowOpacity:Float { 149 | get { 150 | return layer.shadowOpacity 151 | } 152 | set { 153 | layer.shadowOpacity = newValue 154 | } 155 | } 156 | 157 | /** 158 | The blur radius (in points) used to render the layer’s shadow. 159 | */ 160 | var shadowRadius:CGFloat { 161 | get { 162 | return layer.shadowRadius 163 | } 164 | set { 165 | layer.shadowRadius = newValue 166 | } 167 | } 168 | 169 | /** 170 | Shortcut for applying shadow. 171 | 172 | - Parameter color: The shadow color. 173 | - Parameter offset: The offset (in points) of the layer’s shadow. 174 | - Parameter radius: The blur radius (in points) used to render the layer’s shadow. 175 | - Parameter opacity: The shadow opacity. 176 | - Parameter isMasked: Indicates if it should be masked. 177 | - Returns: self UIView 178 | */ 179 | func shadow(_ color: UIColor = UIColor.black, offset: CGSize = CGSize(width: 0, height: 0), radius: CGFloat = 6, opacity: Float = 1, isMasked: Bool = false) -> UIView { 180 | shadowColor = color 181 | shadowOffset = offset 182 | shadowOpacity = opacity 183 | shadowRadius = radius 184 | if isMasked { 185 | layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath 186 | let path = CGMutablePath() 187 | path.addRect(bounds.insetBy(dx: -10, dy: -10)) 188 | path.addPath(UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath) 189 | let maskLayer = CAShapeLayer() 190 | maskLayer.path = path 191 | maskLayer.fillRule = kCAFillRuleEvenOdd 192 | layer.mask = maskLayer 193 | } 194 | return self 195 | } 196 | 197 | // MARK: Gradient 198 | 199 | /** 200 | Sets a gradient color layer 201 | 202 | - Parameter colors: Array of colors to use in gradient. 203 | - Parameter isHorizontal: Indicates if gradient is horizontal instead of vertical. 204 | - Returns: self 205 | */ 206 | func setGradient(_ colors: [UIColor], isHorizontal:Bool = false) -> UIView { 207 | let gradientLayer = layer as! CAGradientLayer 208 | gradientLayer.startPoint = isHorizontal ? CGPoint(x: 0.5, y: 0) : CGPoint(x: 0.5, y: 1) 209 | gradientLayer.startPoint = isHorizontal ? CGPoint(x: 0.5, y: 1) : CGPoint(x: 1, y: 0.5) 210 | gradientLayer.colors = colors 211 | return self 212 | } 213 | 214 | /** 215 | Animates colors of a gradient layer 216 | 217 | - Parameter colors: Array of colors to use in gradient. 218 | - Parameter duration: Duration os animation 219 | - Returns: self 220 | */ 221 | func animateGradientToColors(_ colors: [UIColor], duration: CFTimeInterval = 3) -> UIView { 222 | let gradientLayer = layer as! CAGradientLayer 223 | let fromColors = gradientLayer.colors 224 | gradientLayer.colors = colors 225 | let a = CABasicAnimation(keyPath: "colors") 226 | a.fromValue = fromColors 227 | a.toValue = colors 228 | a.duration = duration 229 | a.isRemovedOnCompletion = true 230 | a.fillMode = kCAFillModeForwards 231 | a.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 232 | //a.delegate = self 233 | layer.add(a, forKey: "Gradient Animation") 234 | return self 235 | } 236 | 237 | /** 238 | Sets a gradient layer mask 239 | 240 | - Parameter alphas: Array of alpha values to use for gradient mask. 241 | - Parameter isHorizontal: Indicates if gradient is horizontal instead of vertical. 242 | - Returns: self 243 | */ 244 | func setGradientMask(_ alphas:[CGFloat], isHorizontal:Bool = false) -> UIView { 245 | let gradientLayer = (layer.mask is CAGradientLayer) ? layer.mask as! CAGradientLayer : CAGradientLayer() 246 | var colors = [CGColor]() 247 | for alpha in alphas { 248 | colors.append(UIColor(white: 1, alpha: alpha).cgColor) 249 | } 250 | gradientLayer.startPoint = isHorizontal ? CGPoint(x: 1, y: 0.5) : CGPoint(x: 0.5, y: 1) 251 | gradientLayer.startPoint = isHorizontal ? CGPoint(x: 0, y: 0.5) : CGPoint(x: 0.5, y: 0) 252 | gradientLayer.colors = colors 253 | layer.mask = gradientLayer 254 | return self 255 | } 256 | 257 | 258 | 259 | } 260 | -------------------------------------------------------------------------------- /Sources/ViewHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewHelper iOS.h 3 | // ViewHelper iOS 4 | // 5 | // Created by Melvin Rivera on 9/16/16. 6 | // Copyright © 2016 All Forces. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for ViewHelper iOS. 12 | FOUNDATION_EXPORT double ViewHelperVersionNumber; 13 | 14 | //! Project version string for ViewHelper iOS. 15 | FOUNDATION_EXPORT const unsigned char ViewHelperVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /ViewHelper.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6588DCCB1DE971EB00575329 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6588DCCA1DE971EB00575329 /* TableViewController.swift */; }; 11 | 658FE8F01D92FA0D00CB92F3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658FE8EF1D92FA0D00CB92F3 /* ViewController.swift */; }; 12 | 65D6FA911D8C6874004BAB04 /* ViewHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 65D6FA8F1D8C6802004BAB04 /* ViewHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | 65D6FA931D8C6876004BAB04 /* ViewHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 65D6FA8F1D8C6802004BAB04 /* ViewHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | 65D6FA941D8C689E004BAB04 /* InspectableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4C1D8C66A0004BAB04 /* InspectableButton.swift */; }; 15 | 65D6FA951D8C689E004BAB04 /* InspectableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4D1D8C66A0004BAB04 /* InspectableView.swift */; }; 16 | 65D6FA961D8C689E004BAB04 /* ViewAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4E1D8C66A0004BAB04 /* ViewAnimation.swift */; }; 17 | 65D6FA971D8C689E004BAB04 /* ViewAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4F1D8C66A0004BAB04 /* ViewAutoLayout.swift */; }; 18 | 65D6FA981D8C689E004BAB04 /* ViewControllerAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA501D8C66A0004BAB04 /* ViewControllerAutoLayout.swift */; }; 19 | 65D6FA991D8C689E004BAB04 /* ViewEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA511D8C66A0004BAB04 /* ViewEffects.swift */; }; 20 | 65D6FAA01D8C68A0004BAB04 /* InspectableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4C1D8C66A0004BAB04 /* InspectableButton.swift */; }; 21 | 65D6FAA11D8C68A0004BAB04 /* InspectableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4D1D8C66A0004BAB04 /* InspectableView.swift */; }; 22 | 65D6FAA21D8C68A0004BAB04 /* ViewAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4E1D8C66A0004BAB04 /* ViewAnimation.swift */; }; 23 | 65D6FAA31D8C68A0004BAB04 /* ViewAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4F1D8C66A0004BAB04 /* ViewAutoLayout.swift */; }; 24 | 65D6FAA41D8C68A0004BAB04 /* ViewControllerAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA501D8C66A0004BAB04 /* ViewControllerAutoLayout.swift */; }; 25 | 65D6FAA51D8C68A0004BAB04 /* ViewEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA511D8C66A0004BAB04 /* ViewEffects.swift */; }; 26 | 65D6FAAD1D8C68CF004BAB04 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FAAC1D8C68CF004BAB04 /* AppDelegate.swift */; }; 27 | 65D6FAB41D8C68CF004BAB04 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65D6FAB31D8C68CF004BAB04 /* Assets.xcassets */; }; 28 | 65D6FAB71D8C68CF004BAB04 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65D6FAB51D8C68CF004BAB04 /* LaunchScreen.storyboard */; }; 29 | 65D6FABC1D8C69BF004BAB04 /* InspectableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4C1D8C66A0004BAB04 /* InspectableButton.swift */; }; 30 | 65D6FABD1D8C69BF004BAB04 /* InspectableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4D1D8C66A0004BAB04 /* InspectableView.swift */; }; 31 | 65D6FABE1D8C69BF004BAB04 /* ViewAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4E1D8C66A0004BAB04 /* ViewAnimation.swift */; }; 32 | 65D6FABF1D8C69BF004BAB04 /* ViewAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4F1D8C66A0004BAB04 /* ViewAutoLayout.swift */; }; 33 | 65D6FAC01D8C69BF004BAB04 /* ViewControllerAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA501D8C66A0004BAB04 /* ViewControllerAutoLayout.swift */; }; 34 | 65D6FAC11D8C69BF004BAB04 /* ViewEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA511D8C66A0004BAB04 /* ViewEffects.swift */; }; 35 | 65D6FAC91D8C6C3E004BAB04 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FAC81D8C6C3E004BAB04 /* AppDelegate.swift */; }; 36 | 65D6FACE1D8C6C3E004BAB04 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65D6FACC1D8C6C3E004BAB04 /* Main.storyboard */; }; 37 | 65D6FAD01D8C6C3E004BAB04 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65D6FACF1D8C6C3E004BAB04 /* Assets.xcassets */; }; 38 | 65D6FAD61D8C73BD004BAB04 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65D6FAD51D8C73BD004BAB04 /* Main.storyboard */; }; 39 | 65D6FAD91D8C76A9004BAB04 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FACA1D8C6C3E004BAB04 /* ViewController.swift */; }; 40 | 65D6FADA1D8C7CDB004BAB04 /* InspectableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4C1D8C66A0004BAB04 /* InspectableButton.swift */; }; 41 | 65D6FADB1D8C7CDB004BAB04 /* InspectableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4D1D8C66A0004BAB04 /* InspectableView.swift */; }; 42 | 65D6FADC1D8C7CDB004BAB04 /* ViewAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4E1D8C66A0004BAB04 /* ViewAnimation.swift */; }; 43 | 65D6FADD1D8C7CDB004BAB04 /* ViewAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA4F1D8C66A0004BAB04 /* ViewAutoLayout.swift */; }; 44 | 65D6FADE1D8C7CDB004BAB04 /* ViewControllerAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA501D8C66A0004BAB04 /* ViewControllerAutoLayout.swift */; }; 45 | 65D6FADF1D8C7CDB004BAB04 /* ViewEffects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D6FA511D8C66A0004BAB04 /* ViewEffects.swift */; }; 46 | /* End PBXBuildFile section */ 47 | 48 | /* Begin PBXFileReference section */ 49 | 655AEB42192D42990053AD6C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 50 | 655AEB44192D42990053AD6C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 51 | 655AEB46192D42990053AD6C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 52 | 655AEB64192D429A0053AD6C /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 53 | 6588DCCA1DE971EB00575329 /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; 54 | 658FE8EF1D92FA0D00CB92F3 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 55 | 65B7EA75197082AA0097E598 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 56 | 65D016A319771FD1005220FB /* AFViewHelper.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = AFViewHelper.podspec; sourceTree = ""; }; 57 | 65D6FA4C1D8C66A0004BAB04 /* InspectableButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectableButton.swift; sourceTree = ""; }; 58 | 65D6FA4D1D8C66A0004BAB04 /* InspectableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectableView.swift; sourceTree = ""; }; 59 | 65D6FA4E1D8C66A0004BAB04 /* ViewAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewAnimation.swift; sourceTree = ""; }; 60 | 65D6FA4F1D8C66A0004BAB04 /* ViewAutoLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewAutoLayout.swift; sourceTree = ""; }; 61 | 65D6FA501D8C66A0004BAB04 /* ViewControllerAutoLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewControllerAutoLayout.swift; sourceTree = ""; }; 62 | 65D6FA511D8C66A0004BAB04 /* ViewEffects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewEffects.swift; sourceTree = ""; }; 63 | 65D6FA6A1D8C673E004BAB04 /* ViewHelper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ViewHelper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | 65D6FA841D8C675E004BAB04 /* ViewHelper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ViewHelper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 65D6FA8C1D8C6802004BAB04 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 66 | 65D6FA8D1D8C6802004BAB04 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; 67 | 65D6FA8F1D8C6802004BAB04 /* ViewHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewHelper.h; sourceTree = ""; }; 68 | 65D6FAAA1D8C68CF004BAB04 /* ViewHelperDemo iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ViewHelperDemo iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 69 | 65D6FAAC1D8C68CF004BAB04 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 70 | 65D6FAB31D8C68CF004BAB04 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 71 | 65D6FAB61D8C68CF004BAB04 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 72 | 65D6FAB81D8C68CF004BAB04 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | 65D6FAC61D8C6C3E004BAB04 /* ViewHelperDemo tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ViewHelperDemo tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | 65D6FAC81D8C6C3E004BAB04 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 75 | 65D6FACA1D8C6C3E004BAB04 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 76 | 65D6FACD1D8C6C3E004BAB04 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 77 | 65D6FACF1D8C6C3E004BAB04 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 78 | 65D6FAD11D8C6C3E004BAB04 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 79 | 65D6FAD51D8C73BD004BAB04 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 80 | /* End PBXFileReference section */ 81 | 82 | /* Begin PBXFrameworksBuildPhase section */ 83 | 65D6FA661D8C673E004BAB04 /* Frameworks */ = { 84 | isa = PBXFrameworksBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | 65D6FA801D8C675E004BAB04 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 65D6FAA71D8C68CF004BAB04 /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | 65D6FAC31D8C6C3E004BAB04 /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXFrameworksBuildPhase section */ 112 | 113 | /* Begin PBXGroup section */ 114 | 655AEB36192D42990053AD6C = { 115 | isa = PBXGroup; 116 | children = ( 117 | 65D6FA4B1D8C66A0004BAB04 /* Sources */, 118 | 65B7EA75197082AA0097E598 /* README.md */, 119 | 65D016A319771FD1005220FB /* AFViewHelper.podspec */, 120 | 65D6FAAB1D8C68CF004BAB04 /* Demo iOS */, 121 | 65D6FAC71D8C6C3E004BAB04 /* Demo tvOS */, 122 | 655AEB41192D42990053AD6C /* Frameworks */, 123 | 655AEB40192D42990053AD6C /* Products */, 124 | ); 125 | sourceTree = ""; 126 | }; 127 | 655AEB40192D42990053AD6C /* Products */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 65D6FA6A1D8C673E004BAB04 /* ViewHelper.framework */, 131 | 65D6FA841D8C675E004BAB04 /* ViewHelper.framework */, 132 | 65D6FAAA1D8C68CF004BAB04 /* ViewHelperDemo iOS.app */, 133 | 65D6FAC61D8C6C3E004BAB04 /* ViewHelperDemo tvOS.app */, 134 | ); 135 | name = Products; 136 | sourceTree = ""; 137 | }; 138 | 655AEB41192D42990053AD6C /* Frameworks */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 655AEB42192D42990053AD6C /* Foundation.framework */, 142 | 655AEB44192D42990053AD6C /* CoreGraphics.framework */, 143 | 655AEB46192D42990053AD6C /* UIKit.framework */, 144 | 655AEB64192D429A0053AD6C /* XCTest.framework */, 145 | ); 146 | name = Frameworks; 147 | sourceTree = ""; 148 | }; 149 | 65D6FA4B1D8C66A0004BAB04 /* Sources */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 65D6FA4C1D8C66A0004BAB04 /* InspectableButton.swift */, 153 | 65D6FA4D1D8C66A0004BAB04 /* InspectableView.swift */, 154 | 65D6FA4E1D8C66A0004BAB04 /* ViewAnimation.swift */, 155 | 65D6FA4F1D8C66A0004BAB04 /* ViewAutoLayout.swift */, 156 | 65D6FA501D8C66A0004BAB04 /* ViewControllerAutoLayout.swift */, 157 | 65D6FA511D8C66A0004BAB04 /* ViewEffects.swift */, 158 | 65D6FA8C1D8C6802004BAB04 /* Info-iOS.plist */, 159 | 65D6FA8D1D8C6802004BAB04 /* Info-tvOS.plist */, 160 | 65D6FA8F1D8C6802004BAB04 /* ViewHelper.h */, 161 | ); 162 | path = Sources; 163 | sourceTree = ""; 164 | }; 165 | 65D6FAAB1D8C68CF004BAB04 /* Demo iOS */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 65D6FAAC1D8C68CF004BAB04 /* AppDelegate.swift */, 169 | 658FE8EF1D92FA0D00CB92F3 /* ViewController.swift */, 170 | 65D6FAB31D8C68CF004BAB04 /* Assets.xcassets */, 171 | 65D6FAD51D8C73BD004BAB04 /* Main.storyboard */, 172 | 65D6FAB51D8C68CF004BAB04 /* LaunchScreen.storyboard */, 173 | 65D6FAB81D8C68CF004BAB04 /* Info.plist */, 174 | ); 175 | name = "Demo iOS"; 176 | path = "ViewHelperDemo iOS"; 177 | sourceTree = ""; 178 | }; 179 | 65D6FAC71D8C6C3E004BAB04 /* Demo tvOS */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 65D6FAC81D8C6C3E004BAB04 /* AppDelegate.swift */, 183 | 65D6FACA1D8C6C3E004BAB04 /* ViewController.swift */, 184 | 6588DCCA1DE971EB00575329 /* TableViewController.swift */, 185 | 65D6FACC1D8C6C3E004BAB04 /* Main.storyboard */, 186 | 65D6FACF1D8C6C3E004BAB04 /* Assets.xcassets */, 187 | 65D6FAD11D8C6C3E004BAB04 /* Info.plist */, 188 | ); 189 | name = "Demo tvOS"; 190 | path = "ViewHelperDemo tvOS"; 191 | sourceTree = ""; 192 | }; 193 | /* End PBXGroup section */ 194 | 195 | /* Begin PBXHeadersBuildPhase section */ 196 | 65D6FA671D8C673E004BAB04 /* Headers */ = { 197 | isa = PBXHeadersBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | 65D6FA911D8C6874004BAB04 /* ViewHelper.h in Headers */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | 65D6FA811D8C675E004BAB04 /* Headers */ = { 205 | isa = PBXHeadersBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | 65D6FA931D8C6876004BAB04 /* ViewHelper.h in Headers */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXHeadersBuildPhase section */ 213 | 214 | /* Begin PBXNativeTarget section */ 215 | 65D6FA691D8C673E004BAB04 /* ViewHelper iOS */ = { 216 | isa = PBXNativeTarget; 217 | buildConfigurationList = 65D6FA6F1D8C673E004BAB04 /* Build configuration list for PBXNativeTarget "ViewHelper iOS" */; 218 | buildPhases = ( 219 | 65D6FA651D8C673E004BAB04 /* Sources */, 220 | 65D6FA661D8C673E004BAB04 /* Frameworks */, 221 | 65D6FA671D8C673E004BAB04 /* Headers */, 222 | 65D6FA681D8C673E004BAB04 /* Resources */, 223 | ); 224 | buildRules = ( 225 | ); 226 | dependencies = ( 227 | ); 228 | name = "ViewHelper iOS"; 229 | productName = "ViewHelper iOS"; 230 | productReference = 65D6FA6A1D8C673E004BAB04 /* ViewHelper.framework */; 231 | productType = "com.apple.product-type.framework"; 232 | }; 233 | 65D6FA831D8C675E004BAB04 /* ViewHelper tvOS */ = { 234 | isa = PBXNativeTarget; 235 | buildConfigurationList = 65D6FA891D8C675E004BAB04 /* Build configuration list for PBXNativeTarget "ViewHelper tvOS" */; 236 | buildPhases = ( 237 | 65D6FA7F1D8C675E004BAB04 /* Sources */, 238 | 65D6FA801D8C675E004BAB04 /* Frameworks */, 239 | 65D6FA811D8C675E004BAB04 /* Headers */, 240 | 65D6FA821D8C675E004BAB04 /* Resources */, 241 | ); 242 | buildRules = ( 243 | ); 244 | dependencies = ( 245 | ); 246 | name = "ViewHelper tvOS"; 247 | productName = "ViewHelper tvOS"; 248 | productReference = 65D6FA841D8C675E004BAB04 /* ViewHelper.framework */; 249 | productType = "com.apple.product-type.framework"; 250 | }; 251 | 65D6FAA91D8C68CF004BAB04 /* ViewHelperDemo iOS */ = { 252 | isa = PBXNativeTarget; 253 | buildConfigurationList = 65D6FAB91D8C68CF004BAB04 /* Build configuration list for PBXNativeTarget "ViewHelperDemo iOS" */; 254 | buildPhases = ( 255 | 65D6FAA61D8C68CF004BAB04 /* Sources */, 256 | 65D6FAA71D8C68CF004BAB04 /* Frameworks */, 257 | 65D6FAA81D8C68CF004BAB04 /* Resources */, 258 | ); 259 | buildRules = ( 260 | ); 261 | dependencies = ( 262 | ); 263 | name = "ViewHelperDemo iOS"; 264 | productName = "ViewHelperDemo iOS"; 265 | productReference = 65D6FAAA1D8C68CF004BAB04 /* ViewHelperDemo iOS.app */; 266 | productType = "com.apple.product-type.application"; 267 | }; 268 | 65D6FAC51D8C6C3E004BAB04 /* ViewHelperDemo tvOS */ = { 269 | isa = PBXNativeTarget; 270 | buildConfigurationList = 65D6FAD21D8C6C3E004BAB04 /* Build configuration list for PBXNativeTarget "ViewHelperDemo tvOS" */; 271 | buildPhases = ( 272 | 65D6FAC21D8C6C3E004BAB04 /* Sources */, 273 | 65D6FAC31D8C6C3E004BAB04 /* Frameworks */, 274 | 65D6FAC41D8C6C3E004BAB04 /* Resources */, 275 | ); 276 | buildRules = ( 277 | ); 278 | dependencies = ( 279 | ); 280 | name = "ViewHelperDemo tvOS"; 281 | productName = "ViewHelperDemo tvOS"; 282 | productReference = 65D6FAC61D8C6C3E004BAB04 /* ViewHelperDemo tvOS.app */; 283 | productType = "com.apple.product-type.application"; 284 | }; 285 | /* End PBXNativeTarget section */ 286 | 287 | /* Begin PBXProject section */ 288 | 655AEB37192D42990053AD6C /* Project object */ = { 289 | isa = PBXProject; 290 | attributes = { 291 | LastSwiftMigration = 0700; 292 | LastSwiftUpdateCheck = 0800; 293 | LastUpgradeCheck = 0800; 294 | ORGANIZATIONNAME = "All Forces"; 295 | TargetAttributes = { 296 | 65D6FA691D8C673E004BAB04 = { 297 | CreatedOnToolsVersion = 8.0; 298 | ProvisioningStyle = Automatic; 299 | }; 300 | 65D6FA831D8C675E004BAB04 = { 301 | CreatedOnToolsVersion = 8.0; 302 | ProvisioningStyle = Automatic; 303 | }; 304 | 65D6FAA91D8C68CF004BAB04 = { 305 | CreatedOnToolsVersion = 8.0; 306 | ProvisioningStyle = Automatic; 307 | }; 308 | 65D6FAC51D8C6C3E004BAB04 = { 309 | CreatedOnToolsVersion = 8.0; 310 | ProvisioningStyle = Automatic; 311 | }; 312 | }; 313 | }; 314 | buildConfigurationList = 655AEB3A192D42990053AD6C /* Build configuration list for PBXProject "ViewHelper" */; 315 | compatibilityVersion = "Xcode 3.2"; 316 | developmentRegion = English; 317 | hasScannedForEncodings = 0; 318 | knownRegions = ( 319 | en, 320 | Base, 321 | ); 322 | mainGroup = 655AEB36192D42990053AD6C; 323 | productRefGroup = 655AEB40192D42990053AD6C /* Products */; 324 | projectDirPath = ""; 325 | projectRoot = ""; 326 | targets = ( 327 | 65D6FAA91D8C68CF004BAB04 /* ViewHelperDemo iOS */, 328 | 65D6FAC51D8C6C3E004BAB04 /* ViewHelperDemo tvOS */, 329 | 65D6FA691D8C673E004BAB04 /* ViewHelper iOS */, 330 | 65D6FA831D8C675E004BAB04 /* ViewHelper tvOS */, 331 | ); 332 | }; 333 | /* End PBXProject section */ 334 | 335 | /* Begin PBXResourcesBuildPhase section */ 336 | 65D6FA681D8C673E004BAB04 /* Resources */ = { 337 | isa = PBXResourcesBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | 65D6FA821D8C675E004BAB04 /* Resources */ = { 344 | isa = PBXResourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | ); 348 | runOnlyForDeploymentPostprocessing = 0; 349 | }; 350 | 65D6FAA81D8C68CF004BAB04 /* Resources */ = { 351 | isa = PBXResourcesBuildPhase; 352 | buildActionMask = 2147483647; 353 | files = ( 354 | 65D6FAD61D8C73BD004BAB04 /* Main.storyboard in Resources */, 355 | 65D6FAB71D8C68CF004BAB04 /* LaunchScreen.storyboard in Resources */, 356 | 65D6FAB41D8C68CF004BAB04 /* Assets.xcassets in Resources */, 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | 65D6FAC41D8C6C3E004BAB04 /* Resources */ = { 361 | isa = PBXResourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | 65D6FAD01D8C6C3E004BAB04 /* Assets.xcassets in Resources */, 365 | 65D6FACE1D8C6C3E004BAB04 /* Main.storyboard in Resources */, 366 | ); 367 | runOnlyForDeploymentPostprocessing = 0; 368 | }; 369 | /* End PBXResourcesBuildPhase section */ 370 | 371 | /* Begin PBXSourcesBuildPhase section */ 372 | 65D6FA651D8C673E004BAB04 /* Sources */ = { 373 | isa = PBXSourcesBuildPhase; 374 | buildActionMask = 2147483647; 375 | files = ( 376 | 65D6FAA21D8C68A0004BAB04 /* ViewAnimation.swift in Sources */, 377 | 65D6FAA11D8C68A0004BAB04 /* InspectableView.swift in Sources */, 378 | 65D6FAA41D8C68A0004BAB04 /* ViewControllerAutoLayout.swift in Sources */, 379 | 65D6FAA31D8C68A0004BAB04 /* ViewAutoLayout.swift in Sources */, 380 | 65D6FAA51D8C68A0004BAB04 /* ViewEffects.swift in Sources */, 381 | 65D6FAA01D8C68A0004BAB04 /* InspectableButton.swift in Sources */, 382 | ); 383 | runOnlyForDeploymentPostprocessing = 0; 384 | }; 385 | 65D6FA7F1D8C675E004BAB04 /* Sources */ = { 386 | isa = PBXSourcesBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | 65D6FA961D8C689E004BAB04 /* ViewAnimation.swift in Sources */, 390 | 65D6FA951D8C689E004BAB04 /* InspectableView.swift in Sources */, 391 | 65D6FA981D8C689E004BAB04 /* ViewControllerAutoLayout.swift in Sources */, 392 | 65D6FA971D8C689E004BAB04 /* ViewAutoLayout.swift in Sources */, 393 | 65D6FA991D8C689E004BAB04 /* ViewEffects.swift in Sources */, 394 | 65D6FA941D8C689E004BAB04 /* InspectableButton.swift in Sources */, 395 | ); 396 | runOnlyForDeploymentPostprocessing = 0; 397 | }; 398 | 65D6FAA61D8C68CF004BAB04 /* Sources */ = { 399 | isa = PBXSourcesBuildPhase; 400 | buildActionMask = 2147483647; 401 | files = ( 402 | 65D6FAC11D8C69BF004BAB04 /* ViewEffects.swift in Sources */, 403 | 65D6FABC1D8C69BF004BAB04 /* InspectableButton.swift in Sources */, 404 | 65D6FABD1D8C69BF004BAB04 /* InspectableView.swift in Sources */, 405 | 65D6FAC01D8C69BF004BAB04 /* ViewControllerAutoLayout.swift in Sources */, 406 | 65D6FABE1D8C69BF004BAB04 /* ViewAnimation.swift in Sources */, 407 | 65D6FABF1D8C69BF004BAB04 /* ViewAutoLayout.swift in Sources */, 408 | 658FE8F01D92FA0D00CB92F3 /* ViewController.swift in Sources */, 409 | 65D6FAAD1D8C68CF004BAB04 /* AppDelegate.swift in Sources */, 410 | ); 411 | runOnlyForDeploymentPostprocessing = 0; 412 | }; 413 | 65D6FAC21D8C6C3E004BAB04 /* Sources */ = { 414 | isa = PBXSourcesBuildPhase; 415 | buildActionMask = 2147483647; 416 | files = ( 417 | 65D6FADF1D8C7CDB004BAB04 /* ViewEffects.swift in Sources */, 418 | 65D6FAD91D8C76A9004BAB04 /* ViewController.swift in Sources */, 419 | 65D6FADA1D8C7CDB004BAB04 /* InspectableButton.swift in Sources */, 420 | 6588DCCB1DE971EB00575329 /* TableViewController.swift in Sources */, 421 | 65D6FADB1D8C7CDB004BAB04 /* InspectableView.swift in Sources */, 422 | 65D6FADE1D8C7CDB004BAB04 /* ViewControllerAutoLayout.swift in Sources */, 423 | 65D6FADC1D8C7CDB004BAB04 /* ViewAnimation.swift in Sources */, 424 | 65D6FADD1D8C7CDB004BAB04 /* ViewAutoLayout.swift in Sources */, 425 | 65D6FAC91D8C6C3E004BAB04 /* AppDelegate.swift in Sources */, 426 | ); 427 | runOnlyForDeploymentPostprocessing = 0; 428 | }; 429 | /* End PBXSourcesBuildPhase section */ 430 | 431 | /* Begin PBXVariantGroup section */ 432 | 65D6FAB51D8C68CF004BAB04 /* LaunchScreen.storyboard */ = { 433 | isa = PBXVariantGroup; 434 | children = ( 435 | 65D6FAB61D8C68CF004BAB04 /* Base */, 436 | ); 437 | name = LaunchScreen.storyboard; 438 | sourceTree = ""; 439 | }; 440 | 65D6FACC1D8C6C3E004BAB04 /* Main.storyboard */ = { 441 | isa = PBXVariantGroup; 442 | children = ( 443 | 65D6FACD1D8C6C3E004BAB04 /* Base */, 444 | ); 445 | name = Main.storyboard; 446 | sourceTree = ""; 447 | }; 448 | /* End PBXVariantGroup section */ 449 | 450 | /* Begin XCBuildConfiguration section */ 451 | 655AEB72192D429A0053AD6C /* Debug */ = { 452 | isa = XCBuildConfiguration; 453 | buildSettings = { 454 | ALWAYS_SEARCH_USER_PATHS = NO; 455 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 456 | CLANG_CXX_LIBRARY = "libc++"; 457 | CLANG_ENABLE_MODULES = YES; 458 | CLANG_ENABLE_OBJC_ARC = YES; 459 | CLANG_WARN_BOOL_CONVERSION = YES; 460 | CLANG_WARN_CONSTANT_CONVERSION = YES; 461 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 462 | CLANG_WARN_EMPTY_BODY = YES; 463 | CLANG_WARN_ENUM_CONVERSION = YES; 464 | CLANG_WARN_INFINITE_RECURSION = YES; 465 | CLANG_WARN_INT_CONVERSION = YES; 466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 467 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 468 | CLANG_WARN_UNREACHABLE_CODE = YES; 469 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 470 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 471 | COPY_PHASE_STRIP = NO; 472 | ENABLE_STRICT_OBJC_MSGSEND = YES; 473 | ENABLE_TESTABILITY = YES; 474 | GCC_C_LANGUAGE_STANDARD = gnu99; 475 | GCC_DYNAMIC_NO_PIC = NO; 476 | GCC_NO_COMMON_BLOCKS = YES; 477 | GCC_OPTIMIZATION_LEVEL = 0; 478 | GCC_PREPROCESSOR_DEFINITIONS = ( 479 | "DEBUG=1", 480 | "$(inherited)", 481 | ); 482 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 483 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 484 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 485 | GCC_WARN_UNDECLARED_SELECTOR = YES; 486 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 487 | GCC_WARN_UNUSED_FUNCTION = YES; 488 | GCC_WARN_UNUSED_VARIABLE = YES; 489 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 490 | ONLY_ACTIVE_ARCH = YES; 491 | SDKROOT = iphoneos; 492 | TARGETED_DEVICE_FAMILY = "1,2"; 493 | }; 494 | name = Debug; 495 | }; 496 | 655AEB73192D429A0053AD6C /* Release */ = { 497 | isa = XCBuildConfiguration; 498 | buildSettings = { 499 | ALWAYS_SEARCH_USER_PATHS = NO; 500 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 501 | CLANG_CXX_LIBRARY = "libc++"; 502 | CLANG_ENABLE_MODULES = YES; 503 | CLANG_ENABLE_OBJC_ARC = YES; 504 | CLANG_WARN_BOOL_CONVERSION = YES; 505 | CLANG_WARN_CONSTANT_CONVERSION = YES; 506 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 507 | CLANG_WARN_EMPTY_BODY = YES; 508 | CLANG_WARN_ENUM_CONVERSION = YES; 509 | CLANG_WARN_INFINITE_RECURSION = YES; 510 | CLANG_WARN_INT_CONVERSION = YES; 511 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 512 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 513 | CLANG_WARN_UNREACHABLE_CODE = YES; 514 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 515 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 516 | COPY_PHASE_STRIP = YES; 517 | ENABLE_NS_ASSERTIONS = NO; 518 | ENABLE_STRICT_OBJC_MSGSEND = YES; 519 | GCC_C_LANGUAGE_STANDARD = gnu99; 520 | GCC_NO_COMMON_BLOCKS = YES; 521 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 522 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 523 | GCC_WARN_UNDECLARED_SELECTOR = YES; 524 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 525 | GCC_WARN_UNUSED_FUNCTION = YES; 526 | GCC_WARN_UNUSED_VARIABLE = YES; 527 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 528 | SDKROOT = iphoneos; 529 | TARGETED_DEVICE_FAMILY = "1,2"; 530 | VALIDATE_PRODUCT = YES; 531 | }; 532 | name = Release; 533 | }; 534 | 65D6FA701D8C673E004BAB04 /* Debug */ = { 535 | isa = XCBuildConfiguration; 536 | buildSettings = { 537 | APPLICATION_EXTENSION_API_ONLY = YES; 538 | CLANG_ANALYZER_NONNULL = YES; 539 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 540 | CLANG_WARN_INFINITE_RECURSION = YES; 541 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 542 | CLANG_WARN_UNREACHABLE_CODE = YES; 543 | CODE_SIGN_IDENTITY = ""; 544 | CURRENT_PROJECT_VERSION = 1; 545 | DEBUG_INFORMATION_FORMAT = dwarf; 546 | DEFINES_MODULE = YES; 547 | DYLIB_COMPATIBILITY_VERSION = 1; 548 | DYLIB_CURRENT_VERSION = 1; 549 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 550 | ENABLE_STRICT_OBJC_MSGSEND = YES; 551 | GCC_NO_COMMON_BLOCKS = YES; 552 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist"; 553 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 554 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 555 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 556 | MTL_ENABLE_DEBUG_INFO = YES; 557 | PRODUCT_BUNDLE_IDENTIFIER = "com.allforces.ViewHelper-iOS"; 558 | PRODUCT_NAME = ViewHelper; 559 | SKIP_INSTALL = YES; 560 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 561 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 562 | SWIFT_VERSION = 3.0; 563 | TVOS_DEPLOYMENT_TARGET = 10.0; 564 | VERSIONING_SYSTEM = "apple-generic"; 565 | VERSION_INFO_PREFIX = ""; 566 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 567 | }; 568 | name = Debug; 569 | }; 570 | 65D6FA711D8C673E004BAB04 /* Release */ = { 571 | isa = XCBuildConfiguration; 572 | buildSettings = { 573 | APPLICATION_EXTENSION_API_ONLY = YES; 574 | CLANG_ANALYZER_NONNULL = YES; 575 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 576 | CLANG_WARN_INFINITE_RECURSION = YES; 577 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 578 | CLANG_WARN_UNREACHABLE_CODE = YES; 579 | CODE_SIGN_IDENTITY = ""; 580 | COPY_PHASE_STRIP = NO; 581 | CURRENT_PROJECT_VERSION = 1; 582 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 583 | DEFINES_MODULE = YES; 584 | DYLIB_COMPATIBILITY_VERSION = 1; 585 | DYLIB_CURRENT_VERSION = 1; 586 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 587 | ENABLE_STRICT_OBJC_MSGSEND = YES; 588 | GCC_NO_COMMON_BLOCKS = YES; 589 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist"; 590 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 591 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 592 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 593 | MTL_ENABLE_DEBUG_INFO = NO; 594 | PRODUCT_BUNDLE_IDENTIFIER = "com.allforces.ViewHelper-iOS"; 595 | PRODUCT_NAME = ViewHelper; 596 | SKIP_INSTALL = YES; 597 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 598 | SWIFT_VERSION = 3.0; 599 | TVOS_DEPLOYMENT_TARGET = 10.0; 600 | VERSIONING_SYSTEM = "apple-generic"; 601 | VERSION_INFO_PREFIX = ""; 602 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 603 | }; 604 | name = Release; 605 | }; 606 | 65D6FA8A1D8C675E004BAB04 /* Debug */ = { 607 | isa = XCBuildConfiguration; 608 | buildSettings = { 609 | APPLICATION_EXTENSION_API_ONLY = YES; 610 | CLANG_ANALYZER_NONNULL = YES; 611 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 612 | CLANG_WARN_INFINITE_RECURSION = YES; 613 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 614 | CLANG_WARN_UNREACHABLE_CODE = YES; 615 | CODE_SIGN_IDENTITY = ""; 616 | CURRENT_PROJECT_VERSION = 1; 617 | DEBUG_INFORMATION_FORMAT = dwarf; 618 | DEFINES_MODULE = YES; 619 | DYLIB_COMPATIBILITY_VERSION = 1; 620 | DYLIB_CURRENT_VERSION = 1; 621 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 622 | ENABLE_STRICT_OBJC_MSGSEND = YES; 623 | GCC_NO_COMMON_BLOCKS = YES; 624 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist"; 625 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 626 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 627 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 628 | MTL_ENABLE_DEBUG_INFO = YES; 629 | PRODUCT_BUNDLE_IDENTIFIER = "com.allforces.ViewHelper-tvOS"; 630 | PRODUCT_NAME = ViewHelper; 631 | SDKROOT = appletvos; 632 | SKIP_INSTALL = YES; 633 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 634 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 635 | SWIFT_VERSION = 3.0; 636 | TARGETED_DEVICE_FAMILY = 3; 637 | TVOS_DEPLOYMENT_TARGET = 10.0; 638 | VERSIONING_SYSTEM = "apple-generic"; 639 | VERSION_INFO_PREFIX = ""; 640 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 641 | }; 642 | name = Debug; 643 | }; 644 | 65D6FA8B1D8C675E004BAB04 /* Release */ = { 645 | isa = XCBuildConfiguration; 646 | buildSettings = { 647 | APPLICATION_EXTENSION_API_ONLY = YES; 648 | CLANG_ANALYZER_NONNULL = YES; 649 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 650 | CLANG_WARN_INFINITE_RECURSION = YES; 651 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 652 | CLANG_WARN_UNREACHABLE_CODE = YES; 653 | CODE_SIGN_IDENTITY = ""; 654 | COPY_PHASE_STRIP = NO; 655 | CURRENT_PROJECT_VERSION = 1; 656 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 657 | DEFINES_MODULE = YES; 658 | DYLIB_COMPATIBILITY_VERSION = 1; 659 | DYLIB_CURRENT_VERSION = 1; 660 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 661 | ENABLE_STRICT_OBJC_MSGSEND = YES; 662 | GCC_NO_COMMON_BLOCKS = YES; 663 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist"; 664 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 665 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 666 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 667 | MTL_ENABLE_DEBUG_INFO = NO; 668 | PRODUCT_BUNDLE_IDENTIFIER = "com.allforces.ViewHelper-tvOS"; 669 | PRODUCT_NAME = ViewHelper; 670 | SDKROOT = appletvos; 671 | SKIP_INSTALL = YES; 672 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 673 | SWIFT_VERSION = 3.0; 674 | TARGETED_DEVICE_FAMILY = 3; 675 | TVOS_DEPLOYMENT_TARGET = 10.0; 676 | VERSIONING_SYSTEM = "apple-generic"; 677 | VERSION_INFO_PREFIX = ""; 678 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 679 | }; 680 | name = Release; 681 | }; 682 | 65D6FABA1D8C68CF004BAB04 /* Debug */ = { 683 | isa = XCBuildConfiguration; 684 | buildSettings = { 685 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 686 | CLANG_ANALYZER_NONNULL = YES; 687 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 688 | CLANG_WARN_INFINITE_RECURSION = YES; 689 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 690 | CLANG_WARN_UNREACHABLE_CODE = YES; 691 | DEBUG_INFORMATION_FORMAT = dwarf; 692 | ENABLE_STRICT_OBJC_MSGSEND = YES; 693 | GCC_NO_COMMON_BLOCKS = YES; 694 | INFOPLIST_FILE = "ViewHelperDemo iOS/Info.plist"; 695 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 696 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 697 | MTL_ENABLE_DEBUG_INFO = YES; 698 | PRODUCT_BUNDLE_IDENTIFIER = "com.allforces.ViewHelperDemo-iOS"; 699 | PRODUCT_NAME = "$(TARGET_NAME)"; 700 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 701 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 702 | SWIFT_VERSION = 3.0; 703 | }; 704 | name = Debug; 705 | }; 706 | 65D6FABB1D8C68CF004BAB04 /* Release */ = { 707 | isa = XCBuildConfiguration; 708 | buildSettings = { 709 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 710 | CLANG_ANALYZER_NONNULL = YES; 711 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 712 | CLANG_WARN_INFINITE_RECURSION = YES; 713 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 714 | CLANG_WARN_UNREACHABLE_CODE = YES; 715 | COPY_PHASE_STRIP = NO; 716 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 717 | ENABLE_STRICT_OBJC_MSGSEND = YES; 718 | GCC_NO_COMMON_BLOCKS = YES; 719 | INFOPLIST_FILE = "ViewHelperDemo iOS/Info.plist"; 720 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 721 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 722 | MTL_ENABLE_DEBUG_INFO = NO; 723 | PRODUCT_BUNDLE_IDENTIFIER = "com.allforces.ViewHelperDemo-iOS"; 724 | PRODUCT_NAME = "$(TARGET_NAME)"; 725 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 726 | SWIFT_VERSION = 3.0; 727 | }; 728 | name = Release; 729 | }; 730 | 65D6FAD31D8C6C3E004BAB04 /* Debug */ = { 731 | isa = XCBuildConfiguration; 732 | buildSettings = { 733 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; 734 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 735 | CLANG_ANALYZER_NONNULL = YES; 736 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 737 | CLANG_WARN_INFINITE_RECURSION = YES; 738 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 739 | CLANG_WARN_UNREACHABLE_CODE = YES; 740 | DEBUG_INFORMATION_FORMAT = dwarf; 741 | ENABLE_STRICT_OBJC_MSGSEND = YES; 742 | GCC_NO_COMMON_BLOCKS = YES; 743 | INFOPLIST_FILE = "ViewHelperDemo tvOS/Info.plist"; 744 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 745 | MTL_ENABLE_DEBUG_INFO = YES; 746 | PRODUCT_BUNDLE_IDENTIFIER = "com.allforces.ViewHelperDemo-tvOS"; 747 | PRODUCT_NAME = "$(TARGET_NAME)"; 748 | SDKROOT = appletvos; 749 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 750 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 751 | SWIFT_VERSION = 3.0; 752 | TARGETED_DEVICE_FAMILY = 3; 753 | TVOS_DEPLOYMENT_TARGET = 10.0; 754 | }; 755 | name = Debug; 756 | }; 757 | 65D6FAD41D8C6C3E004BAB04 /* Release */ = { 758 | isa = XCBuildConfiguration; 759 | buildSettings = { 760 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; 761 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 762 | CLANG_ANALYZER_NONNULL = YES; 763 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 764 | CLANG_WARN_INFINITE_RECURSION = YES; 765 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 766 | CLANG_WARN_UNREACHABLE_CODE = YES; 767 | COPY_PHASE_STRIP = NO; 768 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 769 | ENABLE_STRICT_OBJC_MSGSEND = YES; 770 | GCC_NO_COMMON_BLOCKS = YES; 771 | INFOPLIST_FILE = "ViewHelperDemo tvOS/Info.plist"; 772 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 773 | MTL_ENABLE_DEBUG_INFO = NO; 774 | PRODUCT_BUNDLE_IDENTIFIER = "com.allforces.ViewHelperDemo-tvOS"; 775 | PRODUCT_NAME = "$(TARGET_NAME)"; 776 | SDKROOT = appletvos; 777 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 778 | SWIFT_VERSION = 3.0; 779 | TARGETED_DEVICE_FAMILY = 3; 780 | TVOS_DEPLOYMENT_TARGET = 10.0; 781 | }; 782 | name = Release; 783 | }; 784 | /* End XCBuildConfiguration section */ 785 | 786 | /* Begin XCConfigurationList section */ 787 | 655AEB3A192D42990053AD6C /* Build configuration list for PBXProject "ViewHelper" */ = { 788 | isa = XCConfigurationList; 789 | buildConfigurations = ( 790 | 655AEB72192D429A0053AD6C /* Debug */, 791 | 655AEB73192D429A0053AD6C /* Release */, 792 | ); 793 | defaultConfigurationIsVisible = 0; 794 | defaultConfigurationName = Release; 795 | }; 796 | 65D6FA6F1D8C673E004BAB04 /* Build configuration list for PBXNativeTarget "ViewHelper iOS" */ = { 797 | isa = XCConfigurationList; 798 | buildConfigurations = ( 799 | 65D6FA701D8C673E004BAB04 /* Debug */, 800 | 65D6FA711D8C673E004BAB04 /* Release */, 801 | ); 802 | defaultConfigurationIsVisible = 0; 803 | defaultConfigurationName = Release; 804 | }; 805 | 65D6FA891D8C675E004BAB04 /* Build configuration list for PBXNativeTarget "ViewHelper tvOS" */ = { 806 | isa = XCConfigurationList; 807 | buildConfigurations = ( 808 | 65D6FA8A1D8C675E004BAB04 /* Debug */, 809 | 65D6FA8B1D8C675E004BAB04 /* Release */, 810 | ); 811 | defaultConfigurationIsVisible = 0; 812 | defaultConfigurationName = Release; 813 | }; 814 | 65D6FAB91D8C68CF004BAB04 /* Build configuration list for PBXNativeTarget "ViewHelperDemo iOS" */ = { 815 | isa = XCConfigurationList; 816 | buildConfigurations = ( 817 | 65D6FABA1D8C68CF004BAB04 /* Debug */, 818 | 65D6FABB1D8C68CF004BAB04 /* Release */, 819 | ); 820 | defaultConfigurationIsVisible = 0; 821 | defaultConfigurationName = Release; 822 | }; 823 | 65D6FAD21D8C6C3E004BAB04 /* Build configuration list for PBXNativeTarget "ViewHelperDemo tvOS" */ = { 824 | isa = XCConfigurationList; 825 | buildConfigurations = ( 826 | 65D6FAD31D8C6C3E004BAB04 /* Debug */, 827 | 65D6FAD41D8C6C3E004BAB04 /* Release */, 828 | ); 829 | defaultConfigurationIsVisible = 0; 830 | defaultConfigurationName = Release; 831 | }; 832 | /* End XCConfigurationList section */ 833 | }; 834 | rootObject = 655AEB37192D42990053AD6C /* Project object */; 835 | } 836 | -------------------------------------------------------------------------------- /ViewHelper.xcodeproj/xcshareddata/xcschemes/ViewHelper iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /ViewHelper.xcodeproj/xcshareddata/xcschemes/ViewHelper tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /ViewHelperDemo iOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ViewHelperDemo iOS 4 | // 5 | // Created by Melvin Rivera on 9/16/16. 6 | // Copyright © 2016 All Forces. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /ViewHelperDemo iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /ViewHelperDemo iOS/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /ViewHelperDemo iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ViewHelperDemo iOS/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 81 | 82 | 83 | 84 | 85 | 86 | 90 | 91 | 92 | 93 | 94 | 95 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 113 | 114 | 115 | 116 | 117 | 118 | 122 | 123 | 124 | 125 | 126 | 127 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 144 | 145 | 146 | 147 | 148 | 149 | 153 | 154 | 155 | 156 | 157 | 158 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 196 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | -------------------------------------------------------------------------------- /ViewHelperDemo iOS/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // 4 | // Created by Melvin Rivera on 7/2/14. 5 | // Copyright (c) 2014 All Forces. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | import QuartzCore 11 | 12 | class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource { 13 | 14 | var selectedAnimation: Int = 0 15 | var selectedEasing: Int = 0 16 | 17 | @IBOutlet weak var forceSlider: UISlider! 18 | @IBOutlet weak var forceLabel: UILabel! 19 | 20 | @IBOutlet weak var durationSlider: UISlider! 21 | @IBOutlet weak var durationLabel: UILabel! 22 | 23 | @IBOutlet weak var delaySlider: UISlider! 24 | @IBOutlet weak var delayLabel: UILabel! 25 | 26 | @IBOutlet weak var scaleSlider: UISlider! 27 | @IBOutlet weak var scaleLabel: UILabel! 28 | 29 | @IBOutlet weak var rotateSlider: UISlider! 30 | @IBOutlet weak var rotateLabel: UILabel! 31 | 32 | @IBOutlet weak var dampingSlider: UISlider! 33 | @IBOutlet weak var dampingLabel: UILabel! 34 | 35 | @IBOutlet weak var velocitySlider: UISlider! 36 | @IBOutlet weak var velocityLabel: UILabel! 37 | 38 | @IBOutlet weak var xSlider: UISlider! 39 | @IBOutlet weak var xLabel: UILabel! 40 | 41 | @IBOutlet weak var ySlider: UISlider! 42 | @IBOutlet weak var yLabel: UILabel! 43 | 44 | 45 | @IBOutlet weak var mainBox: InspectableView! 46 | @IBOutlet weak var bigCircle: InspectableView! 47 | @IBOutlet weak var smallCircle: InspectableView! 48 | 49 | override var prefersStatusBarHidden : Bool { 50 | return true 51 | } 52 | 53 | override func viewDidLoad() { 54 | 55 | super.viewDidLoad() 56 | 57 | 58 | // Top Left Square 59 | let topLeftSquare = UIView(autoLayout:true) 60 | bigCircle.addSubview(topLeftSquare) 61 | topLeftSquare.backgroundColor = UIColor(white: 0.1, alpha: 1) 62 | topLeftSquare 63 | .left(to: bigCircle) 64 | .top(to: bigCircle) 65 | .width(to: bigCircle, attribute: .width, constant: 0, multiplier: 0.48) 66 | .height(to: topLeftSquare, attribute: .width) 67 | .layoutIfNeeded() 68 | 69 | // Top Right Square 70 | let topRightSquare = UIView(autoLayout:true) 71 | bigCircle.addSubview(topRightSquare) 72 | topRightSquare.backgroundColor = UIColor(white: 0.1, alpha: 1) 73 | topRightSquare 74 | .right(to: bigCircle) 75 | .top(to: bigCircle) 76 | .size(to: topLeftSquare) 77 | .layoutIfNeeded() 78 | 79 | // Bottom Left Square 80 | let bottomLeftSquare = UIView(autoLayout:true) 81 | bigCircle.addSubview(bottomLeftSquare) 82 | bottomLeftSquare.backgroundColor = UIColor(white: 0.1, alpha: 1) 83 | bottomLeftSquare 84 | .left(to: bigCircle) 85 | .bottom(to: bigCircle) 86 | .size(to: topLeftSquare) 87 | .layoutIfNeeded() 88 | 89 | 90 | // Bottom Right Square 91 | let bottomRightSquare = UIView(autoLayout:true) 92 | bigCircle.addSubview(bottomRightSquare) 93 | bottomRightSquare.backgroundColor = UIColor(white:0.1, alpha: 1) 94 | bottomRightSquare 95 | .right(to: bigCircle) 96 | .bottom(to: bigCircle) 97 | .size(to: topLeftSquare) 98 | .layoutIfNeeded() 99 | 100 | resetValues() 101 | } 102 | 103 | // MARK: View Layout 104 | 105 | override func viewDidAppear(_ animated: Bool) 106 | { 107 | super.viewDidAppear(animated) 108 | layoutView() 109 | } 110 | 111 | override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 112 | { 113 | super.viewWillTransition(to: size, with: coordinator) 114 | 115 | //view.layoutIfNeeded() 116 | coordinator.animate(alongsideTransition: { 117 | context in 118 | // Create a transition and match the context's duration 119 | let transition = CATransition() 120 | transition.duration = context.transitionDuration 121 | transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 122 | self.bigCircle.layer.add(transition, forKey: "cornerRadius") 123 | self.bigCircle.cornerRadius = self.bigCircle.width()/2 124 | self.smallCircle.layer.add(transition, forKey: "cornerRadius") 125 | self.smallCircle.cornerRadius = self.smallCircle.width()/2 126 | }, completion: nil) 127 | 128 | } 129 | 130 | func layoutView() 131 | { 132 | view.layoutIfNeeded() 133 | bigCircle.cornerRadius = bigCircle.width()/2 134 | smallCircle.cornerRadius = smallCircle.width()/2 135 | } 136 | 137 | 138 | // MARK: UIPickerView 139 | 140 | func numberOfComponents(in pickerView: UIPickerView) -> Int { 141 | return 2 142 | } 143 | 144 | func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 145 | return component == 0 ? AnimationType.allValues.count : AnimationEasingCurve.allValues.count 146 | } 147 | 148 | func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 149 | return component == 0 ? String(describing: AnimationType.allValues[row]) : String(describing: AnimationEasingCurve.allValues[row]) 150 | } 151 | 152 | func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 153 | switch component { 154 | case 0: 155 | selectedAnimation = row 156 | animateView(nil) 157 | default: 158 | selectedEasing = row 159 | animateView() 160 | } 161 | } 162 | 163 | 164 | // MARK: Actions 165 | 166 | @IBAction func resetValues(_ sender: AnyObject? = nil) { 167 | forceSlider.setValue(1, animated: true) 168 | durationSlider.setValue(0.5, animated: true) 169 | delaySlider.setValue(0, animated: true) 170 | scaleSlider.setValue(1, animated: true) 171 | rotateSlider.setValue(0, animated: true) 172 | dampingSlider.setValue(0.7, animated: true) 173 | velocitySlider.setValue(0.7, animated: true) 174 | xSlider.setValue(0, animated: true) 175 | ySlider.setValue(0, animated: true) 176 | } 177 | 178 | @IBAction func animateView(_ sender: AnyObject? = nil) { 179 | bigCircle.animate(AnimationType.allValues[selectedAnimation], curve: AnimationEasingCurve.allValues[selectedEasing], duration: CGFloat(durationSlider.value), delay: CGFloat(delaySlider.value), force: CGFloat(forceSlider.value), damping: CGFloat(dampingSlider.value),velocity: CGFloat(velocitySlider.value), fromRotation: CGFloat(rotateSlider.value), fromScale: CGFloat(scaleSlider.value), fromX: CGFloat(xSlider.value), fromY: CGFloat(ySlider.value)) 180 | } 181 | 182 | @IBAction func forceSliderChanged(_ sender: AnyObject) { 183 | animateView() 184 | forceLabel.text = String(format: "Force: %.1f", forceSlider.value) 185 | } 186 | @IBAction func durationSliderChanged(_ sender: AnyObject) { 187 | animateView() 188 | durationLabel.text = String(format: "Duration: %.1f", durationSlider.value) 189 | } 190 | @IBAction func delaySliderChanged(_ sender: AnyObject) { 191 | animateView() 192 | delayLabel.text = String(format: "Delay: %.1f", delaySlider.value) 193 | } 194 | 195 | @IBAction func scaleSliderChanged(_ sender: AnyObject) { 196 | animateView() 197 | scaleLabel.text = String(format: "Scale: %.1f", scaleSlider.value) 198 | } 199 | @IBAction func rotateSliderChanged(_ sender: AnyObject) { 200 | animateView() 201 | rotateLabel.text = String(format: "Rotate: %.1f", rotateSlider.value) 202 | } 203 | @IBAction func dampingSliderChanged(_ sender: AnyObject) { 204 | animateView() 205 | dampingLabel.text = String(format: "Damping: %.1f", dampingSlider.value) 206 | } 207 | 208 | @IBAction func velocitySliderChanged(_ sender: AnyObject) { 209 | animateView() 210 | velocityLabel.text = String(format: "Velocity: %.1f", velocitySlider.value) 211 | } 212 | @IBAction func xSliderChanged(_ sender: AnyObject) { 213 | animateView() 214 | xLabel.text = String(format: "x: %.1f", xSlider.value) 215 | } 216 | @IBAction func ySliderChanged(_ sender: AnyObject) { 217 | animateView() 218 | yLabel.text = String(format: "y: %.1f", ySlider.value) 219 | } 220 | 221 | 222 | } 223 | 224 | -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ViewHelperDemo tvOS 4 | // 5 | // Created by Melvin Rivera on 9/16/16. 6 | // Copyright © 2016 All Forces. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "size" : "1280x768", 5 | "idiom" : "tv", 6 | "filename" : "App Icon - Large.imagestack", 7 | "role" : "primary-app-icon" 8 | }, 9 | { 10 | "size" : "400x240", 11 | "idiom" : "tv", 12 | "filename" : "App Icon - Small.imagestack", 13 | "role" : "primary-app-icon" 14 | }, 15 | { 16 | "size" : "2320x720", 17 | "idiom" : "tv", 18 | "filename" : "Top Shelf Image Wide.imageset", 19 | "role" : "top-shelf-image-wide" 20 | }, 21 | { 22 | "size" : "1920x720", 23 | "idiom" : "tv", 24 | "filename" : "Top Shelf Image.imageset", 25 | "role" : "top-shelf-image" 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "landscape", 5 | "idiom" : "tv", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "9.0", 8 | "scale" : "1x" 9 | } 10 | ], 11 | "info" : { 12 | "version" : 1, 13 | "author" : "xcode" 14 | } 15 | } -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIMainStoryboardFile 24 | Main 25 | UIRequiredDeviceCapabilities 26 | 27 | arm64 28 | 29 | UIUserInterfaceStyle 30 | Automatic 31 | 32 | 33 | -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.swift 3 | // ViewHelper 4 | // 5 | // Created by Melvin Rivera on 11/26/16. 6 | // Copyright © 2016 All Forces. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TableViewController: UITableViewController { 12 | 13 | var selected: Int = 0 14 | var items = [String]() 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | } 20 | 21 | override func viewDidAppear(_ animated: Bool) { 22 | super.viewDidAppear(animated) 23 | self.tableView.selectRow(at: IndexPath(item: selected, section: 0), animated: true, scrollPosition: UITableViewScrollPosition.middle) 24 | } 25 | 26 | // MARK: - Table view data source 27 | 28 | override func numberOfSections(in tableView: UITableView) -> Int { 29 | return 1 30 | } 31 | 32 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 33 | return items.count 34 | } 35 | 36 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 37 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 38 | cell.textLabel?.text = items[indexPath.row] 39 | return cell 40 | } 41 | 42 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 43 | selected = indexPath.row 44 | if self.title == selectedAnimationKey { 45 | UserDefaults.standard.set(selected, forKey: selectedAnimationKey) 46 | } else { 47 | UserDefaults.standard.set(selected, forKey: selectedEasingCurveKey) 48 | } 49 | UserDefaults.standard.synchronize() 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /ViewHelperDemo tvOS/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ViewHelperDemo tvOS 4 | // 5 | // Created by Melvin Rivera on 9/16/16. 6 | // Copyright © 2016 All Forces. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let selectedAnimationKey = "selectedAnimation" 12 | let selectedEasingCurveKey = "selectedEasingCurve" 13 | 14 | class ViewController: UIViewController { 15 | 16 | var selectedAnimation: Int = 0 17 | var selectedEasingCurve: Int = 0 18 | 19 | @IBOutlet weak var mainBox: InspectableView! 20 | @IBOutlet weak var bigCircle: InspectableView! 21 | @IBOutlet weak var smallCircle: InspectableView! 22 | 23 | 24 | @IBOutlet weak var forceLabel: UILabel! 25 | @IBOutlet weak var durationLabel: UILabel! 26 | @IBOutlet weak var delayLabel: UILabel! 27 | @IBOutlet weak var scaleLabel: UILabel! 28 | @IBOutlet weak var rotateLabel: UILabel! 29 | @IBOutlet weak var dampingLabel: UILabel! 30 | @IBOutlet weak var velocityLabel: UILabel! 31 | @IBOutlet weak var xPointLabel: UILabel! 32 | @IBOutlet weak var yPointLabel: UILabel! 33 | 34 | @IBOutlet weak var animation: UIButton! 35 | @IBOutlet weak var curve: UIButton! 36 | 37 | struct AnimationProperty { 38 | var minValue:Float 39 | var maxValue:Float 40 | var defaultValue:Float 41 | var stepValue:Float 42 | init (min:Float, max:Float, defaultValue:Float, step:Float) { 43 | minValue = min 44 | maxValue = max 45 | self.defaultValue = defaultValue 46 | currentValue = defaultValue 47 | stepValue = step 48 | } 49 | var currentValue:Float { 50 | didSet { 51 | currentValue = max(min(currentValue, maxValue), minValue) 52 | } 53 | } 54 | var percentageValue:Float { 55 | get { return (currentValue - minValue) / (maxValue - minValue) } 56 | } 57 | } 58 | 59 | 60 | var force = AnimationProperty(min: 1, max: 5, defaultValue: 1, step: 1) 61 | var duration = AnimationProperty(min: 0.5, max: 5, defaultValue: 0.5, step: 0.5) 62 | var delay = AnimationProperty(min: 0, max: 5, defaultValue: 0, step: 0.5) 63 | var scale = AnimationProperty(min: 1, max: 5, defaultValue: 1, step: 1) 64 | var rotate = AnimationProperty(min: 0, max: 5, defaultValue: 0, step: 1) 65 | var damping = AnimationProperty(min: 0, max: 1, defaultValue: 0.7, step: 0.1) 66 | var velocity = AnimationProperty(min: 0, max: 1, defaultValue: 0.7, step: 0.1) 67 | var xPoint = AnimationProperty(min: -1000, max: 1000, defaultValue: 0, step: 50) 68 | var yPoint = AnimationProperty(min: -1000, max: 1000, defaultValue: 0, step: 50) 69 | 70 | 71 | override func viewDidLoad() { 72 | super.viewDidLoad() 73 | 74 | 75 | /* 76 | 77 | Setting up some views by code to demnstrate how to add a view with constraints. 78 | */ 79 | // Top Left Square 80 | let topLeftSquare = UIView(autoLayout:true) 81 | bigCircle.addSubview(topLeftSquare) 82 | topLeftSquare.backgroundColor = UIColor(white: 0.1, alpha: 1) 83 | topLeftSquare 84 | .left(to: bigCircle) 85 | .top(to: bigCircle) 86 | .width(to: bigCircle, attribute: .width, constant: 0, multiplier: 0.48) 87 | .height(to: topLeftSquare, attribute: .width) 88 | .layoutIfNeeded() 89 | 90 | // Top Right Square 91 | let topRightSquare = UIView(autoLayout:true) 92 | bigCircle.addSubview(topRightSquare) 93 | topRightSquare.backgroundColor = UIColor(white: 0.1, alpha: 1) 94 | topRightSquare 95 | .right(to: bigCircle) 96 | .top(to: bigCircle) 97 | .size(to: topLeftSquare) 98 | .layoutIfNeeded() 99 | 100 | // Bottom Left Square 101 | let bottomLeftSquare = UIView(autoLayout:true) 102 | bigCircle.addSubview(bottomLeftSquare) 103 | bottomLeftSquare.backgroundColor = UIColor(white: 0.1, alpha: 1) 104 | bottomLeftSquare 105 | .left(to: bigCircle) 106 | .bottom(to: bigCircle) 107 | .size(to: topLeftSquare) 108 | .layoutIfNeeded() 109 | 110 | 111 | // Bottom Right Square 112 | let bottomRightSquare = UIView(autoLayout:true) 113 | bigCircle.addSubview(bottomRightSquare) 114 | bottomRightSquare.backgroundColor = UIColor(white:0.1, alpha: 1) 115 | bottomRightSquare 116 | .right(to: bigCircle) 117 | .bottom(to: bigCircle) 118 | .size(to: topLeftSquare) 119 | .layoutIfNeeded() 120 | 121 | UserDefaults.standard.addObserver(self, forKeyPath: selectedAnimationKey, options: NSKeyValueObservingOptions.new, context: nil) 122 | UserDefaults.standard.addObserver(self, forKeyPath: selectedEasingCurveKey, options: NSKeyValueObservingOptions.new, context: nil) 123 | 124 | resetValues() 125 | 126 | } 127 | 128 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 129 | if keyPath == selectedAnimationKey { 130 | updateAnimationUI() 131 | } else { 132 | updateEasingCurveUI() 133 | } 134 | animateView() 135 | } 136 | 137 | override func viewDidAppear(_ animated: Bool) 138 | { 139 | super.viewDidAppear(animated) 140 | layoutView() 141 | } 142 | 143 | func layoutView() 144 | { 145 | view.layoutIfNeeded() 146 | bigCircle.cornerRadius = bigCircle.width()/2 147 | smallCircle.cornerRadius = smallCircle.width()/2 148 | } 149 | 150 | 151 | 152 | @IBAction func resetValues(_ sender: AnyObject? = nil) { 153 | 154 | force.currentValue = force.defaultValue 155 | updateForceUI() 156 | 157 | duration.currentValue = duration.defaultValue 158 | updateDurationUI() 159 | 160 | delay.currentValue = delay.defaultValue 161 | updateDelayUI() 162 | 163 | scale.currentValue = scale.defaultValue 164 | updateScaleUI() 165 | 166 | rotate.currentValue = rotate.defaultValue 167 | updateRotateUI() 168 | 169 | damping.currentValue = damping.defaultValue 170 | updateDampingUI() 171 | 172 | velocity.currentValue = velocity.defaultValue 173 | updateVelocityUI() 174 | 175 | xPoint.currentValue = xPoint.defaultValue 176 | updateXPointUI() 177 | 178 | yPoint.currentValue = yPoint.defaultValue 179 | updateYPointUI() 180 | 181 | selectedAnimation = 0 182 | selectedEasingCurve = 0 183 | UserDefaults.standard.set(selectedAnimation, forKey: selectedAnimationKey) 184 | UserDefaults.standard.set(selectedEasingCurve, forKey: selectedAnimationKey) 185 | UserDefaults.standard.synchronize() 186 | updateAnimationUI() 187 | updateEasingCurveUI() 188 | 189 | } 190 | 191 | @IBAction func animateView(_ sender: AnyObject? = nil) { 192 | bigCircle.animate(AnimationType.allValues[selectedAnimation], 193 | curve: AnimationEasingCurve.allValues[selectedEasingCurve], 194 | duration: CGFloat(duration.currentValue), 195 | delay: CGFloat(delay.currentValue), 196 | force: CGFloat(force.currentValue), 197 | damping: CGFloat(damping.currentValue), 198 | velocity: CGFloat(velocity.currentValue), 199 | fromRotation: CGFloat(rotate.currentValue), 200 | fromScale: CGFloat(scale.currentValue), 201 | fromX: CGFloat(xPoint.currentValue), 202 | fromY: CGFloat(yPoint.currentValue)) 203 | } 204 | 205 | @IBAction func forceAction(sender: UIButton) { 206 | force.currentValue = sender.titleLabel!.text == "+" ? force.currentValue + force.stepValue : force.currentValue - force.stepValue 207 | updateForceUI() 208 | animateView() 209 | } 210 | func updateForceUI() { 211 | forceLabel.text = String(format: "%.1f", force.currentValue) 212 | } 213 | 214 | @IBAction func durationAction(sender: UIButton) { 215 | duration.currentValue = sender.titleLabel!.text == "+" ? duration.currentValue + duration.stepValue : duration.currentValue - duration.stepValue 216 | updateDurationUI() 217 | animateView() 218 | } 219 | func updateDurationUI() { 220 | durationLabel.text = String(format: "%.1f", duration.currentValue) 221 | } 222 | 223 | @IBAction func delayAction(sender: UIButton) { 224 | delay.currentValue = sender.titleLabel!.text == "+" ? delay.currentValue + delay.stepValue : delay.currentValue - delay.stepValue 225 | updateDelayUI() 226 | animateView() 227 | } 228 | func updateDelayUI() { 229 | delayLabel.text = String(format: "%.1f", delay.currentValue) 230 | } 231 | 232 | @IBAction func scaleAction(sender: UIButton) { 233 | scale.currentValue = sender.titleLabel!.text == "+" ? scale.currentValue + scale.stepValue : scale.currentValue - scale.stepValue 234 | updateScaleUI() 235 | animateView() 236 | } 237 | func updateScaleUI() { 238 | scaleLabel.text = String(format: "%.1f", scale.currentValue) 239 | } 240 | 241 | @IBAction func rotateAction(sender: UIButton) { 242 | rotate.currentValue = sender.titleLabel!.text == "+" ? rotate.currentValue + rotate.stepValue : rotate.currentValue - rotate.stepValue 243 | updateRotateUI() 244 | animateView() 245 | } 246 | func updateRotateUI() { 247 | rotateLabel.text = String(format: "%.1f", rotate.currentValue) 248 | } 249 | 250 | @IBAction func dampingAction(sender: UIButton) { 251 | damping.currentValue = sender.titleLabel!.text == "+" ? damping.currentValue + damping.stepValue : damping.currentValue - damping.stepValue 252 | updateDampingUI() 253 | animateView() 254 | } 255 | func updateDampingUI() { 256 | dampingLabel.text = String(format: "%.1f", damping.currentValue) 257 | } 258 | 259 | @IBAction func velocityAction(sender: UIButton) { 260 | velocity.currentValue = sender.titleLabel!.text == "+" ? velocity.currentValue + velocity.stepValue : velocity.currentValue - velocity.stepValue 261 | updateVelocityUI() 262 | animateView() 263 | } 264 | func updateVelocityUI() { 265 | velocityLabel.text = String(format: "%.1f", velocity.currentValue) 266 | } 267 | 268 | @IBAction func xAction(sender: UIButton) { 269 | xPoint.currentValue = sender.titleLabel!.text == "+" ? xPoint.currentValue + xPoint.stepValue : xPoint.currentValue - xPoint.stepValue 270 | updateXPointUI() 271 | animateView() 272 | } 273 | func updateXPointUI() { 274 | xPointLabel.text = String(format: "%.1f", xPoint.currentValue) 275 | } 276 | 277 | @IBAction func yAction(sender: UIButton) { 278 | yPoint.currentValue = sender.titleLabel!.text == "+" ? yPoint.currentValue + yPoint.stepValue : yPoint.currentValue - yPoint.stepValue 279 | updateYPointUI() 280 | animateView() 281 | } 282 | func updateYPointUI() { 283 | yPointLabel.text = String(format: "%.1f", yPoint.currentValue) 284 | } 285 | 286 | func updateAnimationUI() { 287 | selectedAnimation = UserDefaults.standard.integer(forKey: selectedAnimationKey) 288 | animation.setTitle("Animation: \(AnimationType.allValues[selectedAnimation]) ⋯", for: .normal) 289 | } 290 | 291 | func updateEasingCurveUI() { 292 | selectedEasingCurve = UserDefaults.standard.integer(forKey: selectedEasingCurveKey) 293 | curve.setTitle("Curve: \(AnimationEasingCurve.allValues[selectedEasingCurve]) ⋯", for: .normal) 294 | } 295 | 296 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 297 | let controller = segue.destination as! TableViewController 298 | if segue.identifier == "Animation" { 299 | controller.items = AnimationType.allValues.map { $0.description } 300 | controller.selected = selectedAnimation 301 | controller.title = selectedAnimationKey 302 | } else { 303 | controller.items = AnimationEasingCurve.allValues.map { $0.description } 304 | controller.selected = selectedEasingCurve 305 | controller.title = selectedEasingCurveKey 306 | } 307 | 308 | } 309 | 310 | func updateUIFromTableViewControllerAction(){ 311 | 312 | } 313 | 314 | @IBAction func unwindToThisViewController(segue: UIStoryboardSegue) { 315 | print("here") 316 | let controller = segue.source as! TableViewController 317 | if controller.title == selectedAnimationKey { 318 | selectedAnimation = controller.selected 319 | updateAnimationUI() 320 | } else { 321 | selectedEasingCurve = controller.selected 322 | updateEasingCurveUI() 323 | } 324 | } 325 | 326 | 327 | } 328 | 329 | --------------------------------------------------------------------------------