├── .gitignore
├── .swiftlint.yml
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── ImageTransition.podspec
├── ImageTransition.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ ├── ImageTransition.xcscheme
│ └── Sample.xcscheme
├── ImageTransition
├── ImageTransition.h
├── ImageTransitionDelegate.swift
├── ImageTransitionable.swift
├── ImageTransitioning.swift
├── Info.plist
├── UIImage+.swift
├── UIImageView+.swift
└── UIView+.swift
├── ImageTransitionTests
├── ImageTransitionAnimatorTests.swift
├── ImageTransitionDelegateTests.swift
├── Info.plist
├── UIImage+Tests.swift
├── UIImageView+Tests.swift
└── UIView+Tests.swift
├── LICENSE
├── Mintfile
├── Package.swift
├── README.md
├── Sample
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── apple.imageset
│ │ ├── Contents.json
│ │ └── apple-food-fruit-39803.jpg
│ ├── kiwi.imageset
│ │ ├── Contents.json
│ │ └── food-fresh-fruit-51312.jpg
│ ├── lemon.imageset
│ │ ├── Contents.json
│ │ └── acid-bright-citrus-1414110.jpg
│ ├── orange.imageset
│ │ ├── Contents.json
│ │ └── citrus-food-fresh-42059.jpg
│ ├── strawberry.imageset
│ │ ├── Contents.json
│ │ └── close-up-food-fruit-59945.jpg
│ └── tomato.imageset
│ │ ├── Contents.json
│ │ └── cherry-tomatoes-food-freshness-48802.jpg
├── Base.lproj
│ └── LaunchScreen.storyboard
├── Info.plist
├── ItemCell.swift
├── ItemCell.xib
├── ItemDetailViewController.swift
├── ItemDetailViewController.xib
├── ItemListViewController.swift
└── ItemListViewController.xib
└── docs
└── assets
├── sample_01.gif
├── sample_01.mov
├── sample_02.gif
└── sample_02.mov
/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/90cb995068518f26e3c1305401ffa9e4ae8b110b/Swift.gitignore
2 |
3 | # Xcode
4 | #
5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
6 |
7 | ## Build generated
8 | build/
9 | DerivedData/
10 |
11 | ## Various settings
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | xcuserdata/
21 |
22 | ## Other
23 | *.moved-aside
24 | *.xccheckout
25 | *.xcscmblueprint
26 |
27 | ## Obj-C/Swift specific
28 | *.hmap
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | .build/
44 |
45 | # CocoaPods
46 | #
47 | # We recommend against adding the Pods directory to your .gitignore. However
48 | # you should judge for yourself, the pros and cons are mentioned at:
49 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
50 | #
51 | # Pods/
52 | #
53 | # Add this line if you want to avoid checking in source code from the Xcode workspace
54 | # *.xcworkspace
55 |
56 | # Carthage
57 | #
58 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
59 | Carthage/Checkouts
60 | Carthage/Build
61 |
62 | # fastlane
63 | #
64 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
65 | # screenshots whenever they are needed.
66 | # For more information about the recommended setup visit:
67 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
68 |
69 | fastlane/report.xml
70 | # fastlane/Preview.html
71 | # fastlane/screenshots/**/*.png
72 | fastlane/test_output
73 |
74 | # Code Injection
75 | #
76 | # After new code Injection tools there's a generated folder /iOSInjectionProject
77 | # https://github.com/johnno1962/injectionforxcode
78 |
79 | iOSInjectionProject/
80 |
81 |
82 | ### https://raw.github.com/github/gitignore/90cb995068518f26e3c1305401ffa9e4ae8b110b/Global/Xcode.gitignore
83 |
84 | # Xcode
85 | #
86 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
87 |
88 | ## User settings
89 | xcuserdata/
90 |
91 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
92 | *.xcscmblueprint
93 | *.xccheckout
94 |
95 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
96 | build/
97 | DerivedData/
98 | *.moved-aside
99 | *.pbxuser
100 | !default.pbxuser
101 | *.mode1v3
102 | !default.mode1v3
103 | *.mode2v3
104 | !default.mode2v3
105 | *.perspectivev3
106 | !default.perspectivev3
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - attributes
3 | - array_init
4 | - closure_body_length
5 | - conditional_returns_on_newline
6 | - cyclomatic_complexity
7 | - discouraged_optional_boolean
8 | - discouraged_optional_collection
9 | - explicit_acl
10 | - explicit_enum_raw_value
11 | - explicit_top_level_acl
12 | - explicit_type_interface
13 | - extension_access_modifier
14 | - fatal_error_message
15 | - file_header
16 | - file_types_order
17 | - file_length
18 | - function_body_length
19 | - function_default_parameter_at_end
20 | - function_parameter_count
21 | - indentation_width
22 | - implicit_return
23 | - lower_acl_than_parent
24 | - no_extension_access_modifier
25 | - no_grouping_extension
26 | - number_separator
27 | - missing_docs
28 | - modifier_order
29 | - multiline_arguments
30 | - multiple_closures_with_trailing_closure
31 | - multiline_arguments_brackets
32 | - multiline_parameters_brackets
33 | - object_literal
34 | - operator_usage_whitespace
35 | - pattern_matching_keywords
36 | - private_action
37 | - private_outlet
38 | - prefixed_toplevel_constant
39 | - prohibited_interface_builder
40 | - raw_value_for_camel_cased_codable_enum
41 | - required_deinit
42 | - sorted_imports
43 | - strict_fileprivate
44 | - strong_iboutlet
45 | - switch_case_on_newline
46 | - trailing_whitespace
47 | - trailing_closure
48 | - type_contents_order
49 | - todo
50 | - unavailable_function
51 | - unneeded_parentheses_in_closure_argument
52 | - unused_setter_value
53 | - xctfail_message
54 | - xct_specific_matcher
55 | - line_length
56 | - force_unwrapping
57 | - let_var_whitespace
58 | - file_name
59 |
60 | opt_in_rules:
61 | - anyobject_protocol
62 | - array_init
63 | - attributes
64 | - closure_body_length
65 | - closure_end_indentation
66 | - closure_spacing
67 | - collection_alignment
68 | - conditional_returns_on_newline
69 | - contains_over_filter_count
70 | - contains_over_filter_is_empty
71 | - contains_over_first_not_nil
72 | - contains_over_range_nil_comparison
73 | - convenience_type
74 | - discouraged_object_literal
75 | - discouraged_optional_boolean
76 | - discouraged_optional_collection
77 | - empty_collection_literal
78 | - empty_count
79 | - empty_string
80 | - empty_xctest_method
81 | - enum_case_associated_values_count
82 | - expiring_todo
83 | - explicit_acl
84 | - explicit_enum_raw_value
85 | - explicit_init
86 | - explicit_self
87 | - explicit_top_level_acl
88 | - explicit_type_interface
89 | - extension_access_modifier
90 | - fallthrough
91 | - fatal_error_message
92 | - file_header
93 | - file_name
94 | - file_name_no_space
95 | - file_types_order
96 | - first_where
97 | - flatmap_over_map_reduce
98 | - force_unwrapping
99 | - function_default_parameter_at_end
100 | - identical_operands
101 | - implicit_return
102 | - implicitly_unwrapped_optional
103 | - indentation_width
104 | - joined_default_parameter
105 | - last_where
106 | - legacy_multiple
107 | - legacy_random
108 | - let_var_whitespace
109 | - literal_expression_end_indentation
110 | - lower_acl_than_parent
111 | - missing_docs
112 | - modifier_order
113 | - multiline_arguments
114 | - multiline_arguments_brackets
115 | - multiline_function_chains
116 | - multiline_literal_brackets
117 | - multiline_parameters
118 | - multiline_parameters_brackets
119 | - nimble_operator
120 | - no_extension_access_modifier
121 | - no_grouping_extension
122 | - nslocalizedstring_key
123 | - nslocalizedstring_require_bundle
124 | - number_separator
125 | - object_literal
126 | - operator_usage_whitespace
127 | - optional_enum_case_matching
128 | - overridden_super_call
129 | - override_in_extension
130 | - pattern_matching_keywords
131 | - prefer_self_type_over_type_of_self
132 | - prefixed_toplevel_constant
133 | - private_action
134 | - private_outlet
135 | - prohibited_interface_builder
136 | - prohibited_super_call
137 | - quick_discouraged_call
138 | - quick_discouraged_focused_test
139 | - quick_discouraged_pending_test
140 | - raw_value_for_camel_cased_codable_enum
141 | - reduce_into
142 | - redundant_nil_coalescing
143 | - redundant_type_annotation
144 | - required_deinit
145 | - required_enum_case
146 | - single_test_class
147 | - sorted_first_last
148 | - sorted_imports
149 | - static_operator
150 | - strict_fileprivate
151 | - strong_iboutlet
152 | - switch_case_on_newline
153 | - toggle_bool
154 | - trailing_closure
155 | - type_contents_order
156 | - unavailable_function
157 | - unneeded_parentheses_in_closure_argument
158 | - unowned_variable_capture
159 | - untyped_error_in_catch
160 | - unused_declaration
161 | - unused_import
162 | - vertical_parameter_alignment_on_call
163 | - vertical_whitespace_between_cases
164 | - vertical_whitespace_closing_braces
165 | - vertical_whitespace_opening_braces
166 | - xct_specific_matcher
167 | - yoda_condition
168 |
169 | included:
170 | - ImageTransition
171 | - Demo
172 |
173 | # Lint対象から除外するパス
174 | excluded:
175 |
176 | custom_rules:
177 | final_class:
178 | included: "./.*\\.swift"
179 | name: "Final Class"
180 | regex: "^(private |fileprivate |internal |public |open )class"
181 | message: "Final Class"
182 | severity: error
183 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ImageTransition.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = "ImageTransition"
3 | spec.version = "0.5.0"
4 | spec.summary = "ImageTransition is a library for smooth animation of images during transitions."
5 | spec.homepage = "https://github.com/shtnkgm/ImageTransition"
6 | spec.license = { :type => "MIT", :file => "LICENSE" }
7 | spec.author = "shtnkgm"
8 | spec.platform = :ios, "12.0"
9 | spec.swift_version = "5.5"
10 | spec.source = { :git => "https://github.com/shtnkgm/ImageTransition.git", :tag => "#{spec.version}" }
11 | spec.source_files = "ImageTransition/**/*.swift"
12 | end
13 |
--------------------------------------------------------------------------------
/ImageTransition.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 974D5004224683130015B768 /* ItemListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 974D5002224683130015B768 /* ItemListViewController.swift */; };
11 | 974D50072246849C0015B768 /* ItemListViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 974D50062246849C0015B768 /* ItemListViewController.xib */; };
12 | 974D500A2246853B0015B768 /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 974D50082246853B0015B768 /* ItemCell.swift */; };
13 | 974D500B2246853B0015B768 /* ItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 974D50092246853B0015B768 /* ItemCell.xib */; };
14 | 974D500D224694910015B768 /* ItemDetailViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 974D500C224694910015B768 /* ItemDetailViewController.xib */; };
15 | DA4B56BE216AA51D0046FC72 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = DA4B56BD216AA51D0046FC72 /* README.md */; };
16 | DA5486EF21525AEB00E0899D /* ImageTransition.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5486E521525AEB00E0899D /* ImageTransition.framework */; };
17 | DA5486F621525AEB00E0899D /* ImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5486E821525AEB00E0899D /* ImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
18 | DA548700215263A900E0899D /* ImageTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA5486FF215263A900E0899D /* ImageTransitioning.swift */; };
19 | DA548702215263B400E0899D /* ImageTransitionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA548701215263B400E0899D /* ImageTransitionDelegate.swift */; };
20 | DA548704215263BE00E0899D /* ImageTransitionable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA548703215263BE00E0899D /* ImageTransitionable.swift */; };
21 | DA548706215263C800E0899D /* UIImageView+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA548705215263C800E0899D /* UIImageView+.swift */; };
22 | DA548708215263DB00E0899D /* UIView+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA548707215263DB00E0899D /* UIView+.swift */; };
23 | DA54870A215263E500E0899D /* UIImage+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA548709215263E500E0899D /* UIImage+.swift */; };
24 | DA54870C2152644400E0899D /* UIImageView+Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA54870B2152644400E0899D /* UIImageView+Tests.swift */; };
25 | DA54870E2152644D00E0899D /* UIView+Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA54870D2152644D00E0899D /* UIView+Tests.swift */; };
26 | DA5487102152646000E0899D /* ImageTransitionDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA54870F2152646000E0899D /* ImageTransitionDelegateTests.swift */; };
27 | DA5487122152646A00E0899D /* ImageTransitionAnimatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA5487112152646A00E0899D /* ImageTransitionAnimatorTests.swift */; };
28 | DA548714215264A800E0899D /* UIImage+Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA548713215264A800E0899D /* UIImage+Tests.swift */; };
29 | DA54871C215266AB00E0899D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA54871B215266AB00E0899D /* AppDelegate.swift */; };
30 | DA548723215266AC00E0899D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA548722215266AC00E0899D /* Assets.xcassets */; };
31 | DA548726215266AC00E0899D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA548724215266AC00E0899D /* LaunchScreen.storyboard */; };
32 | DA8EAFC22152AECD00BC5968 /* ItemDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8EAFC02152AECD00BC5968 /* ItemDetailViewController.swift */; };
33 | DA8EAFC92152B0A700BC5968 /* ImageTransition.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5486E521525AEB00E0899D /* ImageTransition.framework */; };
34 | /* End PBXBuildFile section */
35 |
36 | /* Begin PBXContainerItemProxy section */
37 | DA5486F021525AEB00E0899D /* PBXContainerItemProxy */ = {
38 | isa = PBXContainerItemProxy;
39 | containerPortal = DA5486DC21525AEB00E0899D /* Project object */;
40 | proxyType = 1;
41 | remoteGlobalIDString = DA5486E421525AEB00E0899D;
42 | remoteInfo = ImageTransition;
43 | };
44 | DA8EAFCA2152B0CA00BC5968 /* PBXContainerItemProxy */ = {
45 | isa = PBXContainerItemProxy;
46 | containerPortal = DA5486DC21525AEB00E0899D /* Project object */;
47 | proxyType = 1;
48 | remoteGlobalIDString = DA5486E421525AEB00E0899D;
49 | remoteInfo = ImageTransition;
50 | };
51 | /* End PBXContainerItemProxy section */
52 |
53 | /* Begin PBXFileReference section */
54 | 974D5002224683130015B768 /* ItemListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListViewController.swift; sourceTree = ""; };
55 | 974D50062246849C0015B768 /* ItemListViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ItemListViewController.xib; sourceTree = ""; };
56 | 974D50082246853B0015B768 /* ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = ""; };
57 | 974D50092246853B0015B768 /* ItemCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ItemCell.xib; sourceTree = ""; };
58 | 974D500C224694910015B768 /* ItemDetailViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ItemDetailViewController.xib; sourceTree = ""; };
59 | DA4B56BD216AA51D0046FC72 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
60 | DA5486E521525AEB00E0899D /* ImageTransition.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ImageTransition.framework; sourceTree = BUILT_PRODUCTS_DIR; };
61 | DA5486E821525AEB00E0899D /* ImageTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageTransition.h; sourceTree = ""; };
62 | DA5486E921525AEB00E0899D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | DA5486EE21525AEB00E0899D /* ImageTransitionTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ImageTransitionTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
64 | DA5486F521525AEB00E0899D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
65 | DA5486FF215263A900E0899D /* ImageTransitioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTransitioning.swift; sourceTree = ""; };
66 | DA548701215263B400E0899D /* ImageTransitionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTransitionDelegate.swift; sourceTree = ""; };
67 | DA548703215263BE00E0899D /* ImageTransitionable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTransitionable.swift; sourceTree = ""; };
68 | DA548705215263C800E0899D /* UIImageView+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+.swift"; sourceTree = ""; };
69 | DA548707215263DB00E0899D /* UIView+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+.swift"; sourceTree = ""; };
70 | DA548709215263E500E0899D /* UIImage+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+.swift"; sourceTree = ""; };
71 | DA54870B2152644400E0899D /* UIImageView+Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+Tests.swift"; sourceTree = ""; };
72 | DA54870D2152644D00E0899D /* UIView+Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Tests.swift"; sourceTree = ""; };
73 | DA54870F2152646000E0899D /* ImageTransitionDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTransitionDelegateTests.swift; sourceTree = ""; };
74 | DA5487112152646A00E0899D /* ImageTransitionAnimatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTransitionAnimatorTests.swift; sourceTree = ""; };
75 | DA548713215264A800E0899D /* UIImage+Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Tests.swift"; sourceTree = ""; };
76 | DA548719215266AB00E0899D /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
77 | DA54871B215266AB00E0899D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
78 | DA548722215266AC00E0899D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
79 | DA548725215266AC00E0899D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
80 | DA548727215266AC00E0899D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
81 | DA8EAFC02152AECD00BC5968 /* ItemDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDetailViewController.swift; sourceTree = ""; };
82 | /* End PBXFileReference section */
83 |
84 | /* Begin PBXFrameworksBuildPhase section */
85 | DA5486E221525AEB00E0899D /* Frameworks */ = {
86 | isa = PBXFrameworksBuildPhase;
87 | buildActionMask = 2147483647;
88 | files = (
89 | );
90 | runOnlyForDeploymentPostprocessing = 0;
91 | };
92 | DA5486EB21525AEB00E0899D /* Frameworks */ = {
93 | isa = PBXFrameworksBuildPhase;
94 | buildActionMask = 2147483647;
95 | files = (
96 | DA5486EF21525AEB00E0899D /* ImageTransition.framework in Frameworks */,
97 | );
98 | runOnlyForDeploymentPostprocessing = 0;
99 | };
100 | DA548716215266AB00E0899D /* Frameworks */ = {
101 | isa = PBXFrameworksBuildPhase;
102 | buildActionMask = 2147483647;
103 | files = (
104 | DA8EAFC92152B0A700BC5968 /* ImageTransition.framework in Frameworks */,
105 | );
106 | runOnlyForDeploymentPostprocessing = 0;
107 | };
108 | /* End PBXFrameworksBuildPhase section */
109 |
110 | /* Begin PBXGroup section */
111 | DA5486DB21525AEB00E0899D = {
112 | isa = PBXGroup;
113 | children = (
114 | DA4B56BD216AA51D0046FC72 /* README.md */,
115 | DA5486E721525AEB00E0899D /* ImageTransition */,
116 | DA5486F221525AEB00E0899D /* ImageTransitionTests */,
117 | DA54871A215266AB00E0899D /* Sample */,
118 | DA5486E621525AEB00E0899D /* Products */,
119 | DA8EAFC82152B0A700BC5968 /* Frameworks */,
120 | );
121 | sourceTree = "";
122 | };
123 | DA5486E621525AEB00E0899D /* Products */ = {
124 | isa = PBXGroup;
125 | children = (
126 | DA5486E521525AEB00E0899D /* ImageTransition.framework */,
127 | DA5486EE21525AEB00E0899D /* ImageTransitionTests.xctest */,
128 | DA548719215266AB00E0899D /* Sample.app */,
129 | );
130 | name = Products;
131 | sourceTree = "";
132 | };
133 | DA5486E721525AEB00E0899D /* ImageTransition */ = {
134 | isa = PBXGroup;
135 | children = (
136 | DA5486E821525AEB00E0899D /* ImageTransition.h */,
137 | DA5486FF215263A900E0899D /* ImageTransitioning.swift */,
138 | DA548701215263B400E0899D /* ImageTransitionDelegate.swift */,
139 | DA548703215263BE00E0899D /* ImageTransitionable.swift */,
140 | DA548705215263C800E0899D /* UIImageView+.swift */,
141 | DA548707215263DB00E0899D /* UIView+.swift */,
142 | DA548709215263E500E0899D /* UIImage+.swift */,
143 | DA5486E921525AEB00E0899D /* Info.plist */,
144 | );
145 | path = ImageTransition;
146 | sourceTree = "";
147 | };
148 | DA5486F221525AEB00E0899D /* ImageTransitionTests */ = {
149 | isa = PBXGroup;
150 | children = (
151 | DA54870B2152644400E0899D /* UIImageView+Tests.swift */,
152 | DA54870D2152644D00E0899D /* UIView+Tests.swift */,
153 | DA548713215264A800E0899D /* UIImage+Tests.swift */,
154 | DA54870F2152646000E0899D /* ImageTransitionDelegateTests.swift */,
155 | DA5487112152646A00E0899D /* ImageTransitionAnimatorTests.swift */,
156 | DA5486F521525AEB00E0899D /* Info.plist */,
157 | );
158 | path = ImageTransitionTests;
159 | sourceTree = "";
160 | };
161 | DA54871A215266AB00E0899D /* Sample */ = {
162 | isa = PBXGroup;
163 | children = (
164 | DA54871B215266AB00E0899D /* AppDelegate.swift */,
165 | 974D5002224683130015B768 /* ItemListViewController.swift */,
166 | 974D50062246849C0015B768 /* ItemListViewController.xib */,
167 | 974D50082246853B0015B768 /* ItemCell.swift */,
168 | 974D50092246853B0015B768 /* ItemCell.xib */,
169 | DA8EAFC02152AECD00BC5968 /* ItemDetailViewController.swift */,
170 | 974D500C224694910015B768 /* ItemDetailViewController.xib */,
171 | DA548722215266AC00E0899D /* Assets.xcassets */,
172 | DA548724215266AC00E0899D /* LaunchScreen.storyboard */,
173 | DA548727215266AC00E0899D /* Info.plist */,
174 | );
175 | path = Sample;
176 | sourceTree = "";
177 | };
178 | DA8EAFC82152B0A700BC5968 /* Frameworks */ = {
179 | isa = PBXGroup;
180 | children = (
181 | );
182 | name = Frameworks;
183 | sourceTree = "";
184 | };
185 | /* End PBXGroup section */
186 |
187 | /* Begin PBXHeadersBuildPhase section */
188 | DA5486E021525AEB00E0899D /* Headers */ = {
189 | isa = PBXHeadersBuildPhase;
190 | buildActionMask = 2147483647;
191 | files = (
192 | DA5486F621525AEB00E0899D /* ImageTransition.h in Headers */,
193 | );
194 | runOnlyForDeploymentPostprocessing = 0;
195 | };
196 | /* End PBXHeadersBuildPhase section */
197 |
198 | /* Begin PBXNativeTarget section */
199 | DA5486E421525AEB00E0899D /* ImageTransition */ = {
200 | isa = PBXNativeTarget;
201 | buildConfigurationList = DA5486F921525AEB00E0899D /* Build configuration list for PBXNativeTarget "ImageTransition" */;
202 | buildPhases = (
203 | DA5486E021525AEB00E0899D /* Headers */,
204 | DA5486E121525AEB00E0899D /* Sources */,
205 | DA5486E221525AEB00E0899D /* Frameworks */,
206 | DA5486E321525AEB00E0899D /* Resources */,
207 | DA54872B215268DF00E0899D /* SwiftLint */,
208 | );
209 | buildRules = (
210 | );
211 | dependencies = (
212 | );
213 | name = ImageTransition;
214 | productName = ImageTransition;
215 | productReference = DA5486E521525AEB00E0899D /* ImageTransition.framework */;
216 | productType = "com.apple.product-type.framework";
217 | };
218 | DA5486ED21525AEB00E0899D /* ImageTransitionTests */ = {
219 | isa = PBXNativeTarget;
220 | buildConfigurationList = DA5486FC21525AEB00E0899D /* Build configuration list for PBXNativeTarget "ImageTransitionTests" */;
221 | buildPhases = (
222 | DA5486EA21525AEB00E0899D /* Sources */,
223 | DA5486EB21525AEB00E0899D /* Frameworks */,
224 | DA5486EC21525AEB00E0899D /* Resources */,
225 | );
226 | buildRules = (
227 | );
228 | dependencies = (
229 | DA5486F121525AEB00E0899D /* PBXTargetDependency */,
230 | );
231 | name = ImageTransitionTests;
232 | productName = ImageTransitionTests;
233 | productReference = DA5486EE21525AEB00E0899D /* ImageTransitionTests.xctest */;
234 | productType = "com.apple.product-type.bundle.unit-test";
235 | };
236 | DA548718215266AB00E0899D /* Sample */ = {
237 | isa = PBXNativeTarget;
238 | buildConfigurationList = DA548728215266AC00E0899D /* Build configuration list for PBXNativeTarget "Sample" */;
239 | buildPhases = (
240 | DA548715215266AB00E0899D /* Sources */,
241 | DA548716215266AB00E0899D /* Frameworks */,
242 | DA548717215266AB00E0899D /* Resources */,
243 | );
244 | buildRules = (
245 | );
246 | dependencies = (
247 | DA8EAFCB2152B0CA00BC5968 /* PBXTargetDependency */,
248 | );
249 | name = Sample;
250 | productName = Sample;
251 | productReference = DA548719215266AB00E0899D /* Sample.app */;
252 | productType = "com.apple.product-type.application";
253 | };
254 | /* End PBXNativeTarget section */
255 |
256 | /* Begin PBXProject section */
257 | DA5486DC21525AEB00E0899D /* Project object */ = {
258 | isa = PBXProject;
259 | attributes = {
260 | LastSwiftUpdateCheck = 1000;
261 | LastUpgradeCheck = 1300;
262 | ORGANIZATIONNAME = "Shota Nakagami";
263 | TargetAttributes = {
264 | DA5486E421525AEB00E0899D = {
265 | CreatedOnToolsVersion = 10.0;
266 | LastSwiftMigration = 1000;
267 | };
268 | DA5486ED21525AEB00E0899D = {
269 | CreatedOnToolsVersion = 10.0;
270 | };
271 | DA548718215266AB00E0899D = {
272 | CreatedOnToolsVersion = 10.0;
273 | };
274 | };
275 | };
276 | buildConfigurationList = DA5486DF21525AEB00E0899D /* Build configuration list for PBXProject "ImageTransition" */;
277 | compatibilityVersion = "Xcode 9.3";
278 | developmentRegion = en;
279 | hasScannedForEncodings = 0;
280 | knownRegions = (
281 | en,
282 | Base,
283 | );
284 | mainGroup = DA5486DB21525AEB00E0899D;
285 | productRefGroup = DA5486E621525AEB00E0899D /* Products */;
286 | projectDirPath = "";
287 | projectRoot = "";
288 | targets = (
289 | DA5486E421525AEB00E0899D /* ImageTransition */,
290 | DA5486ED21525AEB00E0899D /* ImageTransitionTests */,
291 | DA548718215266AB00E0899D /* Sample */,
292 | );
293 | };
294 | /* End PBXProject section */
295 |
296 | /* Begin PBXResourcesBuildPhase section */
297 | DA5486E321525AEB00E0899D /* Resources */ = {
298 | isa = PBXResourcesBuildPhase;
299 | buildActionMask = 2147483647;
300 | files = (
301 | DA4B56BE216AA51D0046FC72 /* README.md in Resources */,
302 | );
303 | runOnlyForDeploymentPostprocessing = 0;
304 | };
305 | DA5486EC21525AEB00E0899D /* Resources */ = {
306 | isa = PBXResourcesBuildPhase;
307 | buildActionMask = 2147483647;
308 | files = (
309 | );
310 | runOnlyForDeploymentPostprocessing = 0;
311 | };
312 | DA548717215266AB00E0899D /* Resources */ = {
313 | isa = PBXResourcesBuildPhase;
314 | buildActionMask = 2147483647;
315 | files = (
316 | 974D50072246849C0015B768 /* ItemListViewController.xib in Resources */,
317 | 974D500D224694910015B768 /* ItemDetailViewController.xib in Resources */,
318 | 974D500B2246853B0015B768 /* ItemCell.xib in Resources */,
319 | DA548726215266AC00E0899D /* LaunchScreen.storyboard in Resources */,
320 | DA548723215266AC00E0899D /* Assets.xcassets in Resources */,
321 | );
322 | runOnlyForDeploymentPostprocessing = 0;
323 | };
324 | /* End PBXResourcesBuildPhase section */
325 |
326 | /* Begin PBXShellScriptBuildPhase section */
327 | DA54872B215268DF00E0899D /* SwiftLint */ = {
328 | isa = PBXShellScriptBuildPhase;
329 | buildActionMask = 2147483647;
330 | files = (
331 | );
332 | inputFileListPaths = (
333 | );
334 | inputPaths = (
335 | );
336 | name = SwiftLint;
337 | outputFileListPaths = (
338 | );
339 | outputPaths = (
340 | );
341 | runOnlyForDeploymentPostprocessing = 0;
342 | shellPath = /bin/sh;
343 | shellScript = "if [ \"${CONFIGURATION}\" = \"Debug\" ]; then\n xcrun --sdk macosx mint run swiftlint autocorrect --format\n xcrun --sdk macosx mint run swiftlint\nfi\n";
344 | };
345 | /* End PBXShellScriptBuildPhase section */
346 |
347 | /* Begin PBXSourcesBuildPhase section */
348 | DA5486E121525AEB00E0899D /* Sources */ = {
349 | isa = PBXSourcesBuildPhase;
350 | buildActionMask = 2147483647;
351 | files = (
352 | DA548706215263C800E0899D /* UIImageView+.swift in Sources */,
353 | DA548700215263A900E0899D /* ImageTransitioning.swift in Sources */,
354 | DA548704215263BE00E0899D /* ImageTransitionable.swift in Sources */,
355 | DA54870A215263E500E0899D /* UIImage+.swift in Sources */,
356 | DA548702215263B400E0899D /* ImageTransitionDelegate.swift in Sources */,
357 | DA548708215263DB00E0899D /* UIView+.swift in Sources */,
358 | );
359 | runOnlyForDeploymentPostprocessing = 0;
360 | };
361 | DA5486EA21525AEB00E0899D /* Sources */ = {
362 | isa = PBXSourcesBuildPhase;
363 | buildActionMask = 2147483647;
364 | files = (
365 | DA54870C2152644400E0899D /* UIImageView+Tests.swift in Sources */,
366 | DA5487122152646A00E0899D /* ImageTransitionAnimatorTests.swift in Sources */,
367 | DA54870E2152644D00E0899D /* UIView+Tests.swift in Sources */,
368 | DA5487102152646000E0899D /* ImageTransitionDelegateTests.swift in Sources */,
369 | DA548714215264A800E0899D /* UIImage+Tests.swift in Sources */,
370 | );
371 | runOnlyForDeploymentPostprocessing = 0;
372 | };
373 | DA548715215266AB00E0899D /* Sources */ = {
374 | isa = PBXSourcesBuildPhase;
375 | buildActionMask = 2147483647;
376 | files = (
377 | DA54871C215266AB00E0899D /* AppDelegate.swift in Sources */,
378 | 974D5004224683130015B768 /* ItemListViewController.swift in Sources */,
379 | DA8EAFC22152AECD00BC5968 /* ItemDetailViewController.swift in Sources */,
380 | 974D500A2246853B0015B768 /* ItemCell.swift in Sources */,
381 | );
382 | runOnlyForDeploymentPostprocessing = 0;
383 | };
384 | /* End PBXSourcesBuildPhase section */
385 |
386 | /* Begin PBXTargetDependency section */
387 | DA5486F121525AEB00E0899D /* PBXTargetDependency */ = {
388 | isa = PBXTargetDependency;
389 | target = DA5486E421525AEB00E0899D /* ImageTransition */;
390 | targetProxy = DA5486F021525AEB00E0899D /* PBXContainerItemProxy */;
391 | };
392 | DA8EAFCB2152B0CA00BC5968 /* PBXTargetDependency */ = {
393 | isa = PBXTargetDependency;
394 | target = DA5486E421525AEB00E0899D /* ImageTransition */;
395 | targetProxy = DA8EAFCA2152B0CA00BC5968 /* PBXContainerItemProxy */;
396 | };
397 | /* End PBXTargetDependency section */
398 |
399 | /* Begin PBXVariantGroup section */
400 | DA548724215266AC00E0899D /* LaunchScreen.storyboard */ = {
401 | isa = PBXVariantGroup;
402 | children = (
403 | DA548725215266AC00E0899D /* Base */,
404 | );
405 | name = LaunchScreen.storyboard;
406 | sourceTree = "";
407 | };
408 | /* End PBXVariantGroup section */
409 |
410 | /* Begin XCBuildConfiguration section */
411 | DA5486F721525AEB00E0899D /* Debug */ = {
412 | isa = XCBuildConfiguration;
413 | buildSettings = {
414 | ALWAYS_SEARCH_USER_PATHS = NO;
415 | CLANG_ANALYZER_NONNULL = YES;
416 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
417 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
418 | CLANG_CXX_LIBRARY = "libc++";
419 | CLANG_ENABLE_MODULES = YES;
420 | CLANG_ENABLE_OBJC_ARC = YES;
421 | CLANG_ENABLE_OBJC_WEAK = YES;
422 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
423 | CLANG_WARN_BOOL_CONVERSION = YES;
424 | CLANG_WARN_COMMA = YES;
425 | CLANG_WARN_CONSTANT_CONVERSION = YES;
426 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
427 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
428 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
429 | CLANG_WARN_EMPTY_BODY = YES;
430 | CLANG_WARN_ENUM_CONVERSION = YES;
431 | CLANG_WARN_INFINITE_RECURSION = YES;
432 | CLANG_WARN_INT_CONVERSION = YES;
433 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
434 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
435 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
436 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
437 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
438 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
439 | CLANG_WARN_STRICT_PROTOTYPES = YES;
440 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
441 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
442 | CLANG_WARN_UNREACHABLE_CODE = YES;
443 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
444 | CODE_SIGN_IDENTITY = "";
445 | COPY_PHASE_STRIP = NO;
446 | CURRENT_PROJECT_VERSION = 1;
447 | DEBUG_INFORMATION_FORMAT = dwarf;
448 | ENABLE_STRICT_OBJC_MSGSEND = YES;
449 | ENABLE_TESTABILITY = YES;
450 | GCC_C_LANGUAGE_STANDARD = gnu11;
451 | GCC_DYNAMIC_NO_PIC = NO;
452 | GCC_NO_COMMON_BLOCKS = YES;
453 | GCC_OPTIMIZATION_LEVEL = 0;
454 | GCC_PREPROCESSOR_DEFINITIONS = (
455 | "DEBUG=1",
456 | "$(inherited)",
457 | );
458 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
459 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
460 | GCC_WARN_UNDECLARED_SELECTOR = YES;
461 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
462 | GCC_WARN_UNUSED_FUNCTION = YES;
463 | GCC_WARN_UNUSED_VARIABLE = YES;
464 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
465 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
466 | MTL_FAST_MATH = YES;
467 | ONLY_ACTIVE_ARCH = YES;
468 | SDKROOT = iphoneos;
469 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
470 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
471 | SWIFT_VERSION = 5.0;
472 | VERSIONING_SYSTEM = "apple-generic";
473 | VERSION_INFO_PREFIX = "";
474 | };
475 | name = Debug;
476 | };
477 | DA5486F821525AEB00E0899D /* Release */ = {
478 | isa = XCBuildConfiguration;
479 | buildSettings = {
480 | ALWAYS_SEARCH_USER_PATHS = NO;
481 | CLANG_ANALYZER_NONNULL = YES;
482 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
483 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
484 | CLANG_CXX_LIBRARY = "libc++";
485 | CLANG_ENABLE_MODULES = YES;
486 | CLANG_ENABLE_OBJC_ARC = YES;
487 | CLANG_ENABLE_OBJC_WEAK = YES;
488 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
489 | CLANG_WARN_BOOL_CONVERSION = YES;
490 | CLANG_WARN_COMMA = YES;
491 | CLANG_WARN_CONSTANT_CONVERSION = YES;
492 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
493 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
494 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
495 | CLANG_WARN_EMPTY_BODY = YES;
496 | CLANG_WARN_ENUM_CONVERSION = YES;
497 | CLANG_WARN_INFINITE_RECURSION = YES;
498 | CLANG_WARN_INT_CONVERSION = YES;
499 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
500 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
501 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
502 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
503 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
504 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
505 | CLANG_WARN_STRICT_PROTOTYPES = YES;
506 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
507 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
508 | CLANG_WARN_UNREACHABLE_CODE = YES;
509 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
510 | CODE_SIGN_IDENTITY = "";
511 | COPY_PHASE_STRIP = NO;
512 | CURRENT_PROJECT_VERSION = 1;
513 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
514 | ENABLE_NS_ASSERTIONS = NO;
515 | ENABLE_STRICT_OBJC_MSGSEND = YES;
516 | GCC_C_LANGUAGE_STANDARD = gnu11;
517 | GCC_NO_COMMON_BLOCKS = YES;
518 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
519 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
520 | GCC_WARN_UNDECLARED_SELECTOR = YES;
521 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
522 | GCC_WARN_UNUSED_FUNCTION = YES;
523 | GCC_WARN_UNUSED_VARIABLE = YES;
524 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
525 | MTL_ENABLE_DEBUG_INFO = NO;
526 | MTL_FAST_MATH = YES;
527 | SDKROOT = iphoneos;
528 | SWIFT_COMPILATION_MODE = wholemodule;
529 | SWIFT_OPTIMIZATION_LEVEL = "-O";
530 | SWIFT_VERSION = 5.0;
531 | VALIDATE_PRODUCT = YES;
532 | VERSIONING_SYSTEM = "apple-generic";
533 | VERSION_INFO_PREFIX = "";
534 | };
535 | name = Release;
536 | };
537 | DA5486FA21525AEB00E0899D /* Debug */ = {
538 | isa = XCBuildConfiguration;
539 | buildSettings = {
540 | CLANG_ENABLE_MODULES = YES;
541 | CODE_SIGN_IDENTITY = "";
542 | CODE_SIGN_STYLE = Automatic;
543 | DEFINES_MODULE = YES;
544 | DEVELOPMENT_TEAM = "";
545 | DYLIB_COMPATIBILITY_VERSION = 1;
546 | DYLIB_CURRENT_VERSION = 1;
547 | DYLIB_INSTALL_NAME_BASE = "@rpath";
548 | INFOPLIST_FILE = ImageTransition/Info.plist;
549 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
550 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
551 | LD_RUNPATH_SEARCH_PATHS = (
552 | "$(inherited)",
553 | "@executable_path/Frameworks",
554 | "@loader_path/Frameworks",
555 | );
556 | PRODUCT_BUNDLE_IDENTIFIER = com.github.shtnkgm.ImageTransition;
557 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
558 | SKIP_INSTALL = YES;
559 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
560 | SWIFT_VERSION = 5.0;
561 | TARGETED_DEVICE_FAMILY = "1,2";
562 | };
563 | name = Debug;
564 | };
565 | DA5486FB21525AEB00E0899D /* Release */ = {
566 | isa = XCBuildConfiguration;
567 | buildSettings = {
568 | CLANG_ENABLE_MODULES = YES;
569 | CODE_SIGN_IDENTITY = "";
570 | CODE_SIGN_STYLE = Automatic;
571 | DEFINES_MODULE = YES;
572 | DEVELOPMENT_TEAM = "";
573 | DYLIB_COMPATIBILITY_VERSION = 1;
574 | DYLIB_CURRENT_VERSION = 1;
575 | DYLIB_INSTALL_NAME_BASE = "@rpath";
576 | INFOPLIST_FILE = ImageTransition/Info.plist;
577 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
578 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
579 | LD_RUNPATH_SEARCH_PATHS = (
580 | "$(inherited)",
581 | "@executable_path/Frameworks",
582 | "@loader_path/Frameworks",
583 | );
584 | PRODUCT_BUNDLE_IDENTIFIER = com.github.shtnkgm.ImageTransition;
585 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
586 | SKIP_INSTALL = YES;
587 | SWIFT_VERSION = 5.0;
588 | TARGETED_DEVICE_FAMILY = "1,2";
589 | };
590 | name = Release;
591 | };
592 | DA5486FD21525AEB00E0899D /* Debug */ = {
593 | isa = XCBuildConfiguration;
594 | buildSettings = {
595 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
596 | CODE_SIGN_IDENTITY = "";
597 | CODE_SIGN_STYLE = Automatic;
598 | DEVELOPMENT_TEAM = "";
599 | INFOPLIST_FILE = ImageTransitionTests/Info.plist;
600 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
601 | LD_RUNPATH_SEARCH_PATHS = (
602 | "$(inherited)",
603 | "@executable_path/Frameworks",
604 | "@loader_path/Frameworks",
605 | );
606 | PRODUCT_BUNDLE_IDENTIFIER = com.shotanakagami.ImageTransitionTests;
607 | PRODUCT_NAME = "$(TARGET_NAME)";
608 | SWIFT_VERSION = 5.0;
609 | TARGETED_DEVICE_FAMILY = "1,2";
610 | };
611 | name = Debug;
612 | };
613 | DA5486FE21525AEB00E0899D /* Release */ = {
614 | isa = XCBuildConfiguration;
615 | buildSettings = {
616 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
617 | CODE_SIGN_IDENTITY = "";
618 | CODE_SIGN_STYLE = Automatic;
619 | DEVELOPMENT_TEAM = "";
620 | INFOPLIST_FILE = ImageTransitionTests/Info.plist;
621 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
622 | LD_RUNPATH_SEARCH_PATHS = (
623 | "$(inherited)",
624 | "@executable_path/Frameworks",
625 | "@loader_path/Frameworks",
626 | );
627 | PRODUCT_BUNDLE_IDENTIFIER = com.shotanakagami.ImageTransitionTests;
628 | PRODUCT_NAME = "$(TARGET_NAME)";
629 | SWIFT_VERSION = 5.0;
630 | TARGETED_DEVICE_FAMILY = "1,2";
631 | };
632 | name = Release;
633 | };
634 | DA548729215266AC00E0899D /* Debug */ = {
635 | isa = XCBuildConfiguration;
636 | buildSettings = {
637 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
638 | CODE_SIGN_IDENTITY = "";
639 | CODE_SIGN_STYLE = Automatic;
640 | DEVELOPMENT_TEAM = "";
641 | INFOPLIST_FILE = Sample/Info.plist;
642 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
643 | LD_RUNPATH_SEARCH_PATHS = (
644 | "$(inherited)",
645 | "@executable_path/Frameworks",
646 | );
647 | PRODUCT_BUNDLE_IDENTIFIER = com.github.shtnkgm.Sample;
648 | PRODUCT_NAME = "$(TARGET_NAME)";
649 | SWIFT_VERSION = 5.0;
650 | TARGETED_DEVICE_FAMILY = "1,2";
651 | };
652 | name = Debug;
653 | };
654 | DA54872A215266AC00E0899D /* Release */ = {
655 | isa = XCBuildConfiguration;
656 | buildSettings = {
657 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
658 | CODE_SIGN_IDENTITY = "";
659 | CODE_SIGN_STYLE = Automatic;
660 | DEVELOPMENT_TEAM = "";
661 | INFOPLIST_FILE = Sample/Info.plist;
662 | IPHONEOS_DEPLOYMENT_TARGET = 14.0;
663 | LD_RUNPATH_SEARCH_PATHS = (
664 | "$(inherited)",
665 | "@executable_path/Frameworks",
666 | );
667 | PRODUCT_BUNDLE_IDENTIFIER = com.github.shtnkgm.Sample;
668 | PRODUCT_NAME = "$(TARGET_NAME)";
669 | SWIFT_VERSION = 5.0;
670 | TARGETED_DEVICE_FAMILY = "1,2";
671 | };
672 | name = Release;
673 | };
674 | /* End XCBuildConfiguration section */
675 |
676 | /* Begin XCConfigurationList section */
677 | DA5486DF21525AEB00E0899D /* Build configuration list for PBXProject "ImageTransition" */ = {
678 | isa = XCConfigurationList;
679 | buildConfigurations = (
680 | DA5486F721525AEB00E0899D /* Debug */,
681 | DA5486F821525AEB00E0899D /* Release */,
682 | );
683 | defaultConfigurationIsVisible = 0;
684 | defaultConfigurationName = Release;
685 | };
686 | DA5486F921525AEB00E0899D /* Build configuration list for PBXNativeTarget "ImageTransition" */ = {
687 | isa = XCConfigurationList;
688 | buildConfigurations = (
689 | DA5486FA21525AEB00E0899D /* Debug */,
690 | DA5486FB21525AEB00E0899D /* Release */,
691 | );
692 | defaultConfigurationIsVisible = 0;
693 | defaultConfigurationName = Release;
694 | };
695 | DA5486FC21525AEB00E0899D /* Build configuration list for PBXNativeTarget "ImageTransitionTests" */ = {
696 | isa = XCConfigurationList;
697 | buildConfigurations = (
698 | DA5486FD21525AEB00E0899D /* Debug */,
699 | DA5486FE21525AEB00E0899D /* Release */,
700 | );
701 | defaultConfigurationIsVisible = 0;
702 | defaultConfigurationName = Release;
703 | };
704 | DA548728215266AC00E0899D /* Build configuration list for PBXNativeTarget "Sample" */ = {
705 | isa = XCConfigurationList;
706 | buildConfigurations = (
707 | DA548729215266AC00E0899D /* Debug */,
708 | DA54872A215266AC00E0899D /* Release */,
709 | );
710 | defaultConfigurationIsVisible = 0;
711 | defaultConfigurationName = Release;
712 | };
713 | /* End XCConfigurationList section */
714 | };
715 | rootObject = DA5486DC21525AEB00E0899D /* Project object */;
716 | }
717 |
--------------------------------------------------------------------------------
/ImageTransition.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ImageTransition.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ImageTransition.xcodeproj/xcshareddata/xcschemes/ImageTransition.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
42 |
48 |
49 |
50 |
51 |
52 |
62 |
63 |
69 |
70 |
71 |
72 |
78 |
79 |
85 |
86 |
87 |
88 |
90 |
91 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/ImageTransition.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
32 |
33 |
39 |
40 |
41 |
42 |
48 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/ImageTransition/ImageTransition.h:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransition.h
3 | // ImageTransition
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ImageTransition.
12 | FOUNDATION_EXPORT double ImageTransitionVersionNumber;
13 |
14 | //! Project version string for ImageTransition.
15 | FOUNDATION_EXPORT const unsigned char ImageTransitionVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ImageTransition/ImageTransitionDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransitionDelegate.swift
3 | // ImageTransition
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public final class ImageTransitionDelegate: NSObject {
12 | public static let shared = ImageTransitionDelegate()
13 |
14 | public var presentDuration: TimeInterval = 0.375
15 | public var dismissDuration: TimeInterval = 0.375
16 | public var pushDuration: TimeInterval = 0.375
17 | public var popDuration: TimeInterval = 0.375
18 | public var presentAnimationOptions: UIView.AnimationOptions = [.allowUserInteraction, .curveEaseInOut]
19 | public var dismissAnimationOptions: UIView.AnimationOptions = [.allowUserInteraction, .curveEaseInOut]
20 | public var pushAnimationOptions: UIView.AnimationOptions = [.allowUserInteraction, .curveEaseInOut]
21 | public var popAnimationOptions: UIView.AnimationOptions = [.allowUserInteraction, .curveEaseInOut]
22 |
23 | private override init() { }
24 | }
25 |
26 | extension ImageTransitionDelegate: UIViewControllerTransitioningDelegate {
27 | public func animationController(
28 | forPresented presented: UIViewController,
29 | presenting: UIViewController,
30 | source: UIViewController
31 | ) -> UIViewControllerAnimatedTransitioning? {
32 | ImageTransitioning(duration: presentDuration, animationOptions: presentAnimationOptions)
33 | }
34 |
35 | public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
36 | ImageTransitioning(duration: dismissDuration, animationOptions: dismissAnimationOptions)
37 | }
38 | }
39 |
40 | extension ImageTransitionDelegate: UINavigationControllerDelegate {
41 | public func navigationController(
42 | _ navigationController: UINavigationController,
43 | animationControllerFor operation: UINavigationController.Operation,
44 | from fromVC: UIViewController,
45 | to toVC: UIViewController
46 | ) -> UIViewControllerAnimatedTransitioning? {
47 | switch operation {
48 | case .none:
49 | return nil
50 |
51 | case .pop:
52 | return ImageTransitioning(duration: popDuration, animationOptions: popAnimationOptions)
53 |
54 | case .push:
55 | return ImageTransitioning(duration: pushDuration, animationOptions: pushAnimationOptions)
56 |
57 | @unknown default:
58 | fatalError()
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/ImageTransition/ImageTransitionable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransitionable.swift
3 | // ImageTransition
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol ImageTransitionable {
12 | var imageViewForTransition: UIImageView? { get }
13 | }
14 |
--------------------------------------------------------------------------------
/ImageTransition/ImageTransitioning.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransitioning.swift
3 | // ImageTransition
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | internal final class ImageTransitioning: NSObject, UIViewControllerAnimatedTransitioning {
12 | private let duration: TimeInterval
13 | private let animationOptions: UIView.AnimationOptions
14 |
15 | internal init(duration: TimeInterval, animationOptions: UIView.AnimationOptions) {
16 | self.duration = duration
17 | self.animationOptions = animationOptions
18 | }
19 |
20 | internal func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
21 | duration
22 | }
23 |
24 | internal func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
25 | guard let fromVC = transitionContext.viewController(forKey: .from) else {
26 | assertionFailure("fromVC is nil")
27 | return
28 | }
29 | guard let toVC = transitionContext.viewController(forKey: .to) else {
30 | assertionFailure("toVC is nil")
31 | return
32 | }
33 | guard let fromImageView = (fromVC as? ImageTransitionable)?.imageViewForTransition else {
34 | assertionFailure("fromImageView is nil")
35 | return
36 | }
37 | guard let toImageView = (toVC as? ImageTransitionable)?.imageViewForTransition else {
38 | assertionFailure("toImageView is nil")
39 | return
40 | }
41 | guard let fromImage = fromImageView.image else {
42 | assertionFailure("fromImage is nil")
43 | return
44 | }
45 | guard let toImage = toImageView.image else {
46 | assertionFailure("toImage is nil")
47 | return
48 | }
49 |
50 | // Use image with larger size
51 | let movingView = UIImageView(image: fromImage.largerCompared(with: toImage))
52 | movingView.clipsToBounds = true
53 | movingView.contentMode = .scaleAspectFill
54 | movingView.frame.size = fromImageView.displayingImageSize
55 | movingView.center = fromImageView.convertCenter(to: fromVC.view)
56 | movingView.layer.cornerRadius = fromImageView.layer.cornerRadius
57 |
58 | transitionContext.containerView.addSubviews(toVC.view, movingView)
59 |
60 | // Do not use "isHidden" not to animate in stackview
61 | fromImageView.alpha = 0.0
62 | toImageView.alpha = 0.0
63 | toVC.view.alpha = 0.0
64 |
65 | // To calculate displayImageSize correctly, recalculate the layout
66 | toVC.view.setNeedsLayout()
67 | toVC.view.layoutIfNeeded()
68 |
69 | let duration = transitionDuration(using: transitionContext)
70 | let options: UIView.AnimationOptions = animationOptions
71 | UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
72 | toVC.view.alpha = 1.0
73 | movingView.frame.size = toImageView.displayingImageSize
74 | movingView.center = toImageView.convertCenter(to: toVC.view)
75 | movingView.layer.cornerRadius = toImageView.layer.cornerRadius
76 | }, completion: { _ in
77 | // Do not use "isHidden" not to animate in stackview
78 | fromImageView.alpha = 1.0
79 | toImageView.alpha = 1.0
80 | movingView.removeFromSuperview()
81 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
82 | })
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/ImageTransition/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ImageTransition/UIImage+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+.swift
3 | // ImageTransition
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | internal extension UIImage {
12 | var area: CGFloat {
13 | size.width * size.height
14 | }
15 |
16 | func largerCompared(with comparedImage: UIImage) -> UIImage {
17 | area > comparedImage.area ? self : comparedImage
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ImageTransition/UIImageView+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+.swift
3 | // ImageTransition
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import AVFoundation
10 | import UIKit
11 |
12 | internal extension UIImageView {
13 | var displayingImageSize: CGSize {
14 | guard let image = image else { return .zero }
15 | switch contentMode {
16 | case .scaleAspectFit:
17 | return AVMakeRect(aspectRatio: image.size, insideRect: bounds).size
18 |
19 | default:
20 | return bounds.size
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ImageTransition/UIView+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+.swift
3 | // ImageTransition
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | internal extension UIView {
12 | func convertFrame(to view: UIView) -> CGRect {
13 | convert(bounds, to: view)
14 | }
15 |
16 | func convertCenter(to view: UIView) -> CGPoint {
17 | let frame = convertFrame(to: view)
18 | return CGPoint(x: frame.minX + frame.width / 2.0, y: frame.minY + frame.height / 2.0)
19 | }
20 |
21 | func addSubviews(_ views: UIView...) {
22 | views.forEach {
23 | addSubview($0)
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ImageTransitionTests/ImageTransitionAnimatorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransitionAnimatorTests.swift
3 | // ImageTransitionTests
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ImageTransition
11 |
12 | class ImageTransitionAnimatorTests: XCTestCase {
13 | func test_transitionDuration() {
14 | let expectedDuration = 3.0
15 | let imageTransitionAnimator = ImageTransitioning(duration: expectedDuration, animationOptions: .curveEaseIn)
16 | XCTAssertEqual(imageTransitionAnimator.transitionDuration(using: nil), expectedDuration)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ImageTransitionTests/ImageTransitionDelegateTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransitionDelegateTests.swift
3 | // ImageTransitionTests
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ImageTransition
11 |
12 | class ImageTransitionDelegateTests: XCTestCase {
13 | func test_animationController_forPresented() {
14 | let imageTransitionDelegate = ImageTransitionDelegate.shared
15 | XCTAssertNotNil(imageTransitionDelegate.animationController(forPresented: UIViewController(),
16 | presenting: UIViewController(),
17 | source: UIViewController()))
18 | }
19 |
20 | func test_animationController_forDismissed() {
21 | let imageTransitionDelegate = ImageTransitionDelegate.shared
22 | XCTAssertNotNil(imageTransitionDelegate.animationController(forDismissed: UIViewController()))
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ImageTransitionTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ImageTransitionTests/UIImage+Tests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Tests.swift
3 | // ImageTransitionTests
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | @testable import ImageTransition
10 | import XCTest
11 |
12 | class UIImage_Tests: XCTestCase {
13 | func test_area() {
14 | let image = UIImage.sampleImage(size: CGSize(width: 3, height: 4))
15 | XCTAssertEqual(image.area, 12)
16 | }
17 |
18 | func test_largerCompared() {
19 | let small = UIImage.sampleImage(size: CGSize(width: 10, height: 10))
20 | let large = UIImage.sampleImage(size: CGSize(width: 100, height: 100))
21 | XCTAssertEqual(small.largerCompared(with: large), large)
22 | XCTAssertEqual(large.largerCompared(with: small), large)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ImageTransitionTests/UIImageView+Tests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+Tests.swift
3 | // ImageTransitionTests
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | @testable import ImageTransition
10 | import XCTest
11 |
12 | class UIImageView_Tests: XCTestCase {
13 | func test_displayingImageSize_画像なし() {
14 | let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
15 | XCTAssertEqual(imageView.displayingImageSize, .zero)
16 | }
17 |
18 | func test_displayingImageSize_scaleAspectFitの場合_画像あり() {
19 | let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
20 | imageView.image = UIImage.sampleImage(size: CGSize(width: 50, height: 30))
21 | imageView.contentMode = .scaleAspectFit
22 | XCTAssertEqual(imageView.displayingImageSize, CGSize(width: 100, height: 60))
23 | }
24 |
25 | func test_displayingImageSize_scaleAspectFillの場合_画像あり() {
26 | let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
27 | imageView.image = UIImage.sampleImage(size: CGSize(width: 50, height: 30))
28 | imageView.contentMode = .scaleAspectFill
29 | XCTAssertEqual(imageView.displayingImageSize, CGSize(width: 100, height: 100))
30 | }
31 | }
32 |
33 | extension UIImage {
34 | class func sampleImage(size: CGSize) -> UIImage {
35 | UIGraphicsBeginImageContext(size)
36 | defer { UIGraphicsEndImageContext() }
37 |
38 | let rect = CGRect(origin: .zero, size: size)
39 | let context = UIGraphicsGetCurrentContext()!
40 | context.setFillColor(UIColor.white.cgColor)
41 | context.fill(rect)
42 | return UIGraphicsGetImageFromCurrentImageContext()!
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ImageTransitionTests/UIView+Tests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Tests.swift
3 | // ImageTransitionTests
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | @testable import ImageTransition
10 | import XCTest
11 |
12 | class UIView_Tests: XCTestCase {
13 | func test_convertFrame() {
14 | let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 1_000, height: 1_000))
15 | let view2 = UIView(frame: CGRect(x: 100, y: 200, width: 500, height: 500))
16 | let view3 = UIView(frame: CGRect(x: 300, y: 400, width: 200, height: 300))
17 | let view4 = UIView(frame: CGRect(x: 10, y: 20, width: 30, height: 40))
18 |
19 | view1.addSubview(view2)
20 | view2.addSubview(view3)
21 | view3.addSubview(view4)
22 |
23 | let expectedFrame = CGRect(x: 410, y: 620, width: 30, height: 40)
24 |
25 | XCTAssertEqual(expectedFrame, view4.convertFrame(to: view1))
26 | }
27 |
28 | func test_convertCenter() {
29 | let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 1_000, height: 1_000))
30 | let view2 = UIView(frame: CGRect(x: 100, y: 200, width: 500, height: 500))
31 | let view3 = UIView(frame: CGRect(x: 300, y: 400, width: 200, height: 300))
32 | let view4 = UIView(frame: CGRect(x: 10, y: 20, width: 30, height: 40))
33 |
34 | view1.addSubview(view2)
35 | view2.addSubview(view3)
36 | view3.addSubview(view4)
37 |
38 | let expectedCenter = CGPoint(x: 410 + 15, y: 620 + 20)
39 |
40 | XCTAssertEqual(expectedCenter, view4.convertCenter(to: view1))
41 | }
42 |
43 | func test_addSubviews() {
44 | let view1 = UIView()
45 | let view2 = UIView()
46 | let view3 = UIView()
47 | view1.addSubviews(view2, view3)
48 | XCTAssertTrue(view1.subviews.contains(view2))
49 | XCTAssertTrue(view1.subviews.contains(view3))
50 | }
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Shota Nakagami
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Mintfile:
--------------------------------------------------------------------------------
1 | realm/SwiftLint@0.42.0
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "ImageTransition",
6 | platforms: [.iOS("12.0")],
7 | products: [
8 | .library(
9 | name: "ImageTransition",
10 | targets: ["ImageTransition"])
11 | ],
12 | dependencies: [],
13 | targets: [
14 | .target(
15 | name: "ImageTransition",
16 | dependencies: []),
17 | .testTarget(
18 | name: "ImageTransitionTests",
19 | dependencies: ["ImageTransition"])
20 | ]
21 | )
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImageTransition
2 |
3 | [](https://github.com/shtnkgm/ImageTransition)
4 | [](https://github.com/Carthage/Carthage)
5 | [](https://developer.apple.com/swift)
6 | [](https://github.com/shtnkgm/ImageTransition/blob/master/LICENSE)
7 |
8 | **ImageTransition** is a library for smooth animation of images during transitions.
9 |
10 | Something looks like below:
11 |
12 | |e.g. UIImageView|e.g. UIImageView in UICollectionView|
13 | |:---:|:---:|
14 | |
|
|
15 |
16 | ## Feature
17 | - [x] Transition zooming animation like the iOS Photos app and the "Pinterest", and so on
18 | - [x] Easy to use (conform to `ImageTransitionable` protocol)
19 | - [x] Swifty (protocol-oriented)
20 | - [x] Animation configuration customizable (animation duration, UIView.AnimationOptions)
21 | - [x] CornerRadius animation (e.g. from a round image to a square Image)
22 |
23 | ## Installation
24 |
25 | - Swift Package Manager: `https://github.com/shtnkgm/ImageTransition.git`
26 | - Carthage: `github "shtnkgm/ImageTransition"`
27 | - CocoaPods: `pod "ImageTransition"`
28 |
29 | ## Usage
30 |
31 | - Confirm `ImageTransitionable` protocol
32 | ```swift
33 | // Source UIViewController
34 | import ImageTransition
35 | extension SourceViewController: ImageTransitionable {
36 | var imageViewForTransition: UIImageView? {
37 | return imageView
38 | }
39 | }
40 | // Destination UIViewController
41 | import ImageTransition
42 | extension DestinationViewController: ImageTransitionable {
43 | var imageViewForTransition: UIImageView? {
44 | return imageView
45 | }
46 | }
47 | ```
48 | - Set Delegate
49 | ```swift
50 | // present / dismiss transition
51 | @objc private func imageViewDidTapped() {
52 | let destinationViewController = DestinationViewController.make()
53 | destinationViewController.transitioningDelegate = ImageTransitionDelegate.shared
54 | present(destinationViewController, animated: true, completion: nil)
55 | }
56 |
57 | // push / pop transition
58 | @objc private func imageViewDidTapped() {
59 | let destinationViewController = DestinationViewController.make()
60 | // Set ImageTransitionDelegate.shared to `delegate` property of UINavigationContoller
61 | navigationController?.delegate = ImageTransitionDelegate.shared
62 | navigationController?.pushViewController(destinationViewController, animated: true)
63 | }
64 | ```
65 |
66 | ## Customize
67 |
68 | You can customize the configuration of animation.
69 |
70 | ```swift
71 | ImageTransitionDelegate.shared.presentDuration = 0.5
72 | ImageTransitionDelegate.shared.dismissDuration = 0.5
73 | ImageTransitionDelegate.shared.pushDuration = 0.5
74 | ImageTransitionDelegate.shared.popDuration = 0.5
75 | ImageTransitionDelegate.shared.presentAnimationOptions = [.curveLinear]
76 | ImageTransitionDelegate.shared.dismissAnimationOptions = [.curveEaseIn]
77 | ImageTransitionDelegate.shared.pushAnimationOptions = [.curveLinear]
78 | ImageTransitionDelegate.shared.popAnimationOptions = [.curveEaseIn]
79 | ```
80 |
81 | ## Requirements
82 |
83 | - iOS 14.0 or later
84 |
85 | ## Contributing
86 |
87 | Pull requests and stars are always welcome.
88 |
89 | For bugs and feature requests, please create an issue.
90 |
91 | 1. Fork it!
92 | 2. Create your feature branch: git checkout -b my-new-feature
93 | 3. Commit your changes: git commit -am 'Add some feature'
94 | 4. Push to the branch: git push origin my-new-feature
95 | 5. Submit a pull request :D
96 |
97 | ## Author
98 |
99 | - [@shtnkgm](https://github.com/shtnkgm) / Shota Nakagami [](https://twitter.com/shtnkgm)
100 |
101 | ## License
102 |
103 | ImageTransition is released under the MIT license. See [LICENSE](https://github.com/shtnkgm/ImageTransition/blob/master/LICENSE) for details.
104 |
--------------------------------------------------------------------------------
/Sample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Sample
4 | //
5 | // Created by Shota Nakagami on 2018/09/19.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | let window = UIWindow(frame: UIScreen.main.bounds)
18 | self.window = window
19 | window.rootViewController = UINavigationController(rootViewController: ItemListViewController())
20 | window.makeKeyAndVisible()
21 | return true
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/apple.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "apple-food-fruit-39803.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/apple.imageset/apple-food-fruit-39803.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/Sample/Assets.xcassets/apple.imageset/apple-food-fruit-39803.jpg
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/kiwi.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "food-fresh-fruit-51312.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/kiwi.imageset/food-fresh-fruit-51312.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/Sample/Assets.xcassets/kiwi.imageset/food-fresh-fruit-51312.jpg
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/lemon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "acid-bright-citrus-1414110.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/lemon.imageset/acid-bright-citrus-1414110.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/Sample/Assets.xcassets/lemon.imageset/acid-bright-citrus-1414110.jpg
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/orange.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "citrus-food-fresh-42059.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/orange.imageset/citrus-food-fresh-42059.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/Sample/Assets.xcassets/orange.imageset/citrus-food-fresh-42059.jpg
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/strawberry.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "close-up-food-fruit-59945.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/strawberry.imageset/close-up-food-fruit-59945.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/Sample/Assets.xcassets/strawberry.imageset/close-up-food-fruit-59945.jpg
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/tomato.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "cherry-tomatoes-food-freshness-48802.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Sample/Assets.xcassets/tomato.imageset/cherry-tomatoes-food-freshness-48802.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/Sample/Assets.xcassets/tomato.imageset/cherry-tomatoes-food-freshness-48802.jpg
--------------------------------------------------------------------------------
/Sample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Sample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | armv7
28 |
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Sample/ItemCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemCell.swift
3 | // Sample
4 | //
5 | // Created by Shota Nakagami on 2019/03/24.
6 | // Copyright © 2019 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ItemCell: UICollectionViewCell {
12 | static let identifier = String(describing: ItemCell.self)
13 |
14 | @IBOutlet private(set) weak var imageView: UIImageView!
15 | @IBOutlet private(set) weak var titleLabel: UILabel!
16 |
17 | override func awakeFromNib() {
18 | super.awakeFromNib()
19 | }
20 |
21 | func set(image: UIImage?, title: String) {
22 | imageView.image = image
23 | titleLabel.text = title
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Sample/ItemCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Sample/ItemDetailViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DestinationViewController.swift
3 | // Sample
4 | //
5 | // Created by Shota Nakagami on 2018/09/20.
6 | // Copyright © 2018年 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ImageTransition
11 |
12 | final class ItemDetailViewController: UIViewController {
13 | @IBOutlet private weak var imageView: UIImageView!
14 | @IBOutlet private weak var titleLabel: UILabel!
15 |
16 | private let dependency: Dependency
17 |
18 | struct Dependency {
19 | let image: UIImage
20 | let title: String
21 | }
22 |
23 | init(dependency: Dependency) {
24 | self.dependency = dependency
25 | super.init(nibName: nil, bundle: nil)
26 | }
27 |
28 | required init?(coder aDecoder: NSCoder) {
29 | fatalError("init(coder:) has not been implemented")
30 | }
31 |
32 | override func viewDidLoad() {
33 | super.viewDidLoad()
34 |
35 | imageView.image = dependency.image
36 | titleLabel.text = dependency.title
37 |
38 | imageView.isUserInteractionEnabled = true
39 | let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageViewDidTapped))
40 | imageView.addGestureRecognizer(tapGestureRecognizer)
41 | }
42 |
43 | @objc private func imageViewDidTapped() {
44 | dismiss(animated: true, completion: nil)
45 | }
46 | }
47 |
48 | extension ItemDetailViewController: ImageTransitionable {
49 | var imageViewForTransition: UIImageView? {
50 | return imageView
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Sample/ItemDetailViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
40 |
41 |
42 |
43 |
44 |
45 | Every season's fruit is attractive to each, and when you look at the harvested fruit you just get excited just to imagine "How delicious it would be if you make this a cake!"
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Sample/ItemListViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemListViewController.swift
3 | // Sample
4 | //
5 | // Created by Shota Nakagami on 2019/03/24.
6 | // Copyright © 2019 Shota Nakagami. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ImageTransition
11 |
12 | class ItemListViewController: UIViewController {
13 |
14 | private let margin: CGFloat = 1
15 | private let column: CGFloat = 3
16 |
17 | private let items: [String] = ["kiwi", "strawberry", "apple", "orange", "tomato", "lemon"]
18 |
19 | @IBOutlet private weak var collectionView: UICollectionView!
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 | collectionView.register(UINib(nibName: ItemCell.identifier, bundle: nil), forCellWithReuseIdentifier: ItemCell.identifier)
24 | collectionView.delegate = self
25 | collectionView.dataSource = self
26 | collectionView.reloadData()
27 | }
28 |
29 | private func selectedCell() -> ItemCell? {
30 | guard let selectedIndexPath = collectionView.indexPathsForSelectedItems?.first,
31 | let selectedCell = collectionView.cellForItem(at: selectedIndexPath) as? ItemCell else {
32 | assertionFailure()
33 | return nil
34 | }
35 | return selectedCell
36 | }
37 | }
38 |
39 | extension ItemListViewController: ImageTransitionable {
40 | var imageViewForTransition: UIImageView? {
41 | guard let selectedCell = selectedCell() else { return nil }
42 | return selectedCell.imageView
43 | }
44 | }
45 |
46 | extension ItemListViewController: UICollectionViewDelegate {
47 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
48 | guard let selectedCell = selectedCell(),
49 | let image = selectedCell.imageView.image,
50 | let title = selectedCell.titleLabel.text else { return }
51 |
52 | let destinationViewController = ItemDetailViewController(dependency: .init(image: image, title: title))
53 | navigationController?.delegate = ImageTransitionDelegate.shared
54 | ImageTransitionDelegate.shared.dismissDuration = 1
55 | ImageTransitionDelegate.shared.presentDuration = 1
56 | navigationController?.pushViewController(destinationViewController, animated: true)
57 | }
58 | }
59 |
60 | extension ItemListViewController: UICollectionViewDataSource {
61 | func numberOfSections(in collectionView: UICollectionView) -> Int {
62 | return 1
63 | }
64 |
65 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
66 | return 30
67 | }
68 |
69 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
70 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ItemCell.identifier, for: indexPath)
71 | guard let itemCell = cell as? ItemCell else { fatalError() }
72 | guard let item = items.randomElement() else { fatalError() }
73 | itemCell.set(image: UIImage(named: item), title: item)
74 | return cell
75 | }
76 | }
77 |
78 | extension ItemListViewController: UICollectionViewDelegateFlowLayout {
79 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
80 | let width = (UIScreen.main.bounds.width - margin * (column + 1)) / column
81 | return CGSize(width: width, height: width * 1.5)
82 | }
83 |
84 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
85 | return margin
86 | }
87 |
88 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
89 | return margin
90 | }
91 |
92 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
93 | return UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/Sample/ItemListViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/docs/assets/sample_01.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/docs/assets/sample_01.gif
--------------------------------------------------------------------------------
/docs/assets/sample_01.mov:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/docs/assets/sample_01.mov
--------------------------------------------------------------------------------
/docs/assets/sample_02.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/docs/assets/sample_02.gif
--------------------------------------------------------------------------------
/docs/assets/sample_02.mov:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shtnkgm/ImageTransition/30b503ac5a5bb1bb3ba95bc418155e4985eeb164/docs/assets/sample_02.mov
--------------------------------------------------------------------------------