Skip to content

Instantly share code, notes, and snippets.

@CodeSlicing
Created May 17, 2020 21:26
Show Gist options
  • Save CodeSlicing/33378e564f8f9941933067c08ba1a6e4 to your computer and use it in GitHub Desktop.
Save CodeSlicing/33378e564f8f9941933067c08ba1a6e4 to your computer and use it in GitHub Desktop.
Code for CodeSlicing episode creating the add animations in MyFitnessPal
//
// MyFitnessPalAddAnimation.swift
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Copyright © 2020 Adam Fordyce. All rights reserved.
//
import SwiftUI
import PureSwiftUI
private let buttonBlue = Color(red: 42/255, green: 99/255, blue: 228/255)
private typealias TitleAndSymbol = (title: String, symbol: SFSymbolName)
private let buttonTitlesAndSymbols: [[TitleAndSymbol]] = [
[("Favorite", .star), ("Tag", .tag), ("Share", .square_and_arrow_up)],
[("Comment", .text_bubble), ("Delete", .trash)]
]
private let defaultAnimation = Animation.easeInOut(duration: 0.2)
private let hideAnimation = defaultAnimation
private let showAnimation = Animation.spring(response: 0.3, dampingFraction: 0.6)
struct MyFitnessPalAddAnimation: View {
@State private var showingButtons = false
@State private var homeLocation = CGPoint.zero
var body: some View {
ZStack {
Color.black.opacity(0.8)
.opacityIfNot(self.showingButtons, 0)
.animation(defaultAnimation)
VStack(spacing: 60) {
Spacer()
ForEach(0..<buttonTitlesAndSymbols.count) { rowIndex in
HStack(spacing: 60) {
ForEach(0..<buttonTitlesAndSymbols[rowIndex].count) { colIndex in
MyFitnessPalButton(titleAndSymbol: buttonTitlesAndSymbols[rowIndex][colIndex])
.opacityIfNot(self.showingButtons, 0)
.offsetToPositionIfNot(self.showingButtons, self.homeLocation)
}
}
}
Circle()
.fill(buttonBlue)
.overlay(SFSymbol(.plus).foregroundColor(.white)
.rotateIf(self.showingButtons, -45.degrees))
.frame(48)
.geometryReader { (geo: GeometryProxy) in
self.homeLocation = geo.globalCenter
}
.onTapGesture {
withAnimation(self.showingButtons ? hideAnimation : showAnimation) {
self.showingButtons.toggle()
}
}
}
.padding()
}
.edgesIgnoringSafeArea(.all)
}
}
struct MyFitnessPalButton: View {
fileprivate let titleAndSymbol: TitleAndSymbol
var body: some View {
Circle()
.fillColor(.white)
.overlay(SFSymbol(titleAndSymbol.symbol))
.overlay(CaptionText(titleAndSymbol.title.uppercased(), .white, .semibold).fixedSize().yOffset(40))
.frame(50)
}
}
struct MyFitnessPalAddAnimation_Previews: PreviewProvider {
struct MyFitnessPalAddAnimation_Harness: View {
var body: some View {
MyFitnessPalAddAnimation().previewDevice(.iPhone_8)
}
}
static var previews: some View {
MyFitnessPalAddAnimation_Harness()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment