Repository: rakaramos/StarButton
Branch: master
Commit: 644bac546603
Files: 16
Total size: 52.3 KB
Directory structure:
gitextract_8i_7yswl/
├── .gitignore
├── LICENSE
├── README.md
├── StarBounce/
│ ├── AppDelegate.swift
│ ├── Base.lproj/
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
│ ├── Extensions.swift
│ ├── Images.xcassets/
│ │ └── AppIcon.appiconset/
│ │ └── Contents.json
│ ├── Info.plist
│ ├── Paths.swift
│ ├── StarButton.swift
│ └── ViewController.swift
├── StarBounce.xcodeproj/
│ ├── project.pbxproj
│ └── project.xcworkspace/
│ └── contents.xcworkspacedata
└── StarBounceTests/
├── Info.plist
└── StarBounceTests.swift
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Pods/
.DS_Store
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015 Rafael Machado
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Star Button
## Article
[Creating Custom Animated Buttons](https://swift.unicorn.tv/articles/creating-custom-animated-buttons)
## Demo
Source of inspiration

## Code result

## A Swift bounce animation :)

## License
Released under the MIT license. See the LICENSE file for more info.
================================================
FILE: StarBounce/AppDelegate.swift
================================================
//
// AppDelegate.swift
// StarBounce
//
// Created by Rafael Machado on 2/10/15.
// Copyright (c) 2015 Rafael Machado. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
}
================================================
FILE: StarBounce/Base.lproj/LaunchScreen.xib
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Rafael Machado. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="StarBounce" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>
================================================
FILE: StarBounce/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6254" systemVersion="14C109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="StarBounce" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ois-ef-f1f" customClass="StarButton" customModule="StarBounce" customModuleProvider="target">
<rect key="frame" x="250" y="250" width="100" height="100"/>
<constraints>
<constraint firstAttribute="height" constant="100" id="CoI-Xk-aOa"/>
<constraint firstAttribute="width" constant="100" id="apZ-gS-R0k"/>
</constraints>
<state key="normal">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="lineWidth">
<real key="value" value="3"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="favoriteColor">
<color key="value" red="0.94509803920000002" green="0.76862745099999996" blue="0.058823529409999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="notFavoriteColor">
<color key="value" red="0.58431372550000005" green="0.64705882349999999" blue="0.65098039220000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="starFavoriteColor">
<color key="value" white="1" alpha="1" colorSpace="calibratedWhite"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="favorite:" destination="BYZ-38-t0r" eventType="touchUpInside" id="fct-j6-UcT"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="centerY" secondItem="Ois-ef-f1f" secondAttribute="centerY" id="LT6-y1-wrH"/>
<constraint firstAttribute="centerX" secondItem="Ois-ef-f1f" secondAttribute="centerX" id="bAT-8T-uJt"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
================================================
FILE: StarBounce/Extensions.swift
================================================
//
// Extensions.swift
// FavoriteStart
//
// Created by Rafael Machado on 2/9/15.
// Copyright (c) 2015 Rafael Machado. All rights reserved.
//
import UIKit
extension UIColor {
convenience init (hex: String) {
var cString = hex.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased()
if cString.hasPrefix("#") {
cString = (cString as NSString).substring(from: 1)
}
if cString.characters.count != 6 {
self.init()
return
}
let rString = (cString as NSString).substring(to: 2)
let gString = ((cString as NSString).substring(from: 2) as NSString).substring(to: 2)
let bString = ((cString as NSString).substring(from: 4) as NSString).substring(to: 2)
var r: CUnsignedInt = 0, g: CUnsignedInt = 0, b: CUnsignedInt = 0
Scanner(string: rString).scanHexInt32(&r)
Scanner(string: gString).scanHexInt32(&g)
Scanner(string: bString).scanHexInt32(&b)
self.init(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: CGFloat(1))
}
}
extension CALayer {
func applyAnimation(_ animation: CABasicAnimation) {
guard let copy = animation.copy() as? CABasicAnimation,
let presentationLayer = self.presentation(),
let keyPath = copy.keyPath else {
return
}
if copy.fromValue == nil {
copy.fromValue = presentationLayer.value(forKeyPath: keyPath)
}
self.add(copy, forKey: copy.keyPath)
CATransaction.begin()
CATransaction.setDisableActions(true)
self.setValue(copy.toValue, forKeyPath:keyPath)
CATransaction.commit()
}
}
extension CGPath {
class func rescaleForFrame(path: CGPath, frame: CGRect) -> CGPath {
let boundingBox = path.boundingBoxOfPath
let boundingBoxAspectRatio = boundingBox.width/boundingBox.height
let viewAspectRatio = frame.width/frame.height
var scaleFactor: CGFloat = 1
if boundingBoxAspectRatio > viewAspectRatio {
scaleFactor = frame.width/boundingBox.width
} else {
scaleFactor = frame.height/boundingBox.height
}
var scaleTransform = CGAffineTransform.identity
scaleTransform = scaleTransform.scaledBy(x: scaleFactor, y: scaleFactor)
scaleTransform = scaleTransform.translatedBy(x: -boundingBox.minX, y: -boundingBox.minY)
let scaledSize = boundingBox.size.applying(CGAffineTransform(scaleX: scaleFactor, y: scaleFactor))
let centerOffset = CGSize(width: (frame.width - scaledSize.width) / (scaleFactor * 2.0),
height: (frame.height - scaledSize.height) / (scaleFactor * 2.0))
scaleTransform = scaleTransform.translatedBy(x: centerOffset.width, y: centerOffset.height)
if let scaleTransform = path.copy(using: &scaleTransform) {
return scaleTransform
} else {
return path
}
}
}
================================================
FILE: StarBounce/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: StarBounce/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
================================================
FILE: StarBounce/Paths.swift
================================================
//
// Paths.swift
// FavoriteStart
//
// Created by Rafael Machado on 2/9/15.
// Copyright (c) 2015 Rafael Machado. All rights reserved.
//
import UIKit
struct Paths {
static var star: CGPath {
let star = UIBezierPath()
star.move(to: CGPoint(x: 112.79, y: 119))
star.addCurve(to: CGPoint(x: 107.75, y: 122.6),
controlPoint1: CGPoint(x: 113.41, y: 122.8),
controlPoint2: CGPoint(x: 111.14, y: 124.42))
star.addLine(to: CGPoint(x: 96.53, y: 116.58))
star.addCurve(to: CGPoint(x: 84.14, y: 116.47),
controlPoint1: CGPoint(x: 93.14, y: 114.76),
controlPoint2: CGPoint(x: 87.56, y: 114.71))
star.addLine(to: CGPoint(x: 72.82, y: 122.3))
star.addCurve(to: CGPoint(x: 67.84, y: 118.62),
controlPoint1: CGPoint(x: 69.4, y: 124.06),
controlPoint2: CGPoint(x: 67.15, y: 122.41))
star.addLine(to: CGPoint(x: 70.1, y: 106.09))
star.addCurve(to: CGPoint(x: 66.37, y: 94.27),
controlPoint1: CGPoint(x: 70.78, y: 102.3),
controlPoint2: CGPoint(x: 69.1, y: 96.98))
star.addLine(to: CGPoint(x: 57.33, y: 85.31))
star.addCurve(to: CGPoint(x: 59.29, y: 79.43),
controlPoint1: CGPoint(x: 54.6, y: 82.6),
controlPoint2: CGPoint(x: 55.48, y: 79.95))
star.addLine(to: CGPoint(x: 71.91, y: 77.71))
star.addCurve(to: CGPoint(x: 81.99, y: 70.51),
controlPoint1: CGPoint(x: 75.72, y: 77.19),
controlPoint2: CGPoint(x: 80.26, y: 73.95))
star.addLine(to: CGPoint(x: 87.72, y: 59.14))
star.addCurve(to: CGPoint(x: 93.92, y: 59.2),
controlPoint1: CGPoint(x: 89.46, y: 55.71),
controlPoint2: CGPoint(x: 92.25, y: 55.73))
star.addLine(to: CGPoint(x: 99.46, y: 70.66))
star.addCurve(to: CGPoint(x: 109.42, y: 78.03),
controlPoint1: CGPoint(x: 101.13, y: 74.13),
controlPoint2: CGPoint(x: 105.62, y: 77.44))
star.addLine(to: CGPoint(x: 122, y: 79.96))
star.addCurve(to: CGPoint(x: 123.87, y: 85.87),
controlPoint1: CGPoint(x: 125.81, y: 80.55),
controlPoint2: CGPoint(x: 126.64, y: 83.21))
star.addLine(to: CGPoint(x: 114.67, y: 94.68))
star.addCurve(to: CGPoint(x: 110.75, y: 106.43),
controlPoint1: CGPoint(x: 111.89, y: 97.34),
controlPoint2: CGPoint(x: 110.13, y: 102.63))
star.addLine(to: CGPoint(x: 112.79, y: 119))
return star.cgPath
}
static var swift: CGPath {
let swiftPath = UIBezierPath()
swiftPath.move(to: CGPoint(x: 376.2, y: 283.2))
swiftPath.addCurve(to: CGPoint(x: 349.8, y: 238.4),
controlPoint1: CGPoint(x: 367.4, y: 258.4),
controlPoint2: CGPoint(x: 349.8, y: 238.4))
swiftPath.addCurve(to: CGPoint(x: 236.5, y: 0),
controlPoint1: CGPoint(x: 349.8, y: 238.4),
controlPoint2: CGPoint(x: 399.7, y: 105.6))
swiftPath.addCurve(to: CGPoint(x: 269, y: 180.8),
controlPoint1: CGPoint(x: 303.7, y: 101.6),
controlPoint2: CGPoint(x: 269, y: 180.8))
swiftPath.addCurve(to: CGPoint(x: 181.29, y: 117.07),
controlPoint1: CGPoint(x: 269, y: 180.8),
controlPoint2: CGPoint(x: 211.4, y: 140.8))
swiftPath.addCurve(to: CGPoint(x: 85, y: 33.6),
controlPoint1: CGPoint(x: 151.18, y: 93.35),
controlPoint2: CGPoint(x: 85, y: 33.6))
swiftPath.addCurve(to: CGPoint(x: 145, y: 117.07),
controlPoint1: CGPoint(x: 85, y: 33.6),
controlPoint2: CGPoint(x: 128.15, y: 96.31))
swiftPath.addCurve(to: CGPoint(x: 185.78, y: 163.66),
controlPoint1: CGPoint(x: 161.85, y: 137.84),
controlPoint2: CGPoint(x: 185.78, y: 163.66))
swiftPath.addCurve(to: CGPoint(x: 136.36, y: 129.42),
controlPoint1: CGPoint(x: 185.78, y: 163.66),
controlPoint2: CGPoint(x: 161.07, y: 147.39))
swiftPath.addCurve(to: CGPoint(x: 34.6, y: 50.4),
controlPoint1: CGPoint(x: 111.65, y: 111.46),
controlPoint2: CGPoint(x: 34.6, y: 50.4))
swiftPath.addCurve(to: CGPoint(x: 133.8, y: 169.2),
controlPoint1: CGPoint(x: 34.6, y: 50.4),
controlPoint2: CGPoint(x: 82.69, y: 119.24))
swiftPath.addCurve(to: CGPoint(x: 214.6, y: 244),
controlPoint1: CGPoint(x: 184.91, y: 219.16),
controlPoint2: CGPoint(x: 214.6, y: 244))
swiftPath.addCurve(to: CGPoint(x: 129.8, y: 264.8),
controlPoint1: CGPoint(x: 214.6, y: 244),
controlPoint2: CGPoint(x: 196.2, y: 263.2))
swiftPath.addCurve(to: CGPoint(x: 0, y: 221),
controlPoint1: CGPoint(x: 63.4, y: 266.4),
controlPoint2: CGPoint(x: 0, y: 221))
swiftPath.addCurve(to: CGPoint(x: 206.6, y: 339.2),
controlPoint1: CGPoint(x: 0, y: 221),
controlPoint2: CGPoint(x: 62.5, y: 339.2))
swiftPath.addCurve(to: CGPoint(x: 325, y: 304.8),
controlPoint1: CGPoint(x: 270.6, y: 339.2),
controlPoint2: CGPoint(x: 288.93, y: 304.8))
swiftPath.addCurve(to: CGPoint(x: 383.3, y: 339.2),
controlPoint1: CGPoint(x: 361.07, y: 304.8),
controlPoint2: CGPoint(x: 381.7, y: 340))
swiftPath.addCurve(to: CGPoint(x: 376.2, y: 283.2),
controlPoint1: CGPoint(x: 384.9, y: 338.4),
controlPoint2: CGPoint(x: 385, y: 308))
return swiftPath.cgPath
}
static func circle(_ inFrame: CGRect) -> CGPath {
let circle = UIBezierPath(ovalIn: inFrame)
return circle.cgPath
}
}
================================================
FILE: StarBounce/StarButton.swift
================================================
//
// StatButton.swift
// FavoriteStar
//
// Created by Rafael Machado on 14/11/14.
// Copyright (c) 2014 Rafael Machado. All rights reserved.
//
import UIKit
import QuartzCore
@IBDesignable
class StarButton: UIButton, CAAnimationDelegate {
fileprivate var starShape: CAShapeLayer!
fileprivate var outerRingShape: CAShapeLayer!
fileprivate var fillRingShape: CAShapeLayer!
fileprivate let starKey = "FAVANIMKEY"
fileprivate let favoriteKey = "FAVORITE"
fileprivate let notFavoriteKey = "NOTFAVORITE"
@IBInspectable
var lineWidth: CGFloat = 1 {
didSet {
updateLayerProperties()
}
}
@IBInspectable
var favoriteColor: UIColor = UIColor(hex:"eecd34") {
didSet {
updateLayerProperties()
}
}
@IBInspectable
var notFavoriteColor: UIColor = UIColor(hex:"9e9b9b") {
didSet {
updateLayerProperties()
}
}
@IBInspectable
var starFavoriteColor: UIColor = UIColor(hex:"9e9b9b") {
didSet {
updateLayerProperties()
}
}
var isFavorite: Bool = false {
didSet {
if self.isFavorite {
favorite()
} else {
notFavorite()
}
}
}
fileprivate func updateLayerProperties() {
if fillRingShape != nil {
fillRingShape.fillColor = favoriteColor.cgColor
}
if outerRingShape != nil {
outerRingShape.lineWidth = lineWidth
outerRingShape.strokeColor = notFavoriteColor.cgColor
}
if starShape != nil {
if isFavorite {
starShape.fillColor = starFavoriteColor.cgColor
} else {
starShape.fillColor = notFavoriteColor.cgColor
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
createLayersIfNeeded()
updateLayerProperties()
}
fileprivate func createLayersIfNeeded() {
if fillRingShape == nil {
fillRingShape = CAShapeLayer()
fillRingShape.path = Paths.circle(frameWithInset())
fillRingShape.bounds = (fillRingShape.path?.boundingBox)!
fillRingShape.fillColor = favoriteColor.cgColor
fillRingShape.lineWidth = lineWidth
fillRingShape.position = CGPoint(x: fillRingShape.bounds.width/2, y: fillRingShape.bounds.height/2)
fillRingShape.transform = CATransform3DMakeScale(0.2, 0.2, 0.2)
fillRingShape.opacity = 0
self.layer.addSublayer(fillRingShape)
}
if outerRingShape == nil {
outerRingShape = CAShapeLayer()
outerRingShape.path = Paths.circle(frameWithInset())
outerRingShape.bounds = frameWithInset()
outerRingShape.lineWidth = lineWidth
outerRingShape.strokeColor = notFavoriteColor.cgColor
outerRingShape.fillColor = UIColor.clear.cgColor
outerRingShape.position = CGPoint(x: self.bounds.width/2, y: self.bounds.height/2)
outerRingShape.transform = CATransform3DIdentity
outerRingShape.opacity = 0.5
self.layer.addSublayer(outerRingShape)
}
if starShape == nil {
var starFrame = self.bounds
starFrame.size.width = starFrame.width/2.5
starFrame.size.height = starFrame.height/2.5
starShape = CAShapeLayer()
starShape.path = CGPath.rescaleForFrame(path: Paths.star, frame: starFrame)
starShape.bounds = (starShape.path?.boundingBoxOfPath)!
starShape.fillColor = notFavoriteColor.cgColor
starShape.position = CGPoint(x: (outerRingShape.path?.boundingBox.width)!/2,
y: (outerRingShape.path?.boundingBox.height)!/2)
starShape.transform = CATransform3DIdentity
starShape.opacity = 0.5
self.layer.addSublayer(starShape)
}
}
fileprivate func frameWithInset() -> CGRect {
return self.bounds.insetBy(dx: lineWidth/2, dy: lineWidth/2)
}
fileprivate func notFavorite() {
let starFillColor = CABasicAnimation(keyPath: "fillColor")
starFillColor.toValue = notFavoriteColor.cgColor
starFillColor.duration = 0.3
let starOpacity = CABasicAnimation(keyPath: "opacity")
starOpacity.toValue = 0.5
starOpacity.duration = 0.3
let starGroup = CAAnimationGroup()
starGroup.animations = [starFillColor, starOpacity]
starShape.add(starGroup, forKey: nil)
starShape.fillColor = notFavoriteColor.cgColor
starShape.opacity = 0.5
let fillCircle = CABasicAnimation(keyPath: "opacity")
fillCircle.toValue = 0
fillCircle.duration = 0.3
fillCircle.setValue(notFavoriteKey, forKey: starKey)
fillCircle.delegate = self
fillRingShape.add(fillCircle, forKey: nil)
fillRingShape.opacity = 0
let outerCircle = CABasicAnimation(keyPath: "opacity")
outerCircle.toValue = 0.5
outerCircle.duration = 0.3
outerRingShape.add(outerCircle, forKey: nil)
outerRingShape.opacity = 0.5
}
fileprivate func favorite() {
var starGoUp = CATransform3DIdentity
starGoUp = CATransform3DScale(starGoUp, 1.5, 1.5, 1.5)
var starGoDown = CATransform3DIdentity
starGoDown = CATransform3DScale(starGoDown, 0.01, 0.01, 0.01)
let starKeyFrames = CAKeyframeAnimation(keyPath: "transform")
starKeyFrames.values = [NSValue(caTransform3D:CATransform3DIdentity),
NSValue(caTransform3D:starGoUp),
NSValue(caTransform3D:starGoDown)]
starKeyFrames.keyTimes = [0.0, 0.4, 0.6]
starKeyFrames.duration = 0.4
starKeyFrames.beginTime = CACurrentMediaTime() + 0.05
starKeyFrames.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
starKeyFrames.fillMode = kCAFillModeBackwards
starKeyFrames.setValue(favoriteKey, forKey: starKey)
starKeyFrames.delegate = self
starShape.add(starKeyFrames, forKey: favoriteKey)
starShape.transform = starGoDown
var grayGoUp = CATransform3DIdentity
grayGoUp = CATransform3DScale(grayGoUp, 1.5, 1.5, 1.5)
var grayGoDown = CATransform3DIdentity
grayGoDown = CATransform3DScale(grayGoDown, 0.01, 0.01, 0.01)
let outerCircleAnimation = CAKeyframeAnimation(keyPath: "transform")
outerCircleAnimation.values = [NSValue(caTransform3D:CATransform3DIdentity),
NSValue(caTransform3D:grayGoUp),
NSValue(caTransform3D:grayGoDown)]
outerCircleAnimation.keyTimes = [0.0, 0.4, 0.6]
outerCircleAnimation.duration = 0.4
outerCircleAnimation.beginTime = CACurrentMediaTime() + 0.01
outerCircleAnimation.fillMode = kCAFillModeBackwards
outerCircleAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
outerRingShape.add(outerCircleAnimation, forKey: "Gray circle Animation")
outerRingShape.transform = grayGoDown
var favoriteFillGrow = CATransform3DIdentity
favoriteFillGrow = CATransform3DScale(favoriteFillGrow, 1.5, 1.5, 1.5)
let fillCircleAnimation = CAKeyframeAnimation(keyPath: "transform")
fillCircleAnimation.values = [NSValue(caTransform3D:fillRingShape.transform),
NSValue(caTransform3D:favoriteFillGrow),
NSValue(caTransform3D:CATransform3DIdentity)]
fillCircleAnimation.keyTimes = [0.0, 0.4, 0.6]
fillCircleAnimation.duration = 0.4
fillCircleAnimation.beginTime = CACurrentMediaTime() + 0.22
fillCircleAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
fillCircleAnimation.fillMode = kCAFillModeBackwards
let favoriteFillOpacity = CABasicAnimation(keyPath: "opacity")
favoriteFillOpacity.toValue = 1
favoriteFillOpacity.duration = 1
favoriteFillOpacity.beginTime = CACurrentMediaTime()
favoriteFillOpacity.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
favoriteFillOpacity.fillMode = kCAFillModeBackwards
fillRingShape.add(favoriteFillOpacity, forKey: "Show fill circle")
fillRingShape.add(fillCircleAnimation, forKey: "fill circle Animation")
fillRingShape.transform = CATransform3DIdentity
}
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let key = anim.value(forKey: starKey) as? String {
switch key {
case favoriteKey:
endFavorite()
case notFavoriteKey:
prepareForFavorite()
default:
break
}
}
enableTouch()
}
fileprivate func endFavorite() {
executeWithoutActions {
self.starShape.fillColor = self.starFavoriteColor.cgColor
self.starShape.opacity = 1
self.fillRingShape.opacity = 1
self.outerRingShape.transform = CATransform3DIdentity
self.outerRingShape.opacity = 0
}
var starGoUp = CATransform3DIdentity
starGoUp = CATransform3DScale(starGoUp, 2, 2, 2)
let starKeyFrames = CAKeyframeAnimation(keyPath: "transform")
starKeyFrames.values = [NSValue(caTransform3D: starShape.transform),
NSValue(caTransform3D:starGoUp),
NSValue(caTransform3D:CATransform3DIdentity)]
starKeyFrames.keyTimes = [0.0, 0.4, 0.6]
starKeyFrames.duration = 0.2
starKeyFrames.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
starShape.add(starKeyFrames, forKey: nil)
starShape.transform = CATransform3DIdentity
}
fileprivate func prepareForFavorite() {
executeWithoutActions {
self.fillRingShape.opacity = 0
self.fillRingShape.transform = CATransform3DMakeScale(0.2, 0.2, 0.2)
}
}
fileprivate func executeWithoutActions(_ closure: () -> Void) {
CATransaction.begin()
CATransaction.setDisableActions(true)
closure()
CATransaction.commit()
}
func animationDidStart(_ anim: CAAnimation) {
disableTouch()
}
fileprivate func disableTouch() {
self.isUserInteractionEnabled = false
}
fileprivate func enableTouch() {
self.isUserInteractionEnabled = true
}
}
================================================
FILE: StarBounce/ViewController.swift
================================================
//
// ViewController.swift
// FavoriteStart
//
// Created by Rafael Machado on 14/11/14.
// Copyright (c) 2014 Rafael Machado. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
@IBAction func favorite(_ sender: StarButton!) {
sender.isFavorite = !sender.isFavorite
}
}
================================================
FILE: StarBounce.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
01D15DC41A8A60240046F649 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D15DC31A8A60240046F649 /* AppDelegate.swift */; };
01D15DC91A8A60240046F649 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 01D15DC71A8A60240046F649 /* Main.storyboard */; };
01D15DCB1A8A60240046F649 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 01D15DCA1A8A60240046F649 /* Images.xcassets */; };
01D15DCE1A8A60240046F649 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 01D15DCC1A8A60240046F649 /* LaunchScreen.xib */; };
01D15DDA1A8A60240046F649 /* StarBounceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D15DD91A8A60240046F649 /* StarBounceTests.swift */; };
01D15DE71A8A60620046F649 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D15DE31A8A60620046F649 /* ViewController.swift */; };
01D15DE81A8A60620046F649 /* StarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D15DE41A8A60620046F649 /* StarButton.swift */; };
01D15DE91A8A60620046F649 /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D15DE51A8A60620046F649 /* Paths.swift */; };
01D15DEA1A8A60620046F649 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D15DE61A8A60620046F649 /* Extensions.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
01D15DD41A8A60240046F649 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 01D15DB61A8A60240046F649 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 01D15DBD1A8A60240046F649;
remoteInfo = StarBounce;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
01D15DBE1A8A60240046F649 /* StarBounce.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StarBounce.app; sourceTree = BUILT_PRODUCTS_DIR; };
01D15DC21A8A60240046F649 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
01D15DC31A8A60240046F649 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
01D15DC81A8A60240046F649 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
01D15DCA1A8A60240046F649 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
01D15DCD1A8A60240046F649 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
01D15DD31A8A60240046F649 /* StarBounceTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StarBounceTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
01D15DD81A8A60240046F649 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
01D15DD91A8A60240046F649 /* StarBounceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StarBounceTests.swift; sourceTree = "<group>"; };
01D15DE31A8A60620046F649 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
01D15DE41A8A60620046F649 /* StarButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarButton.swift; sourceTree = "<group>"; };
01D15DE51A8A60620046F649 /* Paths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Paths.swift; sourceTree = "<group>"; };
01D15DE61A8A60620046F649 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
01D15DBB1A8A60240046F649 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
01D15DD01A8A60240046F649 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
01D15DB51A8A60240046F649 = {
isa = PBXGroup;
children = (
01D15DC01A8A60240046F649 /* StarBounce */,
01D15DD61A8A60240046F649 /* StarBounceTests */,
01D15DBF1A8A60240046F649 /* Products */,
);
sourceTree = "<group>";
};
01D15DBF1A8A60240046F649 /* Products */ = {
isa = PBXGroup;
children = (
01D15DBE1A8A60240046F649 /* StarBounce.app */,
01D15DD31A8A60240046F649 /* StarBounceTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
01D15DC01A8A60240046F649 /* StarBounce */ = {
isa = PBXGroup;
children = (
01D15DC31A8A60240046F649 /* AppDelegate.swift */,
01D15DE31A8A60620046F649 /* ViewController.swift */,
01D15DE41A8A60620046F649 /* StarButton.swift */,
01D15DE51A8A60620046F649 /* Paths.swift */,
01D15DE61A8A60620046F649 /* Extensions.swift */,
01D15DC71A8A60240046F649 /* Main.storyboard */,
01D15DCA1A8A60240046F649 /* Images.xcassets */,
01D15DCC1A8A60240046F649 /* LaunchScreen.xib */,
01D15DC11A8A60240046F649 /* Supporting Files */,
);
path = StarBounce;
sourceTree = "<group>";
};
01D15DC11A8A60240046F649 /* Supporting Files */ = {
isa = PBXGroup;
children = (
01D15DC21A8A60240046F649 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
01D15DD61A8A60240046F649 /* StarBounceTests */ = {
isa = PBXGroup;
children = (
01D15DD91A8A60240046F649 /* StarBounceTests.swift */,
01D15DD71A8A60240046F649 /* Supporting Files */,
);
path = StarBounceTests;
sourceTree = "<group>";
};
01D15DD71A8A60240046F649 /* Supporting Files */ = {
isa = PBXGroup;
children = (
01D15DD81A8A60240046F649 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
01D15DBD1A8A60240046F649 /* StarBounce */ = {
isa = PBXNativeTarget;
buildConfigurationList = 01D15DDD1A8A60240046F649 /* Build configuration list for PBXNativeTarget "StarBounce" */;
buildPhases = (
01D15DBA1A8A60240046F649 /* Sources */,
01D15DBB1A8A60240046F649 /* Frameworks */,
01D15DBC1A8A60240046F649 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = StarBounce;
productName = StarBounce;
productReference = 01D15DBE1A8A60240046F649 /* StarBounce.app */;
productType = "com.apple.product-type.application";
};
01D15DD21A8A60240046F649 /* StarBounceTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 01D15DE01A8A60240046F649 /* Build configuration list for PBXNativeTarget "StarBounceTests" */;
buildPhases = (
01D15DCF1A8A60240046F649 /* Sources */,
01D15DD01A8A60240046F649 /* Frameworks */,
01D15DD11A8A60240046F649 /* Resources */,
);
buildRules = (
);
dependencies = (
01D15DD51A8A60240046F649 /* PBXTargetDependency */,
);
name = StarBounceTests;
productName = StarBounceTests;
productReference = 01D15DD31A8A60240046F649 /* StarBounceTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
01D15DB61A8A60240046F649 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftMigration = 0710;
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0820;
ORGANIZATIONNAME = "Rafael Machado";
TargetAttributes = {
01D15DBD1A8A60240046F649 = {
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 0820;
};
01D15DD21A8A60240046F649 = {
CreatedOnToolsVersion = 6.1.1;
LastSwiftMigration = 0820;
TestTargetID = 01D15DBD1A8A60240046F649;
};
};
};
buildConfigurationList = 01D15DB91A8A60240046F649 /* Build configuration list for PBXProject "StarBounce" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 01D15DB51A8A60240046F649;
productRefGroup = 01D15DBF1A8A60240046F649 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
01D15DBD1A8A60240046F649 /* StarBounce */,
01D15DD21A8A60240046F649 /* StarBounceTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
01D15DBC1A8A60240046F649 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
01D15DC91A8A60240046F649 /* Main.storyboard in Resources */,
01D15DCE1A8A60240046F649 /* LaunchScreen.xib in Resources */,
01D15DCB1A8A60240046F649 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
01D15DD11A8A60240046F649 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
01D15DBA1A8A60240046F649 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
01D15DEA1A8A60620046F649 /* Extensions.swift in Sources */,
01D15DE81A8A60620046F649 /* StarButton.swift in Sources */,
01D15DE71A8A60620046F649 /* ViewController.swift in Sources */,
01D15DE91A8A60620046F649 /* Paths.swift in Sources */,
01D15DC41A8A60240046F649 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
01D15DCF1A8A60240046F649 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
01D15DDA1A8A60240046F649 /* StarBounceTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
01D15DD51A8A60240046F649 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 01D15DBD1A8A60240046F649 /* StarBounce */;
targetProxy = 01D15DD41A8A60240046F649 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
01D15DC71A8A60240046F649 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
01D15DC81A8A60240046F649 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
01D15DCC1A8A60240046F649 /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
01D15DCD1A8A60240046F649 /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
01D15DDB1A8A60240046F649 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
01D15DDC1A8A60240046F649 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
01D15DDE1A8A60240046F649 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = StarBounce/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.machado.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
01D15DDF1A8A60240046F649 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = StarBounce/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.machado.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Release;
};
01D15DE11A8A60240046F649 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = StarBounceTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.machado.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StarBounce.app/StarBounce";
};
name = Debug;
};
01D15DE21A8A60240046F649 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
INFOPLIST_FILE = StarBounceTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.machado.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StarBounce.app/StarBounce";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
01D15DB91A8A60240046F649 /* Build configuration list for PBXProject "StarBounce" */ = {
isa = XCConfigurationList;
buildConfigurations = (
01D15DDB1A8A60240046F649 /* Debug */,
01D15DDC1A8A60240046F649 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
01D15DDD1A8A60240046F649 /* Build configuration list for PBXNativeTarget "StarBounce" */ = {
isa = XCConfigurationList;
buildConfigurations = (
01D15DDE1A8A60240046F649 /* Debug */,
01D15DDF1A8A60240046F649 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
01D15DE01A8A60240046F649 /* Build configuration list for PBXNativeTarget "StarBounceTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
01D15DE11A8A60240046F649 /* Debug */,
01D15DE21A8A60240046F649 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 01D15DB61A8A60240046F649 /* Project object */;
}
================================================
FILE: StarBounce.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:StarBounce.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: StarBounceTests/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
================================================
FILE: StarBounceTests/StarBounceTests.swift
================================================
//
// StarBounceTests.swift
// StarBounceTests
//
// Created by Rafael Machado on 2/10/15.
// Copyright (c) 2015 Rafael Machado. All rights reserved.
//
import UIKit
import XCTest
class StarBounceTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
gitextract_8i_7yswl/
├── .gitignore
├── LICENSE
├── README.md
├── StarBounce/
│ ├── AppDelegate.swift
│ ├── Base.lproj/
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
│ ├── Extensions.swift
│ ├── Images.xcassets/
│ │ └── AppIcon.appiconset/
│ │ └── Contents.json
│ ├── Info.plist
│ ├── Paths.swift
│ ├── StarButton.swift
│ └── ViewController.swift
├── StarBounce.xcodeproj/
│ ├── project.pbxproj
│ └── project.xcworkspace/
│ └── contents.xcworkspacedata
└── StarBounceTests/
├── Info.plist
└── StarBounceTests.swift
Condensed preview — 16 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (58K chars).
[
{
"path": ".gitignore",
"chars": 503,
"preview": "# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!defau"
},
{
"path": "LICENSE",
"chars": 1082,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Rafael Machado\n\nPermission is hereby granted, free of charge, to any person ob"
},
{
"path": "README.md",
"chars": 539,
"preview": "# Star Button\n## Article\n[Creating Custom Animated Buttons](https://swift.unicorn.tv/articles/creating-custom-animated-b"
},
{
"path": "StarBounce/AppDelegate.swift",
"chars": 461,
"preview": "//\n// AppDelegate.swift\n// StarBounce\n//\n// Created by Rafael Machado on 2/10/15.\n// Copyright (c) 2015 Rafael Macha"
},
{
"path": "StarBounce/Base.lproj/LaunchScreen.xib",
"chars": 3709,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" versi"
},
{
"path": "StarBounce/Base.lproj/Main.storyboard",
"chars": 4599,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "StarBounce/Extensions.swift",
"chars": 3036,
"preview": "//\n// Extensions.swift\n// FavoriteStart\n//\n// Created by Rafael Machado on 2/9/15.\n// Copyright (c) 2015 Rafael Mach"
},
{
"path": "StarBounce/Images.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1077,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"29x29\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "StarBounce/Info.plist",
"chars": 1495,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "StarBounce/Paths.swift",
"chars": 6449,
"preview": "//\n// Paths.swift\n// FavoriteStart\n//\n// Created by Rafael Machado on 2/9/15.\n// Copyright (c) 2015 Rafael Machado. "
},
{
"path": "StarBounce/StarButton.swift",
"chars": 10786,
"preview": "//\n// StatButton.swift\n// FavoriteStar\n//\n// Created by Rafael Machado on 14/11/14.\n// Copyright (c) 2014 Rafael Mac"
},
{
"path": "StarBounce/ViewController.swift",
"chars": 320,
"preview": "//\n// ViewController.swift\n// FavoriteStart\n//\n// Created by Rafael Machado on 14/11/14.\n// Copyright (c) 2014 Rafae"
},
{
"path": "StarBounce.xcodeproj/project.pbxproj",
"chars": 17688,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "StarBounce.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 155,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:StarBounce.xcod"
},
{
"path": "StarBounceTests/Info.plist",
"chars": 733,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "StarBounceTests/StarBounceTests.swift",
"chars": 888,
"preview": "//\n// StarBounceTests.swift\n// StarBounceTests\n//\n// Created by Rafael Machado on 2/10/15.\n// Copyright (c) 2015 Raf"
}
]
About this extraction
This page contains the full source code of the rakaramos/StarButton GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 16 files (52.3 KB), approximately 15.6k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.