Created
March 27, 2023 20:13
-
-
Save DarrenHurst/3e8c05264e4fe0184acf990f82eb05c3 to your computer and use it in GitHub Desktop.
A few simple animations on spot, and ms kitty.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftUI | |
@available(iOS 16.0, *) | |
struct AnimalPictures: View { | |
@State var profileImg: ProfileImgType = .teddybear | |
var body: some View { | |
VStack{ | |
HStack { | |
FunView(.white, backColor: Color.green) | |
.shadow(radius: 5) | |
Text("VS").font(.headline) | |
.foregroundColor(.black) | |
FunView(.white, backColor: Color.green) | |
.shadow(radius: 5) | |
} | |
.border(.gray, width: 1) | |
.padding(5) | |
.cornerRadius(4) | |
} | |
} | |
} | |
@available(iOS 16.0, *) | |
enum ProfileImgType { | |
case cat, koala, teddybear, dog | |
} | |
@available(iOS 13.0, *) | |
struct Triangle: Shape { | |
func path(in rect: CGRect) -> Path { | |
var path :Path = Path() | |
path.move(to: CGPoint(x:0,y:0)) | |
path.addLine(to: CGPoint(x:15, y:25)) | |
path.addLine(to: CGPoint(x:30, y:0)) | |
path.addLine(to: CGPoint(x:0, y:0)) | |
return path | |
} | |
} | |
@available(iOS 13.0, *) | |
struct Line: Shape { | |
func path(in rect: CGRect) -> Path { | |
var path: Path = Path() | |
path.move(to: CGPoint(x:0,y:0)) | |
path.addLine(to: CGPoint(x:3, y:18)) | |
return path | |
} | |
} | |
@available(iOS 16.0, *) | |
struct FunView: View, Identifiable { | |
var id: UUID = UUID() | |
@State var viewType: ProfileImgType = .dog | |
@State var blink: Bool = false | |
@State var animalColor: Color = .brown | |
@State var backgroundColor: Color = .brown | |
@State var whiskers: Bool = false | |
@State var spot: Bool = false | |
init(_ color: Color, backColor: Color) { | |
self.animalColor = color | |
self.backgroundColor = backColor | |
} | |
var body: some View { | |
VStack { | |
funProfile(animalColor, backgroundColor, 0.5, viewType) | |
VStack { | |
Button("Dog", action: { | |
viewType = .dog | |
animalColor = .brown | |
backgroundColor = .brown | |
}).foregroundColor(.black) | |
.padding(.bottom, 4) | |
.background(viewType == .dog ? .cyan.opacity(0.3): .clear) | |
Button("Cat", action: { | |
viewType = .cat | |
animalColor = .white | |
backgroundColor = .red | |
}).foregroundColor(.black) | |
.padding(.bottom, 4) | |
.background(viewType == .cat ? .cyan.opacity(0.3): .clear) | |
Button("Teddy", action: { | |
viewType = .teddybear | |
animalColor = .orange | |
backgroundColor = .green | |
}).foregroundColor(.black) | |
.padding(.bottom, 4) | |
.background(viewType == .teddybear ? .cyan.opacity(0.3): .clear) | |
Button("Koala", action: { | |
viewType = .koala | |
animalColor = .gray | |
backgroundColor = .yellow | |
}).foregroundColor(.black) | |
.padding(.bottom, 4) | |
.background(viewType == .koala ? .cyan.opacity(0.3): .clear) | |
}.padding(20) | |
}.padding(10) | |
} | |
public func baseColor(color: Color) -> any ShapeStyle { | |
LinearGradient( | |
gradient: Gradient( | |
colors: [.brown,color,color,.clear, .clear]), | |
startPoint: .top, endPoint: .bottom | |
) | |
} | |
} | |
@available(iOS 16.0, *) | |
extension FunView { | |
fileprivate func funProfile(_ base: Color, _ color: Color, _ opacity: Double, _ viewType: ProfileImgType) -> some View { | |
let bearColor: Color = base | |
return ZStack { | |
animalHead(bearColor, viewType) | |
.rotationEffect( Angle(degrees: 80) ) | |
.frame(width:50).scaledToFit().offset(y:10).zIndex(0.2) | |
ZStack { | |
AnyView( | |
Circle() | |
.fill(baseColor(color: bearColor)) | |
.frame(width: 47).offset(y:50) | |
.scaleEffect(x: 1.2, y: 2, anchor: .bottom)) | |
AnyView( | |
Circle() | |
.fill(baseColor(color: bearColor)) | |
.frame(width: 47).offset(x:20, y:50).scaleEffect(x: 1.1, y: 1.3, anchor: .bottom)) | |
AnyView( | |
Circle() | |
.fill(baseColor(color: bearColor)) | |
.frame(width: 47).offset(x:-20, y:50).scaleEffect(x: 1.1, y: 1.4, anchor: .bottom)) | |
}.zIndex(0.1) | |
animalHead(bearColor.opacity(0.5), viewType).controlSize(.small) | |
.rotationEffect( Angle(degrees: 80) ) | |
.frame(width:50).scaledToFit().offset(y:10).zIndex(0.2) | |
}.frame(width: 100, height:120) | |
.background(.white.opacity(0.05)) | |
.background(color.opacity(opacity)) | |
.mask(Circle()) | |
.shadow(radius: 2) | |
} | |
fileprivate func face(_ color: Color) -> some View { | |
ZStack { | |
Circle().frame(width:10).offset(x:5).zIndex(0.2) | |
Circle().frame(width:2).offset(x:15).zIndex(0.2) | |
Circle().fill().frame(height: 5).offset(x: -1, y: 10).opacity(0.3).zIndex(0.2) | |
Circle().fill().frame(height: 5).offset(x: 3, y: -10).opacity(0.5).zIndex(0.2) | |
Circle() | |
.fill(RadialGradient.init(colors: [color.opacity(0.6), color.opacity(1), color.opacity(0.8)], center: .top, startRadius: 10.0, endRadius: 90.0)) | |
.opacity(blink ? 0.7 : 0.6) | |
.animation(.default.speed(0.5).repeatForever(), value: blink).zIndex(0.6) | |
} | |
} | |
fileprivate func ears(_ color: Color) -> some View { | |
ZStack { | |
Circle().fill(LinearGradient(gradient: Gradient(colors: [color, .clear, .clear]), startPoint: .bottomLeading, endPoint: .topTrailing).opacity(0.9)) | |
.zIndex(0.2) | |
.frame(width:35) | |
.offset(x:-15, y: 13) | |
Circle().fill(LinearGradient(gradient: Gradient(colors: [color, .clear, .clear]), startPoint: .topLeading, endPoint: .bottomTrailing).opacity(0.9)) | |
.zIndex(0.2) | |
.frame(width:35) | |
.offset(x:-12, y: -15) | |
} | |
} | |
fileprivate func builderCircle(_ color: Color) -> some View { | |
return Circle().stroke(lineWidth: 13).fill(color.opacity(0.2)).transformEffect(CGAffineTransform(a: 0.2, b: -0.2, c: 0.4, d: 0.4, tx: -2, ty: 31)).rotationEffect(Angle(degrees: 49)).shadow(radius: 5) | |
} | |
fileprivate func whiskersView() -> some View { | |
ZStack { | |
Line() | |
.stroke(style: StrokeStyle(lineWidth: 1)) | |
.fill(.gray) | |
.offset(x:30, y:24) | |
.shadow(radius: 5) | |
Line() | |
.stroke(style: StrokeStyle(lineWidth: 1)) | |
.fill(.gray) | |
.offset(x:-12, y:35) | |
.rotationEffect(Angle(degrees: 45), anchor: .bottom) | |
.shadow(radius: 5) | |
Line() | |
.stroke(style: StrokeStyle(lineWidth: 1)) | |
.fill(.gray) | |
.offset(x:34, y:60) | |
.shadow(radius: 5) | |
Line() | |
.stroke(style: StrokeStyle(lineWidth: 1)) | |
.fill(.gray) | |
.offset(x:10, y:62) | |
.rotationEffect(Angle(degrees: 34), anchor: .bottom) | |
.shadow(radius: 5) | |
} | |
} | |
fileprivate func animalHead(_ color: Color, _ viewType: ProfileImgType) -> | |
some View { | |
ZStack { | |
ZStack { | |
if [.dog, .teddybear, .koala].contains(viewType) { | |
ears(color) | |
} | |
if [.dog].contains(viewType) { | |
//white face | |
Circle() | |
.fill(.white) | |
.frame(width: 50, height: 100) | |
//snoot | |
Circle() | |
.fill(.gray) | |
.frame(width: 50, height: 20).offset(x:10) | |
//Spot | |
Circle() | |
.fill(.gray.opacity(0.4)) | |
.frame(width: 50, height: spot ? 20 : 30).offset(x:-3, y:10) | |
.animation(.default.repeatCount(3), value: spot) | |
.onAppear() { | |
spot = true | |
} | |
.onDisappear() { | |
spot = false | |
} | |
} | |
face(color) | |
if viewType == .cat { | |
Triangle().fill(LinearGradient(gradient: Gradient(colors: [.white, .clear]), startPoint: .bottom, endPoint: .top)) | |
.frame(width: 25).scaledToFit() | |
.rotationEffect(Angle(degrees: 66)) | |
.offset(x:-30, y:10) | |
.shadow(radius: 2) | |
Triangle() | |
.fill(LinearGradient(gradient: Gradient(colors: [.clear, .white, .white, .white]), startPoint: .topLeading, endPoint: .bottomLeading)) | |
.frame(width: 5).scaledToFit() | |
.rotationEffect(Angle(degrees: 6)).offset(x:-44, y:19) | |
ZStack{ | |
whiskersView().rotationEffect(Angle(degrees: whiskers ? 0 : 15)) | |
.animation(.default.repeatCount(10).speed(0.5), value: whiskers) | |
.onAppear() { | |
whiskers = true | |
} | |
.onDisappear() { | |
whiskers = false | |
} | |
}.zIndex(0.1) | |
.shadow(radius: 5) | |
} | |
}.zIndex(0.05) | |
.shadow(radius: blink ? 0 : 2) | |
.animation(.default.speed(0.1).repeatForever(), value: blink) | |
.zIndex(0.1) | |
.offset( y: blink ? 0 : 0.1) | |
.animation(.default.speed(0.1).repeatForever(), value: blink) | |
.onAppear(){ | |
blink = true | |
} | |
}.onAppear() { | |
blink = blink ? false : true | |
} | |
} | |
} | |
@available(iOS 16.0, *) | |
struct AnimalPicturePreview: PreviewProvider { | |
static var previews: some View { | |
AnimalPictures() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Screen.Recording.2023-03-27.at.4.06.28.PM.mov