Add Swift 2.0 support
One step closer to 1.0. Changes include: - Refactor the API - Make image source non-optional - Use submodule for Runes dependency - Add specs - Remove Runes framework dependency
This commit is contained in:
parent
e979c72bf8
commit
e14b53193f
|
@ -1,19 +1,38 @@
|
||||||
|
# OS X Finder
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Xcode per-user config
|
||||||
*.mode1
|
*.mode1
|
||||||
*.mode1v3
|
*.mode1v3
|
||||||
*.mode2v3
|
*.mode2v3
|
||||||
*.perspective
|
*.perspective
|
||||||
*.perspectivev3
|
*.perspectivev3
|
||||||
*.pbxuser
|
*.pbxuser
|
||||||
*.xccheckout
|
|
||||||
xcuserdata
|
xcuserdata
|
||||||
|
*.xccheckout
|
||||||
|
|
||||||
|
# Build products
|
||||||
build/
|
build/
|
||||||
*.o
|
*.o
|
||||||
*.LinkFileList
|
*.LinkFileList
|
||||||
*.hmap
|
*.hmap
|
||||||
|
|
||||||
|
# Automatic backup files
|
||||||
*~.nib/
|
*~.nib/
|
||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
*.dat
|
*.dat
|
||||||
*.dep
|
*.dep
|
||||||
.DS_Store
|
|
||||||
|
# Cocoapods
|
||||||
|
Pods
|
||||||
|
|
||||||
|
# Carthage
|
||||||
Carthage/Build
|
Carthage/Build
|
||||||
|
|
||||||
|
# AppCode specific files
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
Gifu.framework.zip
|
||||||
|
*.xcscmblueprint
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "Carthage/Checkouts/Runes"]
|
||||||
|
path = Carthage/Checkouts/Runes
|
||||||
|
url = https://github.com/thoughtbot/Runes.git
|
|
@ -0,0 +1 @@
|
||||||
|
github "thoughtbot/Runes" >= 3.0.0
|
|
@ -1 +1 @@
|
||||||
github "thoughtbot/Runes" "v2.0.0"
|
github "thoughtbot/Runes" "v3.0.0"
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit cded739a780fd50c6f888d94802700b104e30f92
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -7,61 +7,21 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
9D25870819BCCB0F00A55A18 /* mugen.gif in Resources */ = {isa = PBXBuildFile; fileRef = 9D25870619BCCB0F00A55A18 /* mugen.gif */; };
|
007380231B279644008DAD5C /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 007380221B279644008DAD5C /* Default-568h@2x.png */; };
|
||||||
9D98823D19BC69CA00B790C6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D98823C19BC69CA00B790C6 /* AppDelegate.swift */; };
|
9D98823D19BC69CA00B790C6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D98823C19BC69CA00B790C6 /* AppDelegate.swift */; };
|
||||||
9D98823F19BC69CA00B790C6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D98823E19BC69CA00B790C6 /* ViewController.swift */; };
|
9D98823F19BC69CA00B790C6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D98823E19BC69CA00B790C6 /* ViewController.swift */; };
|
||||||
9D98824419BC69CA00B790C6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D98824319BC69CA00B790C6 /* Images.xcassets */; };
|
9D98824419BC69CA00B790C6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D98824319BC69CA00B790C6 /* Images.xcassets */; };
|
||||||
9D98825A19BC69F600B790C6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D98825919BC69F600B790C6 /* Main.storyboard */; };
|
9D98825A19BC69F600B790C6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D98825919BC69F600B790C6 /* Main.storyboard */; };
|
||||||
9D98826719BC874C00B790C6 /* FlatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D98826619BC874C00B790C6 /* FlatButton.swift */; };
|
|
||||||
EA5789A01B20C5B100A9F7D1 /* almost_nailed_it.gif in Resources */ = {isa = PBXBuildFile; fileRef = EA57899F1B20C5B100A9F7D1 /* almost_nailed_it.gif */; };
|
|
||||||
EA5789A71B20C65E00A9F7D1 /* Gifu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA5789A61B20C65800A9F7D1 /* Gifu.framework */; };
|
|
||||||
EA5789A91B20C68B00A9F7D1 /* Gifu.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EA5789A61B20C65800A9F7D1 /* Gifu.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
|
||||||
EA9299291AE99E2900E22976 /* Runes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA9299281AE99E2900E22976 /* Runes.framework */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
|
||||||
EA5789A51B20C65800A9F7D1 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = EA5789A11B20C65800A9F7D1 /* Gifu.xcodeproj */;
|
|
||||||
proxyType = 2;
|
|
||||||
remoteGlobalIDString = 00B8C73E1A364DA400C188E7;
|
|
||||||
remoteInfo = Gifu;
|
|
||||||
};
|
|
||||||
EA5789AA1B20C68B00A9F7D1 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = EA5789A11B20C65800A9F7D1 /* Gifu.xcodeproj */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = 00B8C73D1A364DA400C188E7;
|
|
||||||
remoteInfo = Gifu;
|
|
||||||
};
|
|
||||||
/* End PBXContainerItemProxy section */
|
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
|
||||||
00B8C7331A364D4C00C188E7 /* Embed Frameworks */ = {
|
|
||||||
isa = PBXCopyFilesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
dstPath = "";
|
|
||||||
dstSubfolderSpec = 10;
|
|
||||||
files = (
|
|
||||||
EA5789A91B20C68B00A9F7D1 /* Gifu.framework in Embed Frameworks */,
|
|
||||||
);
|
|
||||||
name = "Embed Frameworks";
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
007380221B279644008DAD5C /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "../Default-568h@2x.png"; sourceTree = "<group>"; };
|
||||||
9D25870519BCCB0F00A55A18 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
9D25870519BCCB0F00A55A18 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
9D25870619BCCB0F00A55A18 /* mugen.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = mugen.gif; sourceTree = "<group>"; };
|
9D98823719BC69CA00B790C6 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
9D98823719BC69CA00B790C6 /* gifu-demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "gifu-demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
9D98823C19BC69CA00B790C6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = classes/AppDelegate.swift; sourceTree = "<group>"; };
|
9D98823C19BC69CA00B790C6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = classes/AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
9D98823E19BC69CA00B790C6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = classes/ViewController.swift; sourceTree = "<group>"; };
|
9D98823E19BC69CA00B790C6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = classes/ViewController.swift; sourceTree = "<group>"; };
|
||||||
9D98824319BC69CA00B790C6 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
9D98824319BC69CA00B790C6 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||||
9D98825919BC69F600B790C6 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
|
9D98825919BC69F600B790C6 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
|
||||||
9D98826619BC874C00B790C6 /* FlatButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FlatButton.swift; path = classes/FlatButton.swift; sourceTree = "<group>"; };
|
|
||||||
EA57899F1B20C5B100A9F7D1 /* almost_nailed_it.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = almost_nailed_it.gif; sourceTree = "<group>"; };
|
|
||||||
EA5789A11B20C65800A9F7D1 /* Gifu.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Gifu.xcodeproj; path = ../Gifu.xcodeproj; sourceTree = "<group>"; };
|
|
||||||
EA9299281AE99E2900E22976 /* Runes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Runes.framework; path = ../Carthage/Build/iOS/Runes.framework; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -69,8 +29,6 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
EA9299291AE99E2900E22976 /* Runes.framework in Frameworks */,
|
|
||||||
EA5789A71B20C65E00A9F7D1 /* Gifu.framework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -80,7 +38,6 @@
|
||||||
9D98822E19BC69CA00B790C6 = {
|
9D98822E19BC69CA00B790C6 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
EA92992C1AE9AB2100E22976 /* Frameworks */,
|
|
||||||
9D98823919BC69CA00B790C6 /* Source */,
|
9D98823919BC69CA00B790C6 /* Source */,
|
||||||
9D98823819BC69CA00B790C6 /* Products */,
|
9D98823819BC69CA00B790C6 /* Products */,
|
||||||
);
|
);
|
||||||
|
@ -89,7 +46,7 @@
|
||||||
9D98823819BC69CA00B790C6 /* Products */ = {
|
9D98823819BC69CA00B790C6 /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
9D98823719BC69CA00B790C6 /* gifu-demo.app */,
|
9D98823719BC69CA00B790C6 /* Demo.app */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -99,7 +56,6 @@
|
||||||
children = (
|
children = (
|
||||||
9D98823C19BC69CA00B790C6 /* AppDelegate.swift */,
|
9D98823C19BC69CA00B790C6 /* AppDelegate.swift */,
|
||||||
9D98823E19BC69CA00B790C6 /* ViewController.swift */,
|
9D98823E19BC69CA00B790C6 /* ViewController.swift */,
|
||||||
9D98826619BC874C00B790C6 /* FlatButton.swift */,
|
|
||||||
9D98825919BC69F600B790C6 /* Main.storyboard */,
|
9D98825919BC69F600B790C6 /* Main.storyboard */,
|
||||||
9D98824319BC69CA00B790C6 /* Images.xcassets */,
|
9D98824319BC69CA00B790C6 /* Images.xcassets */,
|
||||||
9D98823A19BC69CA00B790C6 /* Supporting Files */,
|
9D98823A19BC69CA00B790C6 /* Supporting Files */,
|
||||||
|
@ -111,51 +67,30 @@
|
||||||
9D98823A19BC69CA00B790C6 /* Supporting Files */ = {
|
9D98823A19BC69CA00B790C6 /* Supporting Files */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
007380221B279644008DAD5C /* Default-568h@2x.png */,
|
||||||
9D25870519BCCB0F00A55A18 /* Info.plist */,
|
9D25870519BCCB0F00A55A18 /* Info.plist */,
|
||||||
EA57899F1B20C5B100A9F7D1 /* almost_nailed_it.gif */,
|
|
||||||
9D25870619BCCB0F00A55A18 /* mugen.gif */,
|
|
||||||
);
|
);
|
||||||
name = "Supporting Files";
|
name = "Supporting Files";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
EA5789A21B20C65800A9F7D1 /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
EA5789A61B20C65800A9F7D1 /* Gifu.framework */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
EA92992C1AE9AB2100E22976 /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
EA5789A11B20C65800A9F7D1 /* Gifu.xcodeproj */,
|
|
||||||
EA9299281AE99E2900E22976 /* Runes.framework */,
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
9D98823619BC69CA00B790C6 /* gifu-demo */ = {
|
9D98823619BC69CA00B790C6 /* Demo */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 9D98825319BC69CA00B790C6 /* Build configuration list for PBXNativeTarget "gifu-demo" */;
|
buildConfigurationList = 9D98825319BC69CA00B790C6 /* Build configuration list for PBXNativeTarget "Demo" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
9D98823319BC69CA00B790C6 /* Sources */,
|
9D98823319BC69CA00B790C6 /* Sources */,
|
||||||
9D98823419BC69CA00B790C6 /* Frameworks */,
|
9D98823419BC69CA00B790C6 /* Frameworks */,
|
||||||
9D98823519BC69CA00B790C6 /* Resources */,
|
9D98823519BC69CA00B790C6 /* Resources */,
|
||||||
00B8C7331A364D4C00C188E7 /* Embed Frameworks */,
|
|
||||||
EA92992B1AE99E5600E22976 /* ShellScript */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
EA5789AB1B20C68B00A9F7D1 /* PBXTargetDependency */,
|
|
||||||
);
|
);
|
||||||
name = "gifu-demo";
|
name = Demo;
|
||||||
productName = "gifu-demo";
|
productName = "gifu-demo";
|
||||||
productReference = 9D98823719BC69CA00B790C6 /* gifu-demo.app */;
|
productReference = 9D98823719BC69CA00B790C6 /* Demo.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
/* End PBXNativeTarget section */
|
/* End PBXNativeTarget section */
|
||||||
|
@ -164,7 +99,8 @@
|
||||||
9D98822F19BC69CA00B790C6 /* Project object */ = {
|
9D98822F19BC69CA00B790C6 /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0600;
|
LastSwiftUpdateCheck = 0700;
|
||||||
|
LastUpgradeCheck = 0700;
|
||||||
ORGANIZATIONNAME = "Kaishin & Co";
|
ORGANIZATIONNAME = "Kaishin & Co";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
9D98823619BC69CA00B790C6 = {
|
9D98823619BC69CA00B790C6 = {
|
||||||
|
@ -183,60 +119,26 @@
|
||||||
mainGroup = 9D98822E19BC69CA00B790C6;
|
mainGroup = 9D98822E19BC69CA00B790C6;
|
||||||
productRefGroup = 9D98823819BC69CA00B790C6 /* Products */;
|
productRefGroup = 9D98823819BC69CA00B790C6 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectReferences = (
|
|
||||||
{
|
|
||||||
ProductGroup = EA5789A21B20C65800A9F7D1 /* Products */;
|
|
||||||
ProjectRef = EA5789A11B20C65800A9F7D1 /* Gifu.xcodeproj */;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
9D98823619BC69CA00B790C6 /* gifu-demo */,
|
9D98823619BC69CA00B790C6 /* Demo */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
||||||
/* Begin PBXReferenceProxy section */
|
|
||||||
EA5789A61B20C65800A9F7D1 /* Gifu.framework */ = {
|
|
||||||
isa = PBXReferenceProxy;
|
|
||||||
fileType = wrapper.framework;
|
|
||||||
path = Gifu.framework;
|
|
||||||
remoteRef = EA5789A51B20C65800A9F7D1 /* PBXContainerItemProxy */;
|
|
||||||
sourceTree = BUILT_PRODUCTS_DIR;
|
|
||||||
};
|
|
||||||
/* End PBXReferenceProxy section */
|
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
9D98823519BC69CA00B790C6 /* Resources */ = {
|
9D98823519BC69CA00B790C6 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
EA5789A01B20C5B100A9F7D1 /* almost_nailed_it.gif in Resources */,
|
|
||||||
9D98824419BC69CA00B790C6 /* Images.xcassets in Resources */,
|
9D98824419BC69CA00B790C6 /* Images.xcassets in Resources */,
|
||||||
9D25870819BCCB0F00A55A18 /* mugen.gif in Resources */,
|
007380231B279644008DAD5C /* Default-568h@2x.png in Resources */,
|
||||||
9D98825A19BC69F600B790C6 /* Main.storyboard in Resources */,
|
9D98825A19BC69F600B790C6 /* Main.storyboard in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
|
||||||
EA92992B1AE99E5600E22976 /* ShellScript */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"$(SRCROOT)/../Carthage/Build/iOS/Runes.framework",
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "/usr/local/bin/carthage copy-frameworks";
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
9D98823319BC69CA00B790C6 /* Sources */ = {
|
9D98823319BC69CA00B790C6 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
|
@ -244,20 +146,11 @@
|
||||||
files = (
|
files = (
|
||||||
9D98823F19BC69CA00B790C6 /* ViewController.swift in Sources */,
|
9D98823F19BC69CA00B790C6 /* ViewController.swift in Sources */,
|
||||||
9D98823D19BC69CA00B790C6 /* AppDelegate.swift in Sources */,
|
9D98823D19BC69CA00B790C6 /* AppDelegate.swift in Sources */,
|
||||||
9D98826719BC874C00B790C6 /* FlatButton.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
|
||||||
EA5789AB1B20C68B00A9F7D1 /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
name = Gifu;
|
|
||||||
targetProxy = EA5789AA1B20C68B00A9F7D1 /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
/* End PBXTargetDependency section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
9D98825119BC69CA00B790C6 /* Debug */ = {
|
9D98825119BC69CA00B790C6 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
@ -279,6 +172,7 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
@ -340,16 +234,13 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(SRCROOT)/../Carthage/Build/iOS",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = demo/Info.plist;
|
INFOPLIST_FILE = demo/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = co.kaishin.gifu.demo;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
@ -357,16 +248,13 @@
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(SRCROOT)/../Carthage/Build/iOS",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = demo/Info.plist;
|
INFOPLIST_FILE = demo/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = co.kaishin.gifu.demo;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
@ -382,7 +270,7 @@
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
9D98825319BC69CA00B790C6 /* Build configuration list for PBXNativeTarget "gifu-demo" */ = {
|
9D98825319BC69CA00B790C6 /* Build configuration list for PBXNativeTarget "Demo" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
9D98825419BC69CA00B790C6 /* Debug */,
|
9D98825419BC69CA00B790C6 /* Debug */,
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:gifu-demo.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
|
@ -6,17 +6,32 @@
|
||||||
"filename" : "New icon-Small@2x.png",
|
"filename" : "New icon-Small@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "29x29",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "New icon-Small-40@2x.png",
|
"filename" : "New icon-Small-40@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "40x40",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"size" : "60x60",
|
"size" : "60x60",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "New icon-60@2x.png",
|
"filename" : "New icon-60@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "60x60",
|
||||||
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"extent" : "full-screen",
|
|
||||||
"minimum-system-version" : "7.0",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"subtype" : "retina4",
|
|
||||||
"extent" : "full-screen",
|
|
||||||
"minimum-system-version" : "7.0",
|
|
||||||
"scale" : "2x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
},
|
||||||
|
"data" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "mugen.gif"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
0
Demo/demo/mugen.gif → Demo/demo/Images.xcassets/mugen.dataset/mugen.gif
Executable file → Normal file
0
Demo/demo/mugen.gif → Demo/demo/Images.xcassets/mugen.dataset/mugen.gif
Executable file → Normal file
Before Width: | Height: | Size: 933 KiB After Width: | Height: | Size: 933 KiB |
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
},
|
||||||
|
"data" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "nailed.gif"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Before Width: | Height: | Size: 11 MiB After Width: | Height: | Size: 11 MiB |
|
@ -7,7 +7,7 @@
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>co.kaishin.$(PRODUCT_NAME:rfc1034identifier)</string>
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
@ -18,8 +18,6 @@
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
|
||||||
<false/>
|
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="vXZ-lx-hvc">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="vXZ-lx-hvc">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
<deployment identifier="iOS"/>
|
||||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Gifu-->
|
<!--Gifu-->
|
||||||
<scene sceneID="ufC-wZ-h7g">
|
<scene sceneID="ufC-wZ-h7g">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController title="Gifu" id="vXZ-lx-hvc" customClass="ViewController" customModule="gifu_demo" customModuleProvider="target" sceneMemberID="viewController">
|
<viewController title="Gifu" id="vXZ-lx-hvc" customClass="ViewController" customModule="Demo" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
<layoutGuides>
|
<layoutGuides>
|
||||||
<viewControllerLayoutGuide type="top" id="jyV-Pf-zRb"/>
|
<viewControllerLayoutGuide type="top" id="jyV-Pf-zRb"/>
|
||||||
<viewControllerLayoutGuide type="bottom" id="2fi-mo-0CV"/>
|
<viewControllerLayoutGuide type="bottom" id="2fi-mo-0CV"/>
|
||||||
|
@ -17,77 +17,54 @@
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Gifu" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c8Y-41-BaC">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Tap the image to pause/resume" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wsv-cU-WO5">
|
||||||
<rect key="frame" x="284" y="45" width="33" height="21"/>
|
<rect key="frame" x="211" y="79" width="178.5" height="14.5"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="textColor" red="1" green="0.6334223747253418" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Not the Japanese prefecture." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wsv-cU-WO5">
|
<imageView clipsSubviews="YES" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" placeholderIntrinsicWidth="600" placeholderIntrinsicHeight="300" translatesAutoresizingMaskIntoConstraints="NO" id="FSz-xF-Xds" customClass="AnimatableImageView" customModule="Gifu">
|
||||||
<rect key="frame" x="225" y="70" width="150" height="14"/>
|
<rect key="frame" x="0.0" y="143" width="600" height="300"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
<gestureRecognizers/>
|
||||||
<color key="textColor" red="1" green="1" blue="1" alpha="0.5" colorSpace="calibratedRGB"/>
|
<connections>
|
||||||
<nil key="highlightedColor"/>
|
<outletCollection property="gestureRecognizers" destination="yth-9a-24x" appends="YES" id="21e-1P-Idk"/>
|
||||||
</label>
|
</connections>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" placeholderIntrinsicWidth="450" placeholderIntrinsicHeight="300" translatesAutoresizingMaskIntoConstraints="NO" id="FSz-xF-Xds" customClass="AnimatableImageView" customModule="Gifu">
|
|
||||||
<rect key="frame" x="24" y="134" width="552" height="325"/>
|
|
||||||
<color key="backgroundColor" red="0.7725490196" green="0.1764705882" blue="0.1843137255" alpha="1" colorSpace="calibratedRGB"/>
|
|
||||||
</imageView>
|
</imageView>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bFY-3J-OXr" customClass="FlatButton" customModule="gifu_demo" customModuleProvider="target">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Gifu" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c8Y-41-BaC">
|
||||||
<rect key="frame" x="275" y="509" width="50" height="50"/>
|
<rect key="frame" x="283" y="55" width="34" height="20.5"/>
|
||||||
<constraints>
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||||
<constraint firstAttribute="height" constant="50" id="Lmc-xA-WNU"/>
|
<color key="textColor" red="1" green="0.6334223747253418" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraint firstAttribute="width" constant="50" id="eYX-lm-C2V"/>
|
<nil key="highlightedColor"/>
|
||||||
</constraints>
|
</label>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
|
||||||
<color key="tintColor" red="0.99444444444444446" green="1" blue="0.98888888888888893" alpha="1" colorSpace="calibratedRGB"/>
|
|
||||||
<state key="normal" title="❙❙"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleAnimation:" destination="vXZ-lx-hvc" eventType="touchUpInside" id="PvH-3E-LbB"/>
|
|
||||||
</connections>
|
|
||||||
</button>
|
|
||||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="tZ1-rw-Kbd">
|
|
||||||
<rect key="frame" x="236" y="467" width="129" height="29"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="28" id="VXm-pK-heN"/>
|
|
||||||
</constraints>
|
|
||||||
<segments>
|
|
||||||
<segment title="Mugen"/>
|
|
||||||
<segment title="Nailed It"/>
|
|
||||||
</segments>
|
|
||||||
<connections>
|
|
||||||
<action selector="toggleGIF:" destination="vXZ-lx-hvc" eventType="valueChanged" id="W0R-yI-ahi"/>
|
|
||||||
</connections>
|
|
||||||
</segmentedControl>
|
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="0.24722154438495636" green="0.26659342646598816" blue="0.2988148033618927" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="backgroundColor" red="0.98160680789999999" green="0.98160680789999999" blue="0.98160680789999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
|
<color key="tintColor" red="1" green="0.6334223747253418" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="trailingMargin" secondItem="FSz-xF-Xds" secondAttribute="trailing" constant="8" id="8kQ-x1-WJl"/>
|
<constraint firstAttribute="trailing" secondItem="FSz-xF-Xds" secondAttribute="trailing" id="8kQ-x1-WJl"/>
|
||||||
<constraint firstAttribute="centerX" secondItem="bFY-3J-OXr" secondAttribute="centerX" id="CNh-OD-Msi"/>
|
<constraint firstItem="c8Y-41-BaC" firstAttribute="top" secondItem="jyV-Pf-zRb" secondAttribute="bottom" constant="55" id="JHy-q1-JuJ"/>
|
||||||
<constraint firstItem="FSz-xF-Xds" firstAttribute="top" secondItem="wsv-cU-WO5" secondAttribute="bottom" constant="50" id="I39-Ku-NYc"/>
|
|
||||||
<constraint firstItem="c8Y-41-BaC" firstAttribute="top" secondItem="jyV-Pf-zRb" secondAttribute="bottom" constant="25" id="JHy-q1-JuJ"/>
|
|
||||||
<constraint firstAttribute="centerX" secondItem="c8Y-41-BaC" secondAttribute="centerX" id="Kc0-P5-KMZ"/>
|
<constraint firstAttribute="centerX" secondItem="c8Y-41-BaC" secondAttribute="centerX" id="Kc0-P5-KMZ"/>
|
||||||
<constraint firstItem="FSz-xF-Xds" firstAttribute="leading" secondItem="kh9-bI-dsS" secondAttribute="leadingMargin" constant="8" id="O4L-QH-SvV"/>
|
<constraint firstItem="FSz-xF-Xds" firstAttribute="leading" secondItem="kh9-bI-dsS" secondAttribute="leading" id="O4L-QH-SvV"/>
|
||||||
<constraint firstItem="bFY-3J-OXr" firstAttribute="top" secondItem="FSz-xF-Xds" secondAttribute="bottom" constant="50" id="PKi-91-olI"/>
|
<constraint firstItem="FSz-xF-Xds" firstAttribute="top" secondItem="wsv-cU-WO5" secondAttribute="bottom" constant="50" id="ODd-UW-Pca"/>
|
||||||
<constraint firstAttribute="centerX" secondItem="tZ1-rw-Kbd" secondAttribute="centerX" id="QKy-Gl-KPQ"/>
|
|
||||||
<constraint firstItem="bFY-3J-OXr" firstAttribute="top" secondItem="tZ1-rw-Kbd" secondAttribute="bottom" constant="14" id="Vqv-f1-dnH"/>
|
|
||||||
<constraint firstItem="wsv-cU-WO5" firstAttribute="top" secondItem="c8Y-41-BaC" secondAttribute="bottom" constant="4" id="ZG4-fK-WvN"/>
|
<constraint firstItem="wsv-cU-WO5" firstAttribute="top" secondItem="c8Y-41-BaC" secondAttribute="bottom" constant="4" id="ZG4-fK-WvN"/>
|
||||||
<constraint firstItem="tZ1-rw-Kbd" firstAttribute="top" secondItem="FSz-xF-Xds" secondAttribute="bottom" constant="8" id="lu2-sK-QNZ"/>
|
|
||||||
<constraint firstAttribute="centerX" secondItem="FSz-xF-Xds" secondAttribute="centerX" id="oih-yH-vRh"/>
|
<constraint firstAttribute="centerX" secondItem="FSz-xF-Xds" secondAttribute="centerX" id="oih-yH-vRh"/>
|
||||||
<constraint firstItem="2fi-mo-0CV" firstAttribute="top" secondItem="bFY-3J-OXr" secondAttribute="bottom" constant="41" id="w4g-Xu-ht2"/>
|
|
||||||
<constraint firstAttribute="centerX" secondItem="wsv-cU-WO5" secondAttribute="centerX" id="yLb-zR-gfU"/>
|
<constraint firstAttribute="centerX" secondItem="wsv-cU-WO5" secondAttribute="centerX" id="yLb-zR-gfU"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
<nil key="simulatedTopBarMetrics"/>
|
<nil key="simulatedTopBarMetrics"/>
|
||||||
<nil key="simulatedBottomBarMetrics"/>
|
<nil key="simulatedBottomBarMetrics"/>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="button" destination="bFY-3J-OXr" id="MYJ-Xm-nTf"/>
|
|
||||||
<outlet property="imageView" destination="FSz-xF-Xds" id="gtV-MK-Fwd"/>
|
<outlet property="imageView" destination="FSz-xF-Xds" id="gtV-MK-Fwd"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="x5A-6p-PRh" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="x5A-6p-PRh" sceneMemberID="firstResponder"/>
|
||||||
|
<tapGestureRecognizer id="yth-9a-24x">
|
||||||
|
<connections>
|
||||||
|
<action selector="toggleAnimation:" destination="vXZ-lx-hvc" id="AKP-V2-BPy"/>
|
||||||
|
</connections>
|
||||||
|
</tapGestureRecognizer>
|
||||||
</objects>
|
</objects>
|
||||||
|
<point key="canvasLocation" x="330" y="360"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -9,4 +9,3 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
import UIKit
|
|
||||||
|
|
||||||
class FlatButton: UIButton {
|
|
||||||
|
|
||||||
let horizontalPadding: CGFloat = 14.0
|
|
||||||
|
|
||||||
var buttonColor: UIColor?
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
customizeAppearance()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init(coder aDecoder: NSCoder) {
|
|
||||||
super.init(coder: aDecoder)
|
|
||||||
customizeAppearance()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func drawRect(rect: CGRect) {
|
|
||||||
layer.borderColor = tintColor.CGColor
|
|
||||||
setTitleColor(tintColor, forState: UIControlState.Normal)
|
|
||||||
setTitleColor(UIColor.whiteColor(), forState: UIControlState.Selected)
|
|
||||||
}
|
|
||||||
|
|
||||||
func customizeAppearance() {
|
|
||||||
let containsEdgeInsets = !UIEdgeInsetsEqualToEdgeInsets(contentEdgeInsets, UIEdgeInsetsZero)
|
|
||||||
contentEdgeInsets = containsEdgeInsets ? contentEdgeInsets : UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
|
|
||||||
layer.borderWidth = 2.0
|
|
||||||
layer.borderColor = tintColor.CGColor
|
|
||||||
layer.cornerRadius = frame.size.height / 2.0
|
|
||||||
layer.masksToBounds = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override var tintColor: UIColor! {
|
|
||||||
get {
|
|
||||||
if let color = buttonColor {
|
|
||||||
return color
|
|
||||||
} else {
|
|
||||||
return super.tintColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set {
|
|
||||||
super.tintColor = newValue
|
|
||||||
buttonColor = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,37 +2,19 @@ import UIKit
|
||||||
import Gifu
|
import Gifu
|
||||||
|
|
||||||
class ViewController: UIViewController {
|
class ViewController: UIViewController {
|
||||||
|
|
||||||
@IBOutlet weak var imageView: AnimatableImageView!
|
@IBOutlet weak var imageView: AnimatableImageView!
|
||||||
@IBOutlet weak var button: FlatButton!
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
imageView.animateWithImage(named: "mugen.gif")
|
imageView.animateWithImage(named: "mugen.gif")
|
||||||
|
|
||||||
UIApplication.sharedApplication().setStatusBarStyle(.LightContent, animated: false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func toggleAnimation(button: UIButton) {
|
@IBAction func toggleAnimation(sender: AnyObject) {
|
||||||
if imageView.isAnimatingGIF {
|
if imageView.isAnimatingGIF {
|
||||||
imageView.stopAnimatingGIF()
|
imageView.stopAnimatingGIF()
|
||||||
button.layer.backgroundColor = UIColor.whiteColor().CGColor
|
|
||||||
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
|
|
||||||
} else {
|
} else {
|
||||||
imageView.startAnimatingGIF()
|
imageView.startAnimatingGIF()
|
||||||
button.layer.backgroundColor = UIColor.clearColor().CGColor
|
|
||||||
button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func toggleGIF(sender: UISegmentedControl) {
|
|
||||||
imageView.stopAnimatingGIF()
|
|
||||||
|
|
||||||
switch sender.selectedSegmentIndex {
|
|
||||||
case 0: imageView.animateWithImage(named: "mugen.gif")
|
|
||||||
case 1: imageView.animateWithImage(named: "almost_nailed_it.gif")
|
|
||||||
default: imageView.image = .None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,47 +7,94 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
0036ABB71BBD1D0B00C6CC3D /* mugen.gif in Resources */ = {isa = PBXBuildFile; fileRef = 0036ABB61BBD1D0B00C6CC3D /* mugen.gif */; settings = {ASSET_TAGS = (); }; };
|
||||||
|
0036ABB91BBD1D1400C6CC3D /* nailed.gif in Resources */ = {isa = PBXBuildFile; fileRef = 0036ABB81BBD1D1400C6CC3D /* nailed.gif */; settings = {ASSET_TAGS = (); }; };
|
||||||
|
004529921BD82209006493BF /* Runes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 004529911BD82209006493BF /* Runes.swift */; settings = {ASSET_TAGS = (); }; };
|
||||||
005656ED1A6F14D6008A0ED1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 005656EC1A6F14D6008A0ED1 /* Animator.swift */; };
|
005656ED1A6F14D6008A0ED1 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 005656EC1A6F14D6008A0ED1 /* Animator.swift */; };
|
||||||
005656EF1A6F1C26008A0ED1 /* AnimatableImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 005656EE1A6F1C26008A0ED1 /* AnimatableImageView.swift */; };
|
005656EF1A6F1C26008A0ED1 /* AnimatableImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 005656EE1A6F1C26008A0ED1 /* AnimatableImageView.swift */; };
|
||||||
|
009BD1391BBC7F6500FC982B /* GifuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009BD1381BBC7F6500FC982B /* GifuTests.swift */; };
|
||||||
|
009BD13B1BBC7F6500FC982B /* Gifu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B8C73E1A364DA400C188E7 /* Gifu.framework */; settings = {ASSET_TAGS = (); }; };
|
||||||
|
009BD1441BBC93C800FC982B /* CGSizeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 009BD1431BBC93C800FC982B /* CGSizeExtension.swift */; settings = {ASSET_TAGS = (); }; };
|
||||||
00B8C75F1A364DCE00C188E7 /* ImageSourceHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00B8C75C1A364DCE00C188E7 /* ImageSourceHelpers.swift */; };
|
00B8C75F1A364DCE00C188E7 /* ImageSourceHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00B8C75C1A364DCE00C188E7 /* ImageSourceHelpers.swift */; };
|
||||||
00B8C7961A3650EE00C188E7 /* Gifu.h in Headers */ = {isa = PBXBuildFile; fileRef = 00B8C7951A3650EE00C188E7 /* Gifu.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
00B8C7961A3650EE00C188E7 /* Gifu.h in Headers */ = {isa = PBXBuildFile; fileRef = 00B8C7951A3650EE00C188E7 /* Gifu.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
EA1E21131AD5D369000459BD /* Runes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA1E21121AD5D369000459BD /* Runes.framework */; };
|
|
||||||
EAF49C7F1A3A4DE000B395DF /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF49C7E1A3A4DE000B395DF /* UIImageExtension.swift */; };
|
EAF49C7F1A3A4DE000B395DF /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF49C7E1A3A4DE000B395DF /* UIImageExtension.swift */; };
|
||||||
EAF49C811A3A4FAA00B395DF /* Curry.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF49C801A3A4FAA00B395DF /* Curry.swift */; };
|
EAF49C811A3A4FAA00B395DF /* FunctionalHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF49C801A3A4FAA00B395DF /* FunctionalHelpers.swift */; };
|
||||||
EAF49CB11A3B6EEB00B395DF /* AnimatedFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF49CB01A3B6EEB00B395DF /* AnimatedFrame.swift */; };
|
EAF49CB11A3B6EEB00B395DF /* AnimatedFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF49CB01A3B6EEB00B395DF /* AnimatedFrame.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
009BD13C1BBC7F6500FC982B /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 00B8C7351A364DA400C188E7 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 00B8C73D1A364DA400C188E7;
|
||||||
|
remoteInfo = Gifu;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
0036ABB61BBD1D0B00C6CC3D /* mugen.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = mugen.gif; path = Demo/demo/Images.xcassets/mugen.dataset/mugen.gif; sourceTree = SOURCE_ROOT; };
|
||||||
|
0036ABB81BBD1D1400C6CC3D /* nailed.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = nailed.gif; path = Demo/demo/Images.xcassets/nailed.dataset/nailed.gif; sourceTree = SOURCE_ROOT; };
|
||||||
|
004529911BD82209006493BF /* Runes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Runes.swift; path = Carthage/Checkouts/Runes/Source/Runes.swift; sourceTree = SOURCE_ROOT; };
|
||||||
005656EC1A6F14D6008A0ED1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = "<group>"; };
|
005656EC1A6F14D6008A0ED1 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = "<group>"; };
|
||||||
005656EE1A6F1C26008A0ED1 /* AnimatableImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatableImageView.swift; sourceTree = "<group>"; };
|
005656EE1A6F1C26008A0ED1 /* AnimatableImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatableImageView.swift; sourceTree = "<group>"; };
|
||||||
|
009BD1361BBC7F6500FC982B /* GifuTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GifuTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
009BD1381BBC7F6500FC982B /* GifuTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifuTests.swift; sourceTree = "<group>"; };
|
||||||
|
009BD13A1BBC7F6500FC982B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
009BD1431BBC93C800FC982B /* CGSizeExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGSizeExtension.swift; sourceTree = "<group>"; };
|
||||||
00B8C73E1A364DA400C188E7 /* Gifu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Gifu.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
00B8C73E1A364DA400C188E7 /* Gifu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Gifu.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
00B8C7421A364DA400C188E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Source/Info.plist; sourceTree = "<group>"; };
|
00B8C7421A364DA400C188E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Source/Info.plist; sourceTree = "<group>"; };
|
||||||
00B8C75C1A364DCE00C188E7 /* ImageSourceHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageSourceHelpers.swift; sourceTree = "<group>"; };
|
00B8C75C1A364DCE00C188E7 /* ImageSourceHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageSourceHelpers.swift; sourceTree = "<group>"; };
|
||||||
00B8C7951A3650EE00C188E7 /* Gifu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Gifu.h; sourceTree = "<group>"; };
|
00B8C7951A3650EE00C188E7 /* Gifu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Gifu.h; sourceTree = "<group>"; };
|
||||||
EA1E21121AD5D369000459BD /* Runes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Runes.framework; path = Carthage/Build/iOS/Runes.framework; sourceTree = "<group>"; };
|
|
||||||
EAF49C7E1A3A4DE000B395DF /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = "<group>"; };
|
EAF49C7E1A3A4DE000B395DF /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageExtension.swift; sourceTree = "<group>"; };
|
||||||
EAF49C801A3A4FAA00B395DF /* Curry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Curry.swift; sourceTree = "<group>"; };
|
EAF49C801A3A4FAA00B395DF /* FunctionalHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FunctionalHelpers.swift; sourceTree = "<group>"; };
|
||||||
EAF49CB01A3B6EEB00B395DF /* AnimatedFrame.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatedFrame.swift; sourceTree = "<group>"; };
|
EAF49CB01A3B6EEB00B395DF /* AnimatedFrame.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatedFrame.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
009BD1331BBC7F6500FC982B /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
009BD13B1BBC7F6500FC982B /* Gifu.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
00B8C73A1A364DA400C188E7 /* Frameworks */ = {
|
00B8C73A1A364DA400C188E7 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
EA1E21131AD5D369000459BD /* Runes.framework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
0036ABBA1BBD1D1700C6CC3D /* Images */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0036ABB61BBD1D0B00C6CC3D /* mugen.gif */,
|
||||||
|
0036ABB81BBD1D1400C6CC3D /* nailed.gif */,
|
||||||
|
);
|
||||||
|
name = Images;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
009BD1371BBC7F6500FC982B /* GifuTests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
009BD1381BBC7F6500FC982B /* GifuTests.swift */,
|
||||||
|
009BD13A1BBC7F6500FC982B /* Info.plist */,
|
||||||
|
0036ABBA1BBD1D1700C6CC3D /* Images */,
|
||||||
|
);
|
||||||
|
path = GifuTests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
00B8C7341A364DA400C188E7 = {
|
00B8C7341A364DA400C188E7 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
EA1E21111AD5D354000459BD /* Frameworks */,
|
|
||||||
00B8C75A1A364DBE00C188E7 /* Source */,
|
00B8C75A1A364DBE00C188E7 /* Source */,
|
||||||
00B8C7411A364DA400C188E7 /* Supporting Files */,
|
00B8C7411A364DA400C188E7 /* Supporting Files */,
|
||||||
|
009BD1371BBC7F6500FC982B /* GifuTests */,
|
||||||
00B8C73F1A364DA400C188E7 /* Products */,
|
00B8C73F1A364DA400C188E7 /* Products */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -56,6 +103,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
00B8C73E1A364DA400C188E7 /* Gifu.framework */,
|
00B8C73E1A364DA400C188E7 /* Gifu.framework */,
|
||||||
|
009BD1361BBC7F6500FC982B /* GifuTests.xctest */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -75,22 +123,16 @@
|
||||||
005656EE1A6F1C26008A0ED1 /* AnimatableImageView.swift */,
|
005656EE1A6F1C26008A0ED1 /* AnimatableImageView.swift */,
|
||||||
EAF49CB01A3B6EEB00B395DF /* AnimatedFrame.swift */,
|
EAF49CB01A3B6EEB00B395DF /* AnimatedFrame.swift */,
|
||||||
005656EC1A6F14D6008A0ED1 /* Animator.swift */,
|
005656EC1A6F14D6008A0ED1 /* Animator.swift */,
|
||||||
|
009BD1431BBC93C800FC982B /* CGSizeExtension.swift */,
|
||||||
|
EAF49C801A3A4FAA00B395DF /* FunctionalHelpers.swift */,
|
||||||
00B8C7951A3650EE00C188E7 /* Gifu.h */,
|
00B8C7951A3650EE00C188E7 /* Gifu.h */,
|
||||||
00B8C75C1A364DCE00C188E7 /* ImageSourceHelpers.swift */,
|
00B8C75C1A364DCE00C188E7 /* ImageSourceHelpers.swift */,
|
||||||
EAF49C7E1A3A4DE000B395DF /* UIImageExtension.swift */,
|
EAF49C7E1A3A4DE000B395DF /* UIImageExtension.swift */,
|
||||||
EAF49C801A3A4FAA00B395DF /* Curry.swift */,
|
004529911BD82209006493BF /* Runes.swift */,
|
||||||
);
|
);
|
||||||
path = Source;
|
path = Source;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
EA1E21111AD5D354000459BD /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
EA1E21121AD5D369000459BD /* Runes.framework */,
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXHeadersBuildPhase section */
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
@ -105,6 +147,24 @@
|
||||||
/* End PBXHeadersBuildPhase section */
|
/* End PBXHeadersBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
009BD1351BBC7F6500FC982B /* GifuTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 009BD1401BBC7F6500FC982B /* Build configuration list for PBXNativeTarget "GifuTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
009BD1321BBC7F6500FC982B /* Sources */,
|
||||||
|
009BD1331BBC7F6500FC982B /* Frameworks */,
|
||||||
|
009BD1341BBC7F6500FC982B /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
009BD13D1BBC7F6500FC982B /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = GifuTests;
|
||||||
|
productName = GifuTests;
|
||||||
|
productReference = 009BD1361BBC7F6500FC982B /* GifuTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
00B8C73D1A364DA400C188E7 /* Gifu */ = {
|
00B8C73D1A364DA400C188E7 /* Gifu */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 00B8C7541A364DA500C188E7 /* Build configuration list for PBXNativeTarget "Gifu" */;
|
buildConfigurationList = 00B8C7541A364DA500C188E7 /* Build configuration list for PBXNativeTarget "Gifu" */;
|
||||||
|
@ -129,9 +189,13 @@
|
||||||
00B8C7351A364DA400C188E7 /* Project object */ = {
|
00B8C7351A364DA400C188E7 /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0610;
|
LastSwiftUpdateCheck = 0700;
|
||||||
|
LastUpgradeCheck = 0700;
|
||||||
ORGANIZATIONNAME = "Kaishin & Co";
|
ORGANIZATIONNAME = "Kaishin & Co";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
|
009BD1351BBC7F6500FC982B = {
|
||||||
|
CreatedOnToolsVersion = 7.0.1;
|
||||||
|
};
|
||||||
00B8C73D1A364DA400C188E7 = {
|
00B8C73D1A364DA400C188E7 = {
|
||||||
CreatedOnToolsVersion = 6.1.1;
|
CreatedOnToolsVersion = 6.1.1;
|
||||||
};
|
};
|
||||||
|
@ -150,11 +214,21 @@
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
00B8C73D1A364DA400C188E7 /* Gifu */,
|
00B8C73D1A364DA400C188E7 /* Gifu */,
|
||||||
|
009BD1351BBC7F6500FC982B /* GifuTests */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
009BD1341BBC7F6500FC982B /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
0036ABB71BBD1D0B00C6CC3D /* mugen.gif in Resources */,
|
||||||
|
0036ABB91BBD1D1400C6CC3D /* nailed.gif in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
00B8C73C1A364DA400C188E7 /* Resources */ = {
|
00B8C73C1A364DA400C188E7 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -165,22 +239,67 @@
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
009BD1321BBC7F6500FC982B /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
009BD1391BBC7F6500FC982B /* GifuTests.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
00B8C7391A364DA400C188E7 /* Sources */ = {
|
00B8C7391A364DA400C188E7 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
005656EF1A6F1C26008A0ED1 /* AnimatableImageView.swift in Sources */,
|
005656EF1A6F1C26008A0ED1 /* AnimatableImageView.swift in Sources */,
|
||||||
005656ED1A6F14D6008A0ED1 /* Animator.swift in Sources */,
|
005656ED1A6F14D6008A0ED1 /* Animator.swift in Sources */,
|
||||||
|
009BD1441BBC93C800FC982B /* CGSizeExtension.swift in Sources */,
|
||||||
|
004529921BD82209006493BF /* Runes.swift in Sources */,
|
||||||
EAF49CB11A3B6EEB00B395DF /* AnimatedFrame.swift in Sources */,
|
EAF49CB11A3B6EEB00B395DF /* AnimatedFrame.swift in Sources */,
|
||||||
00B8C75F1A364DCE00C188E7 /* ImageSourceHelpers.swift in Sources */,
|
00B8C75F1A364DCE00C188E7 /* ImageSourceHelpers.swift in Sources */,
|
||||||
EAF49C811A3A4FAA00B395DF /* Curry.swift in Sources */,
|
EAF49C811A3A4FAA00B395DF /* FunctionalHelpers.swift in Sources */,
|
||||||
EAF49C7F1A3A4DE000B395DF /* UIImageExtension.swift in Sources */,
|
EAF49C7F1A3A4DE000B395DF /* UIImageExtension.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
009BD13D1BBC7F6500FC982B /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 00B8C73D1A364DA400C188E7 /* Gifu */;
|
||||||
|
targetProxy = 009BD13C1BBC7F6500FC982B /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
|
009BD13E1BBC7F6500FC982B /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
INFOPLIST_FILE = GifuTests/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = co.kaishin.GifuTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
009BD13F1BBC7F6500FC982B /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
INFOPLIST_FILE = GifuTests/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = co.kaishin.GifuTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
00B8C7521A364DA500C188E7 /* Debug */ = {
|
00B8C7521A364DA500C188E7 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
@ -202,6 +321,7 @@
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
@ -269,18 +389,17 @@
|
||||||
00B8C7551A364DA500C188E7 /* Debug */ = {
|
00B8C7551A364DA500C188E7 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Carthage/Build/iOS",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = co.kaishin.gifu;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
@ -290,18 +409,17 @@
|
||||||
00B8C7561A364DA500C188E7 /* Release */ = {
|
00B8C7561A364DA500C188E7 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
DYLIB_CURRENT_VERSION = 1;
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Carthage/Build/iOS",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = co.kaishin.gifu;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
};
|
};
|
||||||
|
@ -310,6 +428,15 @@
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
009BD1401BBC7F6500FC982B /* Build configuration list for PBXNativeTarget "GifuTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
009BD13E1BBC7F6500FC982B /* Debug */,
|
||||||
|
009BD13F1BBC7F6500FC982B /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
00B8C7381A364DA400C188E7 /* Build configuration list for PBXProject "Gifu" */ = {
|
00B8C7381A364DA400C188E7 /* Build configuration list for PBXProject "Gifu" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?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>classNames</key>
|
||||||
|
<dict>
|
||||||
|
<key>GifuTests</key>
|
||||||
|
<dict>
|
||||||
|
<key>testPrepareFramesPerformance()</key>
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
|
||||||
|
<dict>
|
||||||
|
<key>baselineAverage</key>
|
||||||
|
<real>0.003825</real>
|
||||||
|
<key>baselineIntegrationDisplayName</key>
|
||||||
|
<string>Local Baseline</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?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>runDestinationsByUUID</key>
|
||||||
|
<dict>
|
||||||
|
<key>17E637F3-A123-4EFF-966F-BFFEA8927264</key>
|
||||||
|
<dict>
|
||||||
|
<key>localComputer</key>
|
||||||
|
<dict>
|
||||||
|
<key>busSpeedInMHz</key>
|
||||||
|
<integer>100</integer>
|
||||||
|
<key>cpuCount</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>cpuKind</key>
|
||||||
|
<string>Intel Core i7</string>
|
||||||
|
<key>cpuSpeedInMHz</key>
|
||||||
|
<integer>2700</integer>
|
||||||
|
<key>logicalCPUCoresPerPackage</key>
|
||||||
|
<integer>8</integer>
|
||||||
|
<key>modelCode</key>
|
||||||
|
<string>MacBookPro10,1</string>
|
||||||
|
<key>physicalCPUCoresPerPackage</key>
|
||||||
|
<integer>4</integer>
|
||||||
|
<key>platformIdentifier</key>
|
||||||
|
<string>com.apple.platform.macosx</string>
|
||||||
|
</dict>
|
||||||
|
<key>targetArchitecture</key>
|
||||||
|
<string>x86_64</string>
|
||||||
|
<key>targetDevice</key>
|
||||||
|
<dict>
|
||||||
|
<key>modelCode</key>
|
||||||
|
<string>iPhone8,1</string>
|
||||||
|
<key>platformIdentifier</key>
|
||||||
|
<string>com.apple.platform.iphonesimulator</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0610"
|
LastUpgradeVersion = "0700"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
buildForAnalyzing = "YES">
|
buildForAnalyzing = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "00B8C7481A364DA500C188E7"
|
BlueprintIdentifier = "009BD1351BBC7F6500FC982B"
|
||||||
BuildableName = "GifuTests.xctest"
|
BuildableName = "GifuTests.xctest"
|
||||||
BlueprintName = "GifuTests"
|
BlueprintName = "GifuTests"
|
||||||
ReferencedContainer = "container:Gifu.xcodeproj">
|
ReferencedContainer = "container:Gifu.xcodeproj">
|
||||||
|
@ -37,16 +37,16 @@
|
||||||
</BuildActionEntries>
|
</BuildActionEntries>
|
||||||
</BuildAction>
|
</BuildAction>
|
||||||
<TestAction
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
buildConfiguration = "Debug">
|
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "NO">
|
skipped = "NO">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "00B8C7481A364DA500C188E7"
|
BlueprintIdentifier = "009BD1351BBC7F6500FC982B"
|
||||||
BuildableName = "GifuTests.xctest"
|
BuildableName = "GifuTests.xctest"
|
||||||
BlueprintName = "GifuTests"
|
BlueprintName = "GifuTests"
|
||||||
ReferencedContainer = "container:Gifu.xcodeproj">
|
ReferencedContainer = "container:Gifu.xcodeproj">
|
||||||
|
@ -62,15 +62,18 @@
|
||||||
ReferencedContainer = "container:Gifu.xcodeproj">
|
ReferencedContainer = "container:Gifu.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
buildConfiguration = "Debug"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES">
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
|
@ -85,10 +88,10 @@
|
||||||
</AdditionalOptions>
|
</AdditionalOptions>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
savedToolIdentifier = ""
|
savedToolIdentifier = ""
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
buildConfiguration = "Release"
|
|
||||||
debugDocumentVersioning = "YES">
|
debugDocumentVersioning = "YES">
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
<Workspace
|
<Workspace
|
||||||
version = "1.0">
|
version = "1.0">
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Demo.xcodeproj">
|
location = "group:Gifu.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:../Gifu.xcodeproj">
|
location = "group:Demo/Demo.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
|
@ -0,0 +1,60 @@
|
||||||
|
import XCTest
|
||||||
|
import ImageIO
|
||||||
|
@testable import Gifu
|
||||||
|
|
||||||
|
private let imageData = testImageDataNamed("mugen.gif")
|
||||||
|
private let staticImage = UIImage(data: imageData!)
|
||||||
|
|
||||||
|
class GifuTests: XCTestCase {
|
||||||
|
var animator: Animator?
|
||||||
|
var originalFrameCount: Int?
|
||||||
|
var preloadedFrameCount: Int?
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
|
animator = Animator(data: imageData!, size: CGSizeZero, contentMode: .ScaleToFill, framePreloadCount: 20)
|
||||||
|
animator!.prepareFrames()
|
||||||
|
originalFrameCount = Int(CGImageSourceGetCount(animator!.imageSource))
|
||||||
|
preloadedFrameCount = animator!.animatedFrames.count
|
||||||
|
}
|
||||||
|
|
||||||
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testIsAnimatable() {
|
||||||
|
XCTAssertTrue(animator!.isAnimatable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFramePreload() {
|
||||||
|
XCTAssertLessThanOrEqual(preloadedFrameCount!, originalFrameCount!)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFrameAtIndex() {
|
||||||
|
XCTAssertNotNil(animator!.frameAtIndex(preloadedFrameCount! - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFrameDurationPrecision() {
|
||||||
|
let image = animator!.frameAtIndex(5)
|
||||||
|
XCTAssertTrue((image!.duration - 0.05) < 0.00001)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFrameSize() {
|
||||||
|
let image = animator!.frameAtIndex(5)
|
||||||
|
XCTAssertEqual(image!.size, staticImage!.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPrepareFramesPerformance() {
|
||||||
|
let tempAnimator = Animator(data: imageData!, size: CGSizeZero, contentMode: .ScaleToFill, framePreloadCount: 50)
|
||||||
|
|
||||||
|
self.measureBlock() {
|
||||||
|
tempAnimator.prepareFrames()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func testImageDataNamed(name: String) -> NSData? {
|
||||||
|
let testBundle = NSBundle(forClass: GifuTests.self)
|
||||||
|
let imagePath = testBundle.bundleURL.URLByAppendingPathComponent(name)
|
||||||
|
return NSData(contentsOfURL: imagePath)
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?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>
|
39
README.md
39
README.md
|
@ -1,15 +1,18 @@
|
||||||
<img src="https://db.tt/mZ1iMNXO" width="100" />
|
<img src="https://db.tt/mZ1iMNXO" width="100" />
|
||||||
|
|
||||||
Adds performant animated GIF support to UIKit, without subclassing `UIImageView`. If you're looking for the Japanese prefecture, click [here](https://goo.gl/maps/CCeAc).
|
Adds performant animated GIF support to UIKit. If you're looking for the Japanese prefecture, click [here](https://goo.gl/maps/CCeAc).
|
||||||
|
|
||||||
#### Why?
|
|
||||||
|
|
||||||
Because Apple's `+animatedImage*` is not meant to be used for animated GIFs (loads all the full-sized frames in memory), and the few third party implementations that got it right (see [Credits](#credits)) still require you to use a `UIImageView` subclass, which is not very flexible and might clash with other application-specific functionality.
|
|
||||||
|
|
||||||
#### How?
|
#### How?
|
||||||
|
|
||||||
Gifu uses a `UIImage` subclass and `UIImageView` extension written in Swift.
|
Gifu uses a `UIImageView` subclass and an animator that keeps track of frames and their durations.
|
||||||
It relies on `CADisplayLink` to animate the view and optimizes the frames by resizing them.
|
|
||||||
|
It uses `CADisplayLink` to animate the view and only keeps a limited number of
|
||||||
|
resized frames in-memory, which exponentially minimizes memory usage for large GIF files (+300 frames).
|
||||||
|
|
||||||
|
The figure below summarizes how this works in practice. Given an image
|
||||||
|
containing 10 frames, Gifu will load the current frame (red), pre-load the next two frames in this example (orange), and nullify all the other frames to free up memory (gray):
|
||||||
|
|
||||||
|
<img src="https://db.tt/ZLfx23hg" width="300" />
|
||||||
|
|
||||||
#### Install
|
#### Install
|
||||||
|
|
||||||
|
@ -19,25 +22,20 @@ If your prefer Git submodules or want to support iOS 7, you want to add the file
|
||||||
|
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
Start by instantiating an `AnimatedImage`, then pass it to your `UIImageView`'s `setAnimatedImage`:
|
Start by instantiating an `AnimatableImageView` either in code or Interface Builder, then call `animateWithImage(named:)` or `animateWithImageData(data:)` on it.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let image = AnimatedImage.animatedImageWithName("mugen.gif") {
|
let imageView = AnimatableImageView(frame: CGRect(...))
|
||||||
imageView.setAnimatedImage(image)
|
imageView.animateWithImage(named: "mugen.gif")
|
||||||
imageView.startAnimatingGIF()
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
Note that the image view will not start animating until you call `startAnimatingGIF()`
|
You can stop the animation anytime using `imageView.stopAnimatingGIF()`, and resume
|
||||||
on it. You can stop the animation anytime using `stopAnimatingGIF()`, and resume
|
it using `imageView.startAnimatingGIF()`.
|
||||||
it using `startAnimatingGIF()`. These methods will fallback to UIKit's `startAnimating()` and `stopAnimating()`
|
|
||||||
if the image view has no animatable image.
|
|
||||||
|
|
||||||
Likewise, the `isAnimatingGIF()` method returns the current animation state of the view if it has an animatable image,
|
The `isAnimatingGIF()` method returns the current animation state of the view if it has an animatable image.
|
||||||
or UIKit's `isAnimating()` otherwise.
|
|
||||||
|
|
||||||
#### Demo App
|
#### Demo App
|
||||||
|
|
||||||
<img src="https://db.tt/ZoUNLHGp" width="300" />
|
Clone or download the repository and open `Gifu.xcworkspace` to check out the demo app.
|
||||||
|
|
||||||
#### Compatibility
|
#### Compatibility
|
||||||
|
|
||||||
|
@ -46,8 +44,7 @@ or UIKit's `isAnimating()` otherwise.
|
||||||
#### Roadmap
|
#### Roadmap
|
||||||
|
|
||||||
- Documentation.
|
- Documentation.
|
||||||
- Write some basic tests.
|
- Add ability to set the frame-rate
|
||||||
- Add ability to pass a frame-rate argument to `startAnimatingGIF()`
|
|
||||||
|
|
||||||
#### Contributors
|
#### Contributors
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import Runes
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
/// A subclass of `UIImageView` that can be animated using an image name string or raw data.
|
/// A subclass of `UIImageView` that can be animated using an image name string or raw data.
|
||||||
public class AnimatableImageView: UIImageView {
|
public class AnimatableImageView: UIImageView {
|
||||||
/// An `Animator` instance that holds the frames of a specific image in memory.
|
/// An `Animator` instance that holds the frames of a specific image in memory.
|
||||||
private var animator: Animator?
|
var animator: Animator?
|
||||||
/// A display link that keeps calling the `updateFrame` method on every screen refresh.
|
/// A display link that keeps calling the `updateFrame` method on every screen refresh.
|
||||||
private lazy var displayLink: CADisplayLink = CADisplayLink(target: self, selector: Selector("updateFrame"))
|
lazy var displayLink: CADisplayLink = CADisplayLink(target: self, selector: Selector("updateFrame"))
|
||||||
|
|
||||||
/// The size of the frame cache.
|
/// The size of the frame cache.
|
||||||
public var framePreloadCount = 50
|
public var framePreloadCount = 50
|
||||||
|
@ -19,15 +18,15 @@ public class AnimatableImageView: UIImageView {
|
||||||
/// Prepares the frames using a GIF image file name, without starting the animation.
|
/// Prepares the frames using a GIF image file name, without starting the animation.
|
||||||
/// The file name should include the `.gif` extension.
|
/// The file name should include the `.gif` extension.
|
||||||
///
|
///
|
||||||
/// :param: imageName The name of the GIF file. The method looks for the file in the app bundle.
|
/// - parameter imageName: The name of the GIF file. The method looks for the file in the app bundle.
|
||||||
public func prepareForAnimation(imageNamed imageName: String) {
|
public func prepareForAnimation(imageNamed imageName: String) {
|
||||||
let path = NSBundle.mainBundle().bundlePath.stringByAppendingPathComponent(imageName)
|
let imagePath = NSBundle.mainBundle().bundleURL.URLByAppendingPathComponent(imageName)
|
||||||
prepareForAnimation <^> NSData(contentsOfFile: path)
|
prepareForAnimation <^> NSData(contentsOfURL: imagePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepares the frames using raw GIF image data, without starting the animation.
|
/// Prepares the frames using raw GIF image data, without starting the animation.
|
||||||
///
|
///
|
||||||
/// :param: data GIF image data.
|
/// - parameter data: GIF image data.
|
||||||
public func prepareForAnimation(imageData data: NSData) {
|
public func prepareForAnimation(imageData data: NSData) {
|
||||||
image = UIImage(data: data)
|
image = UIImage(data: data)
|
||||||
animator = Animator(data: data, size: frame.size, contentMode: contentMode, framePreloadCount: framePreloadCount)
|
animator = Animator(data: data, size: frame.size, contentMode: contentMode, framePreloadCount: framePreloadCount)
|
||||||
|
@ -37,7 +36,7 @@ public class AnimatableImageView: UIImageView {
|
||||||
|
|
||||||
/// Prepares the frames using a GIF image file name and starts animating the image view.
|
/// Prepares the frames using a GIF image file name and starts animating the image view.
|
||||||
///
|
///
|
||||||
/// :param: imageName The name of the GIF file. The method looks for the file in the app bundle.
|
/// - parameter imageName: The name of the GIF file. The method looks for the file in the app bundle.
|
||||||
public func animateWithImage(named imageName: String) {
|
public func animateWithImage(named imageName: String) {
|
||||||
prepareForAnimation(imageNamed: imageName)
|
prepareForAnimation(imageNamed: imageName)
|
||||||
startAnimatingGIF()
|
startAnimatingGIF()
|
||||||
|
@ -45,24 +44,17 @@ public class AnimatableImageView: UIImageView {
|
||||||
|
|
||||||
/// Prepares the frames using raw GIF image data and starts animating the image view.
|
/// Prepares the frames using raw GIF image data and starts animating the image view.
|
||||||
///
|
///
|
||||||
/// :param: data GIF image data.
|
/// - parameter data: GIF image data.
|
||||||
public func animateWithImageData(#data: NSData) {
|
public func animateWithImageData(data: NSData) {
|
||||||
prepareForAnimation(imageData: data)
|
prepareForAnimation(imageData: data)
|
||||||
startAnimatingGIF()
|
startAnimatingGIF()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the `UIImage` property of the image view if necessary. This method should not be called manually.
|
/// Updates the `image` property of the image view if necessary. This method should not be called manually.
|
||||||
override public func displayLayer(layer: CALayer!) {
|
override public func displayLayer(layer: CALayer) {
|
||||||
image = animator?.currentFrame
|
image = animator?.currentFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the current frame with the displayLink duration
|
|
||||||
func updateFrame() {
|
|
||||||
if animator?.updateCurrentFrame(displayLink.duration) ?? false {
|
|
||||||
layer.setNeedsDisplay()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starts the image view animation.
|
/// Starts the image view animation.
|
||||||
public func startAnimatingGIF() {
|
public func startAnimatingGIF() {
|
||||||
if animator?.isAnimatable ?? false {
|
if animator?.isAnimatable ?? false {
|
||||||
|
@ -75,13 +67,20 @@ public class AnimatableImageView: UIImageView {
|
||||||
displayLink.paused = true
|
displayLink.paused = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the current frame with the displayLink duration
|
||||||
|
func updateFrame() {
|
||||||
|
if animator?.updateCurrentFrame(displayLink.duration) ?? false {
|
||||||
|
layer.setNeedsDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Invalidate the displayLink so it releases this object.
|
/// Invalidate the displayLink so it releases this object.
|
||||||
public func cleanup() {
|
deinit {
|
||||||
displayLink.invalidate()
|
displayLink.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attaches the display link.
|
/// Attaches the display link.
|
||||||
private func attachDisplayLink() {
|
func attachDisplayLink() {
|
||||||
displayLink.addToRunLoop(.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
displayLink.addToRunLoop(.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,9 @@
|
||||||
struct AnimatedFrame {
|
struct AnimatedFrame {
|
||||||
let image: UIImage?
|
let image: UIImage?
|
||||||
let duration: NSTimeInterval
|
let duration: NSTimeInterval
|
||||||
|
|
||||||
|
static func null() -> AnimatedFrame {
|
||||||
|
return AnimatedFrame(image: .None, duration: 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,28 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import ImageIO
|
import ImageIO
|
||||||
import Runes
|
|
||||||
|
|
||||||
/// Responsible for storing and updating the frames of a `AnimatableImageView` instance via delegation.
|
/// Responsible for storing and updating the frames of a `AnimatableImageView` instance via delegation.
|
||||||
class Animator {
|
class Animator {
|
||||||
/// Maximum duration to increment the frame timer with.
|
/// Maximum duration to increment the frame timer with.
|
||||||
private let maxTimeStep = 1.0
|
let maxTimeStep = 1.0
|
||||||
/// An array of animated frames from a single GIF image.
|
/// An array of animated frames from a single GIF image.
|
||||||
private var animatedFrames = [AnimatedFrame]()
|
var animatedFrames = [AnimatedFrame]()
|
||||||
/// The size to resize all frames to
|
/// The size to resize all frames to
|
||||||
private let size: CGSize
|
let size: CGSize
|
||||||
/// The content mode to use when resizing
|
/// The content mode to use when resizing
|
||||||
private let contentMode: UIViewContentMode
|
let contentMode: UIViewContentMode
|
||||||
/// Maximum number of frames to load at once
|
/// Maximum number of frames to load at once
|
||||||
private let maxNumberOfFrames: Int
|
let maxFrameCount: Int
|
||||||
/// The total number of frames in the GIF.
|
/// The total number of frames in the GIF.
|
||||||
private var numberOfFrames = 0
|
var frameCount = 0
|
||||||
/// A reference to the original image source.
|
/// A reference to the original image source.
|
||||||
private var imageSource: CGImageSourceRef
|
var imageSource: CGImageSourceRef
|
||||||
/// The index of the current GIF frame.
|
/// The index of the current GIF frame.
|
||||||
private var currentFrameIndex = 0
|
var currentFrameIndex = 0
|
||||||
/// The index of the current GIF frame from the source.
|
/// The index of the current GIF frame from the source.
|
||||||
private var currentPreloadIndex = 0
|
var currentPreloadIndex = 0
|
||||||
/// Time elapsed since the last frame change. Used to determine when the frame should be updated.
|
/// Time elapsed since the last frame change. Used to determine when the frame should be updated.
|
||||||
private var timeSinceLastFrameChange: NSTimeInterval = 0.0
|
var timeSinceLastFrameChange: NSTimeInterval = 0.0
|
||||||
|
|
||||||
/// The current image frame to show.
|
/// The current image frame to show.
|
||||||
var currentFrame: UIImage? {
|
var currentFrame: UIImage? {
|
||||||
|
@ -37,41 +36,43 @@ class Animator {
|
||||||
|
|
||||||
/// Initializes an animator instance from raw GIF image data and an `Animatable` delegate.
|
/// Initializes an animator instance from raw GIF image data and an `Animatable` delegate.
|
||||||
///
|
///
|
||||||
/// :param: data The raw GIF image data.
|
/// - parameter data: The raw GIF image data.
|
||||||
/// :param: delegate An `Animatable` delegate.
|
/// - parameter delegate: An `Animatable` delegate.
|
||||||
init(data: NSData, size: CGSize, contentMode: UIViewContentMode, framePreloadCount: Int) {
|
init(data: NSData, size: CGSize, contentMode: UIViewContentMode, framePreloadCount: Int) {
|
||||||
let options = [String(kCGImageSourceShouldCache): kCFBooleanFalse]
|
let options = [String(kCGImageSourceShouldCache): kCFBooleanFalse]
|
||||||
imageSource = CGImageSourceCreateWithData(data, options)
|
self.imageSource = CGImageSourceCreateWithData(data, options) ?? CGImageSourceCreateIncremental(options)
|
||||||
self.size = size
|
self.size = size
|
||||||
self.contentMode = contentMode
|
self.contentMode = contentMode
|
||||||
maxNumberOfFrames = framePreloadCount
|
self.maxFrameCount = framePreloadCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Frames
|
// MARK: - Frames
|
||||||
/// Loads the frames from an image source, resizes them, then caches them in `animatedFrames`.
|
/// Loads the frames from an image source, resizes them, then caches them in `animatedFrames`.
|
||||||
func prepareFrames() {
|
func prepareFrames() {
|
||||||
numberOfFrames = Int(CGImageSourceGetCount(imageSource))
|
frameCount = Int(CGImageSourceGetCount(imageSource))
|
||||||
let framesToProcess = min(numberOfFrames, maxNumberOfFrames)
|
let framesToProcess = min(frameCount, maxFrameCount)
|
||||||
animatedFrames.reserveCapacity(framesToProcess)
|
animatedFrames.reserveCapacity(framesToProcess)
|
||||||
animatedFrames = reduce(0..<framesToProcess, []) { $0 + pure(prepareFrame($1)) }
|
animatedFrames = (0..<framesToProcess).reduce([]) { $0 + pure(prepareFrame($1)) }
|
||||||
currentPreloadIndex = framesToProcess
|
currentPreloadIndex = framesToProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a single frame from an image source, resizes it, then returns an `AnimatedFrame`.
|
/// Loads a single frame from an image source, resizes it, then returns an `AnimatedFrame`.
|
||||||
///
|
///
|
||||||
/// :param: index The index of the GIF image source to prepare
|
/// - parameter index: The index of the GIF image source to prepare
|
||||||
/// :returns: An AnimatedFrame object
|
/// - returns: An AnimatedFrame object
|
||||||
private func prepareFrame(index: Int) -> AnimatedFrame {
|
func prepareFrame(index: Int) -> AnimatedFrame {
|
||||||
let frameDuration = CGImageSourceGIFFrameDuration(imageSource, index)
|
guard let frameImageRef = CGImageSourceCreateImageAtIndex(imageSource, index, nil) else {
|
||||||
let frameImageRef = CGImageSourceCreateImageAtIndex(imageSource, index, nil)
|
return AnimatedFrame.null()
|
||||||
|
}
|
||||||
|
|
||||||
|
let frameDuration = CGImageSourceGIFFrameDuration(imageSource, index: index)
|
||||||
let image = UIImage(CGImage: frameImageRef)
|
let image = UIImage(CGImage: frameImageRef)
|
||||||
let scaledImage: UIImage?
|
let scaledImage: UIImage?
|
||||||
|
|
||||||
switch contentMode {
|
switch contentMode {
|
||||||
case .ScaleAspectFit: scaledImage = image?.resizeAspectFit(size)
|
case .ScaleAspectFit: scaledImage = image.resizeAspectFit(size)
|
||||||
case .ScaleAspectFill: scaledImage = image?.resizeAspectFill(size)
|
case .ScaleAspectFill: scaledImage = image.resizeAspectFill(size)
|
||||||
default: scaledImage = image?.resize(size)
|
default: scaledImage = image.resize(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
return AnimatedFrame(image: scaledImage, duration: frameDuration)
|
return AnimatedFrame(image: scaledImage, duration: frameDuration)
|
||||||
|
@ -79,18 +80,18 @@ class Animator {
|
||||||
|
|
||||||
/// Returns the frame at a particular index.
|
/// Returns the frame at a particular index.
|
||||||
///
|
///
|
||||||
/// :param: index The index of the frame.
|
/// - parameter index: The index of the frame.
|
||||||
/// :returns: An optional image at a given frame.
|
/// - returns: An optional image at a given frame.
|
||||||
private func frameAtIndex(index: Int) -> UIImage? {
|
func frameAtIndex(index: Int) -> UIImage? {
|
||||||
return animatedFrames[index].image
|
return animatedFrames[index].image
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the current frame if necessary using the frame timer and the duration of each frame in `animatedFrames`.
|
/// Updates the current frame if necessary using the frame timer and the duration of each frame in `animatedFrames`.
|
||||||
///
|
///
|
||||||
/// :returns: An optional image at a given frame.
|
/// - returns: An optional image at a given frame.
|
||||||
func updateCurrentFrame(duration: CFTimeInterval) -> Bool {
|
func updateCurrentFrame(duration: CFTimeInterval) -> Bool {
|
||||||
timeSinceLastFrameChange += min(maxTimeStep, duration)
|
timeSinceLastFrameChange += min(maxTimeStep, duration)
|
||||||
var frameDuration = animatedFrames[currentFrameIndex].duration
|
let frameDuration = animatedFrames[currentFrameIndex].duration
|
||||||
|
|
||||||
if timeSinceLastFrameChange >= frameDuration {
|
if timeSinceLastFrameChange >= frameDuration {
|
||||||
timeSinceLastFrameChange -= frameDuration
|
timeSinceLastFrameChange -= frameDuration
|
||||||
|
@ -98,9 +99,9 @@ class Animator {
|
||||||
currentFrameIndex = ++currentFrameIndex % animatedFrames.count
|
currentFrameIndex = ++currentFrameIndex % animatedFrames.count
|
||||||
|
|
||||||
// Loads the next needed frame for progressive loading
|
// Loads the next needed frame for progressive loading
|
||||||
if animatedFrames.count < numberOfFrames {
|
if animatedFrames.count < frameCount {
|
||||||
animatedFrames[lastFrameIndex] = prepareFrame(currentPreloadIndex)
|
animatedFrames[lastFrameIndex] = prepareFrame(currentPreloadIndex)
|
||||||
currentPreloadIndex = ++currentPreloadIndex % numberOfFrames
|
currentPreloadIndex = ++currentPreloadIndex % frameCount
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
extension CGSize {
|
||||||
|
/// Calculates the aspect ratio of the size.
|
||||||
|
///
|
||||||
|
/// - returns: aspectRatio The aspect ratio of the size.
|
||||||
|
var aspectRatio: CGFloat {
|
||||||
|
if height == 0 { return 1 }
|
||||||
|
return width / height
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds a new size constrained by a size keeping the aspect ratio.
|
||||||
|
///
|
||||||
|
/// - parameter size: The contraining size.
|
||||||
|
/// - returns: size A new size that fits inside the contraining size with the same aspect ratio.
|
||||||
|
func sizeConstrainedBySize(size: CGSize) -> CGSize {
|
||||||
|
let aspectWidth = round(aspectRatio * size.height)
|
||||||
|
let aspectHeight = round(size.width / aspectRatio)
|
||||||
|
|
||||||
|
if aspectWidth > size.width {
|
||||||
|
return CGSize(width: size.width, height: aspectHeight)
|
||||||
|
} else {
|
||||||
|
return CGSize(width: aspectWidth, height: size.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds a new size filling the given size while keeping the aspect ratio.
|
||||||
|
///
|
||||||
|
/// - parameter size: The contraining size.
|
||||||
|
/// - returns: size A new size that fills the contraining size keeping the same aspect ratio.
|
||||||
|
func sizeFillingSize(size: CGSize) -> CGSize {
|
||||||
|
let aspectWidth = round(aspectRatio * size.height)
|
||||||
|
let aspectHeight = round(size.width / aspectRatio)
|
||||||
|
|
||||||
|
if aspectWidth > size.width {
|
||||||
|
return CGSize(width: aspectWidth, height: size.height)
|
||||||
|
} else {
|
||||||
|
return CGSize(width: size.width, height: aspectHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
/// One of my favorite indian spices.
|
|
||||||
func curry<A, B, C>(f: (A, B) -> C) -> A -> B -> C {
|
|
||||||
return { a in { b in f(a, b) } }
|
|
||||||
}
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/// One of my favorite indian spices.
|
||||||
|
func curry<A, B, C>(f: (A, B) -> C) -> A -> B -> C {
|
||||||
|
return { a in { b in f(a, b) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Optional
|
||||||
|
func <^> <T, U>(@noescape f: T -> U, a: T?) -> U? {
|
||||||
|
return a.map(f)
|
||||||
|
}
|
||||||
|
func <*> <T, U>(f: (T -> U)?, a: T?) -> U? {
|
||||||
|
return a.apply(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func >>- <T, U>(a: T?, @noescape f: T -> U?) -> U? {
|
||||||
|
return a.flatMap(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pure<T>(a: T) -> T? {
|
||||||
|
return .Some(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Optional {
|
||||||
|
func apply<U>(f: (Wrapped -> U)?) -> U? {
|
||||||
|
return f.flatMap { self.map($0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Array
|
||||||
|
public func <^> <T, U>(f: T -> U, a: [T]) -> [U] {
|
||||||
|
return a.map(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func <*> <T, U>(fs: [T -> U], a: [T]) -> [U] {
|
||||||
|
return a.apply(fs)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func >>- <T, U>(a: [T], f: T -> [U]) -> [U] {
|
||||||
|
return a.flatMap(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func -<< <T, U>(f: T -> [U], a: [T]) -> [U] {
|
||||||
|
return a.flatMap(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func pure<T>(a: T) -> [T] {
|
||||||
|
return [a]
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension Array {
|
||||||
|
func apply<U>(fs: [Element -> U]) -> [U] {
|
||||||
|
return fs.flatMap { self.map($0) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,13 @@
|
||||||
import ImageIO
|
import ImageIO
|
||||||
import MobileCoreServices
|
import MobileCoreServices
|
||||||
import Runes
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
typealias GIFProperties = [String : Double]
|
typealias GIFProperties = [String : Double]
|
||||||
private let defaultDuration: Double = 0
|
let defaultDuration: Double = 0
|
||||||
|
|
||||||
/// Retruns the duration of a frame at a specific index using an image source (an `CGImageSource` instance).
|
/// Retruns the duration of a frame at a specific index using an image source (an `CGImageSource` instance).
|
||||||
///
|
///
|
||||||
/// :returns: A frame duration.
|
/// - returns: A frame duration.
|
||||||
func CGImageSourceGIFFrameDuration(imageSource: CGImageSource, index: Int) -> NSTimeInterval {
|
func CGImageSourceGIFFrameDuration(imageSource: CGImageSource, index: Int) -> NSTimeInterval {
|
||||||
if !imageSource.isAnimatedGIF { return 0.0 }
|
if !imageSource.isAnimatedGIF { return 0.0 }
|
||||||
|
|
||||||
|
@ -21,8 +20,8 @@ func CGImageSourceGIFFrameDuration(imageSource: CGImageSource, index: Int) -> NS
|
||||||
|
|
||||||
/// Ensures that a duration is never smaller than a threshold value.
|
/// Ensures that a duration is never smaller than a threshold value.
|
||||||
///
|
///
|
||||||
/// :returns: A capped frame duration.
|
/// - returns: A capped frame duration.
|
||||||
private func capDuration(duration: Double) -> Double? {
|
func capDuration(duration: Double) -> Double? {
|
||||||
if duration < 0 { return .None }
|
if duration < 0 { return .None }
|
||||||
let threshold = 0.02 - Double(FLT_EPSILON)
|
let threshold = 0.02 - Double(FLT_EPSILON)
|
||||||
let cappedDuration = duration < threshold ? 0.1 : duration
|
let cappedDuration = duration < threshold ? 0.1 : duration
|
||||||
|
@ -31,8 +30,8 @@ private func capDuration(duration: Double) -> Double? {
|
||||||
|
|
||||||
/// Returns a frame duration from a `GIFProperties` dictionary.
|
/// Returns a frame duration from a `GIFProperties` dictionary.
|
||||||
///
|
///
|
||||||
/// :returns: A frame duration.
|
/// - returns: A frame duration.
|
||||||
private func durationFromGIFProperties(properties: GIFProperties) -> Double? {
|
func durationFromGIFProperties(properties: GIFProperties) -> Double? {
|
||||||
let unclampedDelayTime = properties[String(kCGImagePropertyGIFUnclampedDelayTime)]
|
let unclampedDelayTime = properties[String(kCGImagePropertyGIFUnclampedDelayTime)]
|
||||||
let delayTime = properties[String(kCGImagePropertyGIFDelayTime)]
|
let delayTime = properties[String(kCGImagePropertyGIFDelayTime)]
|
||||||
|
|
||||||
|
@ -41,16 +40,16 @@ private func durationFromGIFProperties(properties: GIFProperties) -> Double? {
|
||||||
|
|
||||||
/// Calculates frame duration based on both clamped and unclamped times.
|
/// Calculates frame duration based on both clamped and unclamped times.
|
||||||
///
|
///
|
||||||
/// :returns: A frame duration.
|
/// - returns: A frame duration.
|
||||||
private func duration(unclampedDelayTime: Double)(delayTime: Double) -> Double {
|
func duration(unclampedDelayTime: Double)(delayTime: Double) -> Double {
|
||||||
let delayArray = [unclampedDelayTime, delayTime]
|
let delayArray = [unclampedDelayTime, delayTime]
|
||||||
return delayArray.filter(isPositive).first ?? defaultDuration
|
return delayArray.filter(isPositive).first ?? defaultDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a `Double` value is positive.
|
/// Checks if a `Double` value is positive.
|
||||||
///
|
///
|
||||||
/// :returns: A boolean value that is `true` if the tested value is positive.
|
/// - returns: A boolean value that is `true` if the tested value is positive.
|
||||||
private func isPositive(value: Double) -> Bool {
|
func isPositive(value: Double) -> Bool {
|
||||||
return value >= 0
|
return value >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,21 +57,19 @@ private func isPositive(value: Double) -> Bool {
|
||||||
extension CGImageSourceRef {
|
extension CGImageSourceRef {
|
||||||
/// Returns whether the image source contains an animated GIF.
|
/// Returns whether the image source contains an animated GIF.
|
||||||
///
|
///
|
||||||
/// :returns: A boolean value that is `true` if the image source contains animated GIF data.
|
/// - returns: A boolean value that is `true` if the image source contains animated GIF data.
|
||||||
var isAnimatedGIF: Bool {
|
var isAnimatedGIF: Bool {
|
||||||
let isTypeGIF = UTTypeConformsTo(CGImageSourceGetType(self), kUTTypeGIF)
|
let isTypeGIF = UTTypeConformsTo(CGImageSourceGetType(self) ?? "", kUTTypeGIF)
|
||||||
let imageCount = CGImageSourceGetCount(self)
|
let imageCount = CGImageSourceGetCount(self)
|
||||||
return isTypeGIF != 0 && imageCount > 1
|
return isTypeGIF != false && imageCount > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the GIF properties at a specific index.
|
/// Returns the GIF properties at a specific index.
|
||||||
///
|
///
|
||||||
/// :param: index The index of the GIF properties to retrieve.
|
/// - parameter index: The index of the GIF properties to retrieve.
|
||||||
/// :returns: A dictionary containing the GIF properties at the passed in index.
|
/// - returns: A dictionary containing the GIF properties at the passed in index.
|
||||||
func GIFPropertiesAtIndex(index: Int) -> GIFProperties? {
|
func GIFPropertiesAtIndex(index: Int) -> GIFProperties? {
|
||||||
if !isAnimatedGIF { return .None }
|
let imageProperties = CGImageSourceCopyPropertiesAtIndex(self, index, nil) as Dictionary?
|
||||||
|
return imageProperties?[String(kCGImagePropertyGIFDictionary)] as? GIFProperties
|
||||||
let imageProperties = CGImageSourceCopyPropertiesAtIndex(self, index, nil) as Dictionary
|
|
||||||
return imageProperties[String(kCGImagePropertyGIFDictionary)] as? GIFProperties
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>co.kaishin.$(PRODUCT_NAME:rfc1034identifier)</string>
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
|
|
@ -3,20 +3,20 @@
|
||||||
extension UIImage {
|
extension UIImage {
|
||||||
/// Resizes an image instance.
|
/// Resizes an image instance.
|
||||||
///
|
///
|
||||||
/// :param: size The new size of the image.
|
/// - parameter size: The new size of the image.
|
||||||
/// :returns: A new resized image instance.
|
/// - returns: A new resized image instance.
|
||||||
func resize(size: CGSize) -> UIImage {
|
func resize(size: CGSize) -> UIImage {
|
||||||
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
|
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
|
||||||
self.drawInRect(CGRect(origin: CGPointZero, size: size))
|
self.drawInRect(CGRect(origin: CGPointZero, size: size))
|
||||||
let newImage = UIGraphicsGetImageFromCurrentImageContext()
|
let newImage = UIGraphicsGetImageFromCurrentImageContext()
|
||||||
UIGraphicsEndImageContext()
|
UIGraphicsEndImageContext()
|
||||||
return newImage
|
return newImage ?? self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resizes an image instance to fit inside a constraining size while keeping the aspect ratio.
|
/// Resizes an image instance to fit inside a constraining size while keeping the aspect ratio.
|
||||||
///
|
///
|
||||||
/// :param: size The constraining size of the image.
|
/// - parameter size: The constraining size of the image.
|
||||||
/// :returns: A new resized image instance.
|
/// - returns: A new resized image instance.
|
||||||
func resizeAspectFit(size: CGSize) -> UIImage {
|
func resizeAspectFit(size: CGSize) -> UIImage {
|
||||||
let newSize = self.size.sizeConstrainedBySize(size)
|
let newSize = self.size.sizeConstrainedBySize(size)
|
||||||
return resize(newSize)
|
return resize(newSize)
|
||||||
|
@ -24,8 +24,8 @@ extension UIImage {
|
||||||
|
|
||||||
/// Resizes an image instance to fill a constraining size while keeping the aspect ratio.
|
/// Resizes an image instance to fill a constraining size while keeping the aspect ratio.
|
||||||
///
|
///
|
||||||
/// :param: size The constraining size of the image.
|
/// - parameter size: The constraining size of the image.
|
||||||
/// :returns: A new resized image instance.
|
/// - returns: A new resized image instance.
|
||||||
func resizeAspectFill(size: CGSize) -> UIImage {
|
func resizeAspectFill(size: CGSize) -> UIImage {
|
||||||
let newSize = self.size.sizeFillingSize(size)
|
let newSize = self.size.sizeFillingSize(size)
|
||||||
return resize(newSize)
|
return resize(newSize)
|
||||||
|
@ -33,58 +33,18 @@ extension UIImage {
|
||||||
|
|
||||||
/// Returns a new `UIImage` instance using raw image data and a size.
|
/// Returns a new `UIImage` instance using raw image data and a size.
|
||||||
///
|
///
|
||||||
/// :param: data Raw image data.
|
/// - parameter data: Raw image data.
|
||||||
/// :param: size The size to be used to resize the new image instance.
|
/// - parameter size: The size to be used to resize the new image instance.
|
||||||
/// :returns: A new image instance from the passed in data.
|
/// - returns: A new image instance from the passed in data.
|
||||||
class func imageWithData(data: NSData, size: CGSize) -> UIImage? {
|
class func imageWithData(data: NSData, size: CGSize) -> UIImage? {
|
||||||
return UIImage(data: data)?.resize(size)
|
return UIImage(data: data)?.resize(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an image size from raw image data.
|
/// Returns an image size from raw image data.
|
||||||
///
|
///
|
||||||
/// :param: data Raw image data.
|
/// - parameter data: Raw image data.
|
||||||
/// :returns: The size of the image contained in the data.
|
/// - returns: The size of the image contained in the data.
|
||||||
class func sizeForImageData(data: NSData) -> CGSize? {
|
class func sizeForImageData(data: NSData) -> CGSize? {
|
||||||
return UIImage(data: data)?.size
|
return UIImage(data: data)?.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension CGSize {
|
|
||||||
/// Calculates the aspect ratio of the size.
|
|
||||||
///
|
|
||||||
/// :returns: aspectRatio The aspect ratio of the size.
|
|
||||||
var aspectRatio: CGFloat {
|
|
||||||
if height == 0 { return 1 }
|
|
||||||
return width / height
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds a new size constrained by a size keeping the aspect ratio.
|
|
||||||
///
|
|
||||||
/// :param: size The contraining size.
|
|
||||||
/// :returns: size A new size that fits inside the contraining size with the same aspect ratio.
|
|
||||||
func sizeConstrainedBySize(size: CGSize) -> CGSize {
|
|
||||||
let aspectWidth = round(aspectRatio * size.height)
|
|
||||||
let aspectHeight = round(size.width / aspectRatio)
|
|
||||||
|
|
||||||
if aspectWidth > size.width {
|
|
||||||
return CGSize(width: size.width, height: aspectHeight)
|
|
||||||
} else {
|
|
||||||
return CGSize(width: aspectWidth, height: size.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds a new size filling the given size while keeping the aspect ratio.
|
|
||||||
///
|
|
||||||
/// :param: size The contraining size.
|
|
||||||
/// :returns: size A new size that fills the contraining size keeping the same aspect ratio.
|
|
||||||
func sizeFillingSize(size: CGSize) -> CGSize {
|
|
||||||
let aspectWidth = round(aspectRatio * size.height)
|
|
||||||
let aspectHeight = round(size.width / aspectRatio)
|
|
||||||
|
|
||||||
if aspectWidth > size.width {
|
|
||||||
return CGSize(width: aspectWidth, height: size.height)
|
|
||||||
} else {
|
|
||||||
return CGSize(width: size.width, height: aspectHeight)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue