From fc9310de2095a3dbe4ea72e5ad94296c15b6cce1 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 2 Mar 2021 13:45:47 +0800 Subject: [PATCH] feat: add motion effect for welcome illustration elements --- Mastodon.xcodeproj/project.pbxproj | 44 ++++-- .../xcschemes/xcschememanagement.plist | 4 +- .../Mastodon+Entidy+ErrorDetailReason.swift | 1 + .../UIInterpolatingMotionEffect.swift | 30 ++++ Mastodon/Generated/Assets.swift | 1 + .../TootContent.swift} | 2 +- .../View/WelcomeIllustrationView.swift | 132 ++++++++++++------ .../Welcome/WelcomeViewController.swift | 35 ++++- Mastodon/Supporting Files/AppDelegate.swift | 8 +- 9 files changed, 194 insertions(+), 63 deletions(-) rename Mastodon/Extension/{ => MastodonSDK}/Mastodon+Entidy+ErrorDetailReason.swift (99%) create mode 100644 Mastodon/Extension/UIInterpolatingMotionEffect.swift rename Mastodon/{Extension/MastodonContent.swift => Helper/TootContent.swift} (99%) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 8878f8065..6de95a41e 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -38,7 +38,7 @@ 2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D38F20725CD491300561493 /* DisposeBagCollectable.swift */; }; 2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */; }; 2D42FF6125C8177C004A627A /* ActiveLabel in Frameworks */ = {isa = PBXBuildFile; productRef = 2D42FF6025C8177C004A627A /* ActiveLabel */; }; - 2D42FF6B25C817D2004A627A /* MastodonContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF6A25C817D2004A627A /* MastodonContent.swift */; }; + 2D42FF6B25C817D2004A627A /* TootContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF6A25C817D2004A627A /* TootContent.swift */; }; 2D42FF7E25C82218004A627A /* ActionToolBarContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF7D25C82218004A627A /* ActionToolBarContainer.swift */; }; 2D42FF8525C8224F004A627A /* HitTestExpandedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF8425C8224F004A627A /* HitTestExpandedButton.swift */; }; 2D42FF8F25C8228A004A627A /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF8E25C8228A004A627A /* UIButton.swift */; }; @@ -160,6 +160,7 @@ DB9D6C2425E502C60051B173 /* MosaicImageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6C2225E502C60051B173 /* MosaicImageViewModel.swift */; }; DB9D6C2E25E504AC0051B173 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6C2D25E504AC0051B173 /* Attachment.swift */; }; DB9D6C3825E508BE0051B173 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6C3725E508BE0051B173 /* Attachment.swift */; }; + DB9E0D6F25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */; }; DBABE3EC25ECAC4B00879EE5 /* WelcomeIllustrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBABE3EB25ECAC4B00879EE5 /* WelcomeIllustrationView.swift */; }; DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */; }; DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */; }; @@ -248,7 +249,7 @@ 2D38F1FD25CD481700561493 /* StatusProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusProvider.swift; sourceTree = ""; }; 2D38F20725CD491300561493 /* DisposeBagCollectable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisposeBagCollectable.swift; sourceTree = ""; }; 2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITapGestureRecognizer.swift; sourceTree = ""; }; - 2D42FF6A25C817D2004A627A /* MastodonContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonContent.swift; sourceTree = ""; }; + 2D42FF6A25C817D2004A627A /* TootContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TootContent.swift; sourceTree = ""; }; 2D42FF7D25C82218004A627A /* ActionToolBarContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionToolBarContainer.swift; sourceTree = ""; }; 2D42FF8425C8224F004A627A /* HitTestExpandedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HitTestExpandedButton.swift; sourceTree = ""; }; 2D42FF8E25C8228A004A627A /* UIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIButton.swift; sourceTree = ""; }; @@ -380,6 +381,7 @@ DB9D6C2225E502C60051B173 /* MosaicImageViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MosaicImageViewModel.swift; sourceTree = ""; }; DB9D6C2D25E504AC0051B173 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; DB9D6C3725E508BE0051B173 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; + DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIInterpolatingMotionEffect.swift; sourceTree = ""; }; DBABE3EB25ECAC4B00879EE5 /* WelcomeIllustrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeIllustrationView.swift; sourceTree = ""; }; DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Onboarding.swift"; sourceTree = ""; }; DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewController.swift; sourceTree = ""; }; @@ -801,6 +803,7 @@ 2D61335525C1886800CAE157 /* Service */, DB8AF55525C1379F002E6C99 /* Scene */, DB8AF54125C13647002E6C99 /* Coordinator */, + DB9E0D6925EDFFE500CFDD76 /* Helper */, DB8AF56225C138BC002E6C99 /* Extension */, 2D5A3D0125CF8640002347D6 /* Vender */, DB5086CB25CC0DB400C2C187 /* Preference */, @@ -1000,22 +1003,22 @@ isa = PBXGroup; children = ( DB084B5125CBC56300F898ED /* CoreDataStack */, - DB0140CE25C42AEE00F9F3CF /* OSLog.swift */, - 2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */, - DB8AF55C25C138B7002E6C99 /* UIViewController.swift */, - 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */, - 2D46976325C2A71500CF4AA9 /* UIIamge.swift */, + DB9E0D6425EDFF5600CFDD76 /* MastodonSDK */, 2DF123A625C3B0210020F248 /* ActiveLabel.swift */, + 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */, DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */, - 2D42FF6A25C817D2004A627A /* MastodonContent.swift */, + 2D939AB425EDD8A90076FA61 /* String.swift */, + DB0140CE25C42AEE00F9F3CF /* OSLog.swift */, DB68A06225E905E000CFDF14 /* UIApplication.swift */, DB45FAB525CA5485005A8AC7 /* UIAlertController.swift */, 2D42FF8E25C8228A004A627A /* UIButton.swift */, DB45FAD625CA6C76005A8AC7 /* UIBarButtonItem.swift */, - 2D32EAB925CB9B0500C9ED86 /* UIView.swift */, 0FAA101B25E10E760017CCDE /* UIFont.swift */, - 2D650FAA25ECDC9300851B58 /* Mastodon+Entidy+ErrorDetailReason.swift */, - 2D939AB425EDD8A90076FA61 /* String.swift */, + 2D46976325C2A71500CF4AA9 /* UIIamge.swift */, + 2D32EAB925CB9B0500C9ED86 /* UIView.swift */, + DB8AF55C25C138B7002E6C99 /* UIViewController.swift */, + 2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */, + DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */, ); path = Extension; sourceTree = ""; @@ -1078,6 +1081,22 @@ path = ViewModel; sourceTree = ""; }; + DB9E0D6425EDFF5600CFDD76 /* MastodonSDK */ = { + isa = PBXGroup; + children = ( + 2D650FAA25ECDC9300851B58 /* Mastodon+Entidy+ErrorDetailReason.swift */, + ); + path = MastodonSDK; + sourceTree = ""; + }; + DB9E0D6925EDFFE500CFDD76 /* Helper */ = { + isa = PBXGroup; + children = ( + 2D42FF6A25C817D2004A627A /* TootContent.swift */, + ); + path = Helper; + sourceTree = ""; + }; DBABE3F125ECAC4E00879EE5 /* View */ = { isa = PBXGroup; children = ( @@ -1486,6 +1505,7 @@ 2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */, DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */, DB98337F25C9452D00AD9700 /* APIService+APIError.swift in Sources */, + DB9E0D6F25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift in Sources */, 2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */, DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */, 2DF75B9B25D0E27500694EC8 /* StatusProviderFacade.swift in Sources */, @@ -1540,7 +1560,7 @@ 2D76317D25C14DF500929FB9 /* PublicTimelineViewController+StatusProvider.swift in Sources */, 2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */, DB98339C25C96DE600AD9700 /* APIService+Account.swift in Sources */, - 2D42FF6B25C817D2004A627A /* MastodonContent.swift in Sources */, + 2D42FF6B25C817D2004A627A /* TootContent.swift in Sources */, 2DF75BA725D10E1000694EC8 /* APIService+Favorite.swift in Sources */, DB9D6C3825E508BE0051B173 /* Attachment.swift in Sources */, DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b1a7a744c..da5807cfe 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -17,12 +17,12 @@ Mastodon - Release.xcscheme_^#shared#^_ orderHint - 1 + 3 Mastodon.xcscheme_^#shared#^_ orderHint - 0 + 1 SuppressBuildableAutocreation diff --git a/Mastodon/Extension/Mastodon+Entidy+ErrorDetailReason.swift b/Mastodon/Extension/MastodonSDK/Mastodon+Entidy+ErrorDetailReason.swift similarity index 99% rename from Mastodon/Extension/Mastodon+Entidy+ErrorDetailReason.swift rename to Mastodon/Extension/MastodonSDK/Mastodon+Entidy+ErrorDetailReason.swift index cc1a47907..500bc1cb8 100644 --- a/Mastodon/Extension/Mastodon+Entidy+ErrorDetailReason.swift +++ b/Mastodon/Extension/MastodonSDK/Mastodon+Entidy+ErrorDetailReason.swift @@ -4,6 +4,7 @@ // // Created by sxiaojian on 2021/3/1. // + import MastodonSDK extension Mastodon.Entity.ErrorDetailReason { diff --git a/Mastodon/Extension/UIInterpolatingMotionEffect.swift b/Mastodon/Extension/UIInterpolatingMotionEffect.swift new file mode 100644 index 000000000..5ab4cb2f5 --- /dev/null +++ b/Mastodon/Extension/UIInterpolatingMotionEffect.swift @@ -0,0 +1,30 @@ +// +// UIInterpolatingMotionEffect.swift +// Mastodon +// +// Created by MainasuK Cirno on 2021-3-2. +// + +import UIKit + +extension UIInterpolatingMotionEffect { + static func motionEffect( + minX: CGFloat, + maxX: CGFloat, + minY: CGFloat, + maxY: CGFloat + ) -> UIMotionEffectGroup { + let motionEffectX = UIInterpolatingMotionEffect(keyPath: "layer.transform.translation.x", type: .tiltAlongHorizontalAxis) + motionEffectX.minimumRelativeValue = minX + motionEffectX.maximumRelativeValue = maxX + + let motionEffectY = UIInterpolatingMotionEffect(keyPath: "layer.transform.translation.y", type: .tiltAlongVerticalAxis) + motionEffectY.minimumRelativeValue = minY + motionEffectY.maximumRelativeValue = maxY + + let motionEffectGroup = UIMotionEffectGroup() + motionEffectGroup.motionEffects = [motionEffectX, motionEffectY] + + return motionEffectGroup + } +} diff --git a/Mastodon/Generated/Assets.swift b/Mastodon/Generated/Assets.swift index 46780bb6a..c909b6206 100644 --- a/Mastodon/Generated/Assets.swift +++ b/Mastodon/Generated/Assets.swift @@ -84,6 +84,7 @@ internal enum Asset { } internal static let mastodonLogo = ImageAsset(name: "Welcome/mastodon.logo") internal static let mastodonLogoLarge = ImageAsset(name: "Welcome/mastodon.logo.large") + internal static let welcomeLogo = ImageAsset(name: "Welcome/welcome.logo") } } // swiftlint:enable identifier_name line_length nesting type_body_length type_name diff --git a/Mastodon/Extension/MastodonContent.swift b/Mastodon/Helper/TootContent.swift similarity index 99% rename from Mastodon/Extension/MastodonContent.swift rename to Mastodon/Helper/TootContent.swift index b1b1a635f..55f71beac 100755 --- a/Mastodon/Extension/MastodonContent.swift +++ b/Mastodon/Helper/TootContent.swift @@ -1,5 +1,5 @@ // -// MastodonContent.swift +// TootContent.swift // Mastodon // // Created by MainasuK Cirno on 2021/2/1. diff --git a/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift b/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift index 0e733b74e..4817ffc33 100644 --- a/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift +++ b/Mastodon/Scene/Onboarding/Welcome/View/WelcomeIllustrationView.swift @@ -10,7 +10,13 @@ import UIKit final class WelcomeIllustrationView: UIView { static let artworkImageSize = CGSize(width: 870, height: 2000) - let artworkImageView = UIImageView() + + let cloudBaseImageView = UIImageView() + let rightHillImageView = UIImageView() + let leftHillImageView = UIImageView() + let centerHillImageView = UIImageView() + let lineDashTwoImageView = UIImageView() + let elephantTwoImageView = UIImageView() // layout outside let elephantOnAirplaneWithContrailImageView: UIImageView = { @@ -47,6 +53,7 @@ final class WelcomeIllustrationView: UIView { } extension WelcomeIllustrationView { + private func _init() { backgroundColor = Asset.Welcome.Illustration.backgroundCyan.color @@ -60,65 +67,108 @@ extension WelcomeIllustrationView { topPaddingView.trailingAnchor.constraint(equalTo: trailingAnchor), ]) - artworkImageView.translatesAutoresizingMaskIntoConstraints = false - addSubview(artworkImageView) + cloudBaseImageView.translatesAutoresizingMaskIntoConstraints = false + addSubview(cloudBaseImageView) NSLayoutConstraint.activate([ - artworkImageView.topAnchor.constraint(equalTo: topPaddingView.bottomAnchor), - artworkImageView.leadingAnchor.constraint(equalTo: leadingAnchor), - artworkImageView.trailingAnchor.constraint(equalTo: trailingAnchor), - artworkImageView.bottomAnchor.constraint(equalTo: bottomAnchor), - artworkImageView.widthAnchor.constraint(equalTo: artworkImageView.heightAnchor, multiplier: WelcomeIllustrationView.artworkImageSize.width / WelcomeIllustrationView.artworkImageSize.height), + cloudBaseImageView.topAnchor.constraint(equalTo: topPaddingView.bottomAnchor), + cloudBaseImageView.leadingAnchor.constraint(equalTo: leadingAnchor), + cloudBaseImageView.trailingAnchor.constraint(equalTo: trailingAnchor), + cloudBaseImageView.bottomAnchor.constraint(equalTo: bottomAnchor), + cloudBaseImageView.widthAnchor.constraint(equalTo: cloudBaseImageView.heightAnchor, multiplier: WelcomeIllustrationView.artworkImageSize.width / WelcomeIllustrationView.artworkImageSize.height), ]) + + + [ + rightHillImageView, + leftHillImageView, + centerHillImageView, + lineDashTwoImageView, + elephantTwoImageView, + ].forEach { imageView in + imageView.translatesAutoresizingMaskIntoConstraints = false + addSubview(imageView) + NSLayoutConstraint.activate([ + imageView.topAnchor.constraint(equalTo: cloudBaseImageView.topAnchor), + imageView.leadingAnchor.constraint(equalTo: cloudBaseImageView.leadingAnchor), + imageView.trailingAnchor.constraint(equalTo: cloudBaseImageView.trailingAnchor), + imageView.bottomAnchor.constraint(equalTo: cloudBaseImageView.bottomAnchor), + ]) + } } override func layoutSubviews() { super.layoutSubviews() - artworkImageView.image = WelcomeIllustrationView.artworkImage() + updateImage() } - static func artworkImage() -> UIImage { - let size = artworkImageSize - let width = artworkImageSize.width - let height = artworkImageSize.height - let image = UIGraphicsImageRenderer(size: size).image { context in + private func updateImage() { + let size = WelcomeIllustrationView.artworkImageSize + let width = size.width + let height = size.height + + let elephantFourOnGrassWithTreeTwoImage = Asset.Welcome.Illustration.elephantFourOnGrassWithTreeTwo.image + let elephantThreeOnGrassWithTreeFourImage = Asset.Welcome.Illustration.elephantThreeOnGrassWithTreeFour.image + let elephantThreeOnGrassImage = Asset.Welcome.Illustration.elephantThreeOnGrass.image + let elephantTwoImage = Asset.Welcome.Illustration.elephantTwo.image + let lineDashTwoImage = Asset.Welcome.Illustration.lineDashTwo.image + + + cloudBaseImageView.image = UIGraphicsImageRenderer(size: size).image { context in // clear background UIColor.clear.setFill() - context.fill(CGRect(origin: .zero, size: artworkImageSize)) + context.fill(CGRect(origin: .zero, size: size)) // draw cloud let cloudBaseImage = Asset.Welcome.Illustration.cloudBase.image cloudBaseImage.draw(at: CGPoint(x: 0, y: height - cloudBaseImage.size.height)) - - let elephantFourOnGrassWithTreeTwoImage = Asset.Welcome.Illustration.elephantFourOnGrassWithTreeTwo.image - let elephantThreeOnGrassWithTreeFourImage = Asset.Welcome.Illustration.elephantThreeOnGrassWithTreeFour.image - let elephantThreeOnGrassImage = Asset.Welcome.Illustration.elephantThreeOnGrass.image - let elephantTwoImage = Asset.Welcome.Illustration.elephantTwo.image - let lineDashTwoImage = Asset.Welcome.Illustration.lineDashTwo.image - - // let elephantOnAirplaneWithContrailImageView = Asset.Welcome.Illustration.elephantOnAirplaneWithContrail.image - - // draw elephantFourOnGrassWithTreeTwo - // elephantFourOnGrassWithTreeTwo.bottomY + 40 align to elephantThreeOnGrassImage.centerY - elephantFourOnGrassWithTreeTwoImage.draw(at: CGPoint(x: 0, y: height - 0.5 * elephantThreeOnGrassImage.size.height - elephantFourOnGrassWithTreeTwoImage.size.height - 40)) - + } + + rightHillImageView.image = UIGraphicsImageRenderer(size: size).image { context in + // clear background + UIColor.clear.setFill() + context.fill(CGRect(origin: .zero, size: size)) + // draw elephantThreeOnGrassWithTreeFour // elephantThreeOnGrassWithTreeFour.bottomY + 40 align to elephantThreeOnGrassImage.centerY elephantThreeOnGrassWithTreeFourImage.draw(at: CGPoint(x: width - elephantThreeOnGrassWithTreeFourImage.size.width, y: height - 0.5 * elephantThreeOnGrassImage.size.height - elephantThreeOnGrassWithTreeFourImage.size.height - 40)) - - // draw elephantThreeOnGrass - elephantThreeOnGrassImage.draw(at: CGPoint(x: 0, y: height - elephantThreeOnGrassImage.size.height)) - - // darw ineDashTwoImage - lineDashTwoImage.draw(at: CGPoint(x: 0.5 * elephantThreeOnGrassImage.size.width + 60, y: height - elephantThreeOnGrassImage.size.height - 50)) - - // draw elephantTwo.image - elephantTwoImage.draw(at: CGPoint(x: 0, y: height - elephantTwoImage.size.height - 125)) - - // draw elephantOnAirplaneWithContrailImageView - // elephantOnAirplaneWithContrailImageView.draw(at: CGPoint(x: 0, y: height - cloudBaseImage.size.height - 0.5 * elephantOnAirplaneWithContrailImageView.size.height)) } - return image + leftHillImageView.image = UIGraphicsImageRenderer(size: size).image { context in + // clear background + UIColor.clear.setFill() + context.fill(CGRect(origin: .zero, size: size)) + + // draw elephantFourOnGrassWithTreeTwo + // elephantFourOnGrassWithTreeTwo.bottomY + 40 align to elephantThreeOnGrassImage.centerY + elephantFourOnGrassWithTreeTwoImage.draw(at: CGPoint(x: 0, y: height - 0.5 * elephantThreeOnGrassImage.size.height - elephantFourOnGrassWithTreeTwoImage.size.height - 40)) + } + + centerHillImageView.image = UIGraphicsImageRenderer(size: size).image { context in + // clear background + UIColor.clear.setFill() + context.fill(CGRect(origin: .zero, size: size)) + + // draw elephantThreeOnGrass + elephantThreeOnGrassImage.draw(at: CGPoint(x: 0, y: height - elephantThreeOnGrassImage.size.height)) + } + + lineDashTwoImageView.image = UIGraphicsImageRenderer(size: size).image { context in + // clear background + UIColor.clear.setFill() + context.fill(CGRect(origin: .zero, size: size)) + + // darw ineDashTwoImage + lineDashTwoImage.draw(at: CGPoint(x: 0.5 * elephantThreeOnGrassImage.size.width + 60, y: height - elephantThreeOnGrassImage.size.height - 50)) + } + + elephantTwoImageView.image = UIGraphicsImageRenderer(size: size).image { context in + // clear background + UIColor.clear.setFill() + context.fill(CGRect(origin: .zero, size: size)) + + // draw elephantTwo.image + elephantTwoImage.draw(at: CGPoint(x: 0, y: height - elephantTwoImage.size.height - 125)) + } } } diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index 16592f328..e306aafe9 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -75,6 +75,25 @@ extension WelcomeViewController { ]) view.backgroundColor = .black welcomeIllustrationView.alpha = 0.9 + + welcomeIllustrationView.cloudBaseImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -5, maxX: 5, minY: -5, maxY: 5) + ) + welcomeIllustrationView.rightHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -12, maxX: 12, minY: -12, maxY: 12) + ) + welcomeIllustrationView.leftHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -12, maxX: 12, minY: -20, maxY: 20) + ) + welcomeIllustrationView.centerHillImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -14, maxX: 14, minY: -30, maxY: 30) + ) + welcomeIllustrationView.lineDashTwoImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -25, maxX: 25, minY: -40, maxY: 40) + ) + welcomeIllustrationView.elephantTwoImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -30, maxX: 30, minY: -30, maxY: 30) + ) } view.addSubview(logoImageView) @@ -122,12 +141,26 @@ extension WelcomeViewController { welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(welcomeIllustrationView.elephantOnAirplaneWithContrailImageView) NSLayoutConstraint.activate([ - welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.leftAnchor.constraint(equalTo: view.leftAnchor), + view.leftAnchor.constraint(equalTo: welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.leftAnchor, constant: 12), // add 12pt bleeding welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.bottomAnchor.constraint(equalTo: sloganLabel.topAnchor), // make a little bit large welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.widthAnchor.constraint(equalToConstant: 656 / traitCollection.displayScale * imageSizeScale), welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.heightAnchor.constraint(equalToConstant: 195 / traitCollection.displayScale * imageSizeScale), ]) + + welcomeIllustrationView.cloudFirstImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -30, maxX: 30, minY: -20, maxY: 10) + ) + welcomeIllustrationView.cloudSecondImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -10, maxX: 30, minY: -8, maxY: 10) + ) + welcomeIllustrationView.cloudThirdImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -20, maxX: 10, minY: -6, maxY: 10) + ) + welcomeIllustrationView.elephantOnAirplaneWithContrailImageView.addMotionEffect( + UIInterpolatingMotionEffect.motionEffect(minX: -20, maxX: 12, minY: -20, maxY: 12) // maxX should not larger then the bleeding (12pt) + ) + view.bringSubviewToFront(logoImageView) view.bringSubviewToFront(sloganLabel) } diff --git a/Mastodon/Supporting Files/AppDelegate.swift b/Mastodon/Supporting Files/AppDelegate.swift index 00d839b51..72ee1334d 100644 --- a/Mastodon/Supporting Files/AppDelegate.swift +++ b/Mastodon/Supporting Files/AppDelegate.swift @@ -40,12 +40,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { extension AppDelegate { - func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { - #if DEBUG - return .all - #else - return UIDevice.current.userInterfaceIdiom == .pad ? .all : .portrait - #endif + func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { + return UIDevice.current.userInterfaceIdiom == .phone ? .portrait : .all } }