From b3d16a9b47c5c588341f75c09a7d37701b86ec2b Mon Sep 17 00:00:00 2001 From: HayesGordon Date: Fri, 15 Dec 2023 09:14:17 +0000 Subject: [PATCH] chore: cleanup ios examples This PR: - Removes developer comments + Todos - Changes the samples to use @StateObject for the RiveViewModel instances. This is the SwiftUI way to instantiate an ObservableObject. This also ensures the Rive data is only loaded when the view is displayed and not when the app is started. The `view` method may also be called multiple times for various reasons, so moving this logic to be in the view state is more efficient. @mjtalbot I think you made comments about this in the past. By doing the above it also fixes the samples in `SwiftWidgets` that was giving issues - For example, the sliders didn't work. It does now. - The toggle `RSwitch` still does not work, as it's an Animation and not a StateMachine (I believe there is now logic that disables touch events if there are no active listeners, or it only does touch processing when it's a state machine). - We should remove this file entirely or just keep the sliders. This seems to have been made before state machines were a thing, and implementing buttons etc. should rather be done through listeners and events. ### TODO - Some samples still create the RiveViewModel in the view but rely on other state data. Need to check to see what is the correct way to lazily create those. Diffs= fbb092d8c chore: cleanup ios examples (#6351) Co-authored-by: Gordon --- .rive_head | 2 +- .rive_renderer | 2 +- Example-iOS/Assets/switch.riv | Bin 3607 -> 0 bytes .../RiveExample.xcodeproj/project.pbxproj | 16 +---- .../Examples/Storyboard/CachedAssets.swift | 2 - .../Examples/Storyboard/SimpleOutOfBand.swift | 3 - .../Examples/SwiftUI/SwiftCannonGame.swift | 13 ++-- .../Source/Examples/SwiftUI/SwiftLayout.swift | 11 +++- .../Examples/SwiftUI/SwiftMeshAnimation.swift | 5 +- .../SwiftUI/SwiftMultipleAnimations.swift | 2 +- .../SwiftUI/SwiftSimpleAnimation.swift | 3 +- .../Examples/SwiftUI/SwiftSimpleAssets.swift | 60 +++++++++--------- .../Examples/SwiftUI/SwiftStateMachine.swift | 3 +- .../SwiftUI/SwiftTestParityAnimSM.swift | 23 ------- .../Examples/SwiftUI/SwiftTestText.swift | 2 +- .../Examples/SwiftUI/SwiftTouchEvents.swift | 20 +++--- .../Examples/SwiftUI/SwiftVariableFPS.swift | 2 +- .../Examples/SwiftUI/SwiftWidgets.swift | 18 ++---- .../Examples/ViewModel/RiveSwitch.swift | 38 ----------- Example-iOS/Source/ExamplesMaster.swift | 1 - 20 files changed, 70 insertions(+), 156 deletions(-) delete mode 100644 Example-iOS/Assets/switch.riv delete mode 100644 Example-iOS/Source/Examples/SwiftUI/SwiftTestParityAnimSM.swift delete mode 100644 Example-iOS/Source/Examples/ViewModel/RiveSwitch.swift diff --git a/.rive_head b/.rive_head index 8b6016b7..0b213a5e 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -bd71143bc0964a789174f30f01d14fa551e33bb9 +fbb092d8c71e2854102a30cdec6e0a57ad10a3ba diff --git a/.rive_renderer b/.rive_renderer index 12eef9ff..7c166b57 100644 --- a/.rive_renderer +++ b/.rive_renderer @@ -1 +1 @@ -7e2d06a1e206eac1c65dcc88e153e6fe1e8067c9 +9859a2759e36e12f10e95324c11602ef5e7fa6a7 diff --git a/Example-iOS/Assets/switch.riv b/Example-iOS/Assets/switch.riv deleted file mode 100644 index a419b6c9f0c54b3579adad8d9711ea1e5fce8c5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3607 zcmbVOUu;ul6hF7SmzIAW8ymE9VMV+f40K=_&BE69uB<>ZvSsTA8Xg?bjU{CzrG%h9 z@L-6+2oWNNX~-UY@=pTsjR(sTA2cRLVq%OYMt$&Ei6#Oe^_=sa@7}hfDC}YPJLfyU z^Z%T$WBVtE{P5#fCaed;3^;}2k^EHQm>*yy6#)2oaOGbQca~NG{89p+*))D;ws`b- zB$b~l7V^1VwqU_(fPJYTBwtHGgK1{6Qw7UF-uxo+{w%>7(;S^D9=Cj8nJefN8O_hm z6|II^It*~$fo99L%eRYV=&|h625MYBHal~?7#TX7Wwoz3K>%|ROmo#xE;oDfR5rru z11$g%rjX)>cMzU^qKn0Y;x51zuSN-l)OWf&6Lo+-L%TQg97ibTFD~vq4x^ z6;)&C_T?*1_`}@5V&<-WwKUN`Y$qol-g}TZc=zvn$y({~0ZH_Drm7;&d^y2t7~1#m9G zsq;&QETeh;+O;^wzEE0{xK@mPVGt9yFoZpUW4lfOlN!9b3I)XtMz=7C=ZNd_5Raa=Wp^c(H;TMDD^8Ziu;+a_ySa z?oeu=9on5>>~I`E-}KGkC-K|)XA;h6;vt<$A{p5DM!yIn<6Hvy2X@{W(5y@S1vz)b zmZwkWa*^SD{$$?|=5C`O27Wi<285#qwDqor4Jm7nZ)i)JGLA%x5DpRBkmyd|x;9V5 z?mY$yU8Un05n|%J!IVf{C#o9-2TAZ#b;r8fdK-~L#D*_r?7#^*>VJLT_g#*sif z_@7K{!>?$UJJBvM*1i>^Sc8H(3e1Jl{(O3RdYXtZ`-dGugfb;JDkMhekeFbj-5URv z3PKc!3!(vCpsXM&9QC6o1vK#qrvMLMyO(Xfr;uiUU#PkWM^_-q23sZM5U&~=y)+JS zzuS@kO`&x|35BDppBfoNWE1*fq3ck>LwkB)MU2vOk)lCXIJ)+!wYMOW^1vk~<(&V0 zzuu?nQvSE3g?NcetxC+sD=#_Gt|;Xa^->yji*l)y^23*Wy0}}?LZEV08MleJP81`X z5iv0%lvlEFv=!|&yY^_qu>WFK@< zu8s_PCVPXEC<~#H30VPMNVpqdmx$qV;RS#sjkN;ER4afCH34L%17sk%xRa1*GNZ3l7m*#BMVIZ3B0Hxiu50PQ)w`Fm(zCP<^IA1Z^>BJ%_#Rza z$KlD0P Bool in diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftCannonGame.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftCannonGame.swift index 7a3539ee..cce3ae8f 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftCannonGame.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftCannonGame.swift @@ -12,12 +12,13 @@ import RiveRuntime struct SwiftCannonGame: DismissableView { var dismiss: () -> Void = {} + // MARK: RiveViewModel + // This view model controls a file configured with: + // - StateMachine + // - Listeners + @StateObject private var riveViewModel = RiveViewModel(fileName: "bullet_man_game") + var body: some View { - // MARK: RiveViewModel - // This view model controls a file configured with: - // - StateMachine - // - Listeners - - RiveViewModel(fileName: "bullet_man_game").view() + riveViewModel.view() } } diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftLayout.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftLayout.swift index 8e7e9643..e32193cd 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftLayout.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftLayout.swift @@ -9,15 +9,24 @@ import SwiftUI import RiveRuntime + + struct SwiftLayout: DismissableView { var dismiss: () -> Void = {} @State private var fit: RiveFit = .contain @State private var alignment: RiveAlignment = .center + @StateObject private var riveViewModel = RiveViewModel(fileName: "truck_v7", fit: .contain, alignment: .center) var body: some View { VStack { - RiveViewModel(fileName: "truck_v7", fit: fit, alignment: alignment).view() + riveViewModel.view() + .onChange(of: fit) { value in + riveViewModel.fit = value + } + .onChange(of: alignment) { value in + riveViewModel.alignment = value + } } HStack { Text("Fit") diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftMeshAnimation.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftMeshAnimation.swift index 0de4f987..7fe6f673 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftMeshAnimation.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftMeshAnimation.swift @@ -14,13 +14,10 @@ struct SwiftMeshAnimation: DismissableView { // MARK: RiveViewModel // This view model specifies the exact StateMachine that it wants from the file - - // TODO: - // Review viewmodel set-up here to avoid recreation & also loading files on launch. @State var isTapped: Bool = false + @StateObject private var tapePlayer = RiveViewModel(fileName: "prop_example", stateMachineName: "State Machine 1") var body: some View { - let tapePlayer = RiveViewModel(fileName: "prop_example", stateMachineName: "State Machine 1") tapePlayer.view() .aspectRatio(1, contentMode: .fit) .onTapGesture { diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftMultipleAnimations.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftMultipleAnimations.swift index 503b6f54..7e7b0c86 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftMultipleAnimations.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftMultipleAnimations.swift @@ -13,9 +13,9 @@ import RiveRuntime /// different animations within those artboards struct SwiftMultipleAnimations: DismissableView { var dismiss: () -> Void = {} + let file = try! RiveFile(name: "artboard_animations") var body: some View { - let file = try! RiveFile(name: "artboard_animations") ScrollView{ VStack { Text("Square - go around") diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftSimpleAnimation.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftSimpleAnimation.swift index 15dc8564..c115e720 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftSimpleAnimation.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftSimpleAnimation.swift @@ -13,11 +13,12 @@ import RiveRuntime struct SwiftSimpleAnimation: DismissableView { var dismiss: () -> Void = {} + @StateObject private var riveViewModel = RiveViewModel(fileName: "halloween", autoPlay: false) var body: some View { SwiftVMPlayer( viewModels: - RiveViewModel(fileName: "halloween", autoPlay: false) + riveViewModel ) } } diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftSimpleAssets.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftSimpleAssets.swift index ce9c7f90..d424a162 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftSimpleAssets.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftSimpleAssets.swift @@ -11,38 +11,38 @@ import RiveRuntime struct SwiftSimpleAssets: DismissableView { var dismiss: () -> Void = {} - - var body: some View { - RiveViewModel(fileName: "simple_assets", autoPlay: false, loadCdn: false, customLoader: { (asset: RiveFileAsset, data: Data, factory: RiveFactory) -> Bool in + @StateObject private var riveViewModel = RiveViewModel(fileName: "simple_assets", autoPlay: false, loadCdn: false, customLoader: { (asset: RiveFileAsset, data: Data, factory: RiveFactory) -> Bool in + + if (asset is RiveImageAsset){ - // TODO: this looks kinda compolex, can this be simpler? - if (asset is RiveImageAsset){ - - guard let url = (.main as Bundle).url(forResource: "picture-47982", withExtension: "jpeg") else { - fatalError("Failed to locate 'picture-47982' in bundle.") - } - guard let data = try? Data(contentsOf: url) else { - fatalError("Failed to load \(url) from bundle.") - } - (asset as! RiveImageAsset).renderImage( - factory.decodeImage(data) - ) - return true; - }else if (asset is RiveFontAsset) { - guard let url = (.main as Bundle).url(forResource: "Inter-45562", withExtension: "ttf") else { - fatalError("Failed to locate 'Inter-45562' in bundle.") - } - guard let data = try? Data(contentsOf: url) else { - fatalError("Failed to load \(url) from bundle.") - } - - (asset as! RiveFontAsset).font( - factory.decodeFont(data) - ) - return true; + guard let url = (.main as Bundle).url(forResource: "picture-47982", withExtension: "jpeg") else { + fatalError("Failed to locate 'picture-47982' in bundle.") + } + guard let data = try? Data(contentsOf: url) else { + fatalError("Failed to load \(url) from bundle.") + } + (asset as! RiveImageAsset).renderImage( + factory.decodeImage(data) + ) + return true; + }else if (asset is RiveFontAsset) { + guard let url = (.main as Bundle).url(forResource: "Inter-45562", withExtension: "ttf") else { + fatalError("Failed to locate 'Inter-45562' in bundle.") + } + guard let data = try? Data(contentsOf: url) else { + fatalError("Failed to load \(url) from bundle.") } - return false; - }).view() + (asset as! RiveFontAsset).font( + factory.decodeFont(data) + ) + return true; + } + + return false; + }); + + var body: some View { + riveViewModel.view() } } diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftStateMachine.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftStateMachine.swift index 84c2bc79..9573bba5 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftStateMachine.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftStateMachine.swift @@ -14,8 +14,9 @@ struct SwiftStateMachine: DismissableView { // MARK: RiveViewModel // This view model specifies the exact StateMachine that it wants from the file + @StateObject private var stateChanger = RiveViewModel(fileName: "skills", stateMachineName: "Designer's Test") + var body: some View { - let stateChanger = RiveViewModel(fileName: "skills", stateMachineName: "Designer's Test") ScrollView{ VStack { stateChanger.view() diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftTestParityAnimSM.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftTestParityAnimSM.swift deleted file mode 100644 index 7e970a38..00000000 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftTestParityAnimSM.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// SwiftTestParityAnimSM.swift -// RiveExample -// -// Created by Zachary Duncan on 5/27/22. -// Copyright © 2022 Rive. All rights reserved. -// - -import SwiftUI -import RiveRuntime - -/// Test to check the difference in behavior between an Animation and an almost idential StateMachine -struct SwiftTestParityAnimSM: DismissableView { - var dismiss: () -> Void = {} - - var body: some View { - SwiftVMPlayer( - viewModels: - RiveViewModel(fileName: "teststatemachine", stateMachineName: "State Machine 1", autoPlay: false), - RiveViewModel(fileName: "testanimation", animationName: "Move", autoPlay: false) - ) - } -} diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftTestText.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftTestText.swift index 52459778..10f17cb1 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftTestText.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftTestText.swift @@ -13,7 +13,7 @@ struct TextInputView: DismissableView { var dismiss: () -> Void = {} @State private var userInput: String = "" - @State private var rvm = RiveViewModel(fileName: "text_test_2") + @StateObject private var rvm = RiveViewModel(fileName: "text_test_2") var body: some View { VStack(spacing: 20) { diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftTouchEvents.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftTouchEvents.swift index e10a2058..431682ec 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftTouchEvents.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftTouchEvents.swift @@ -17,19 +17,15 @@ struct SwiftTouchEvents: DismissableView { // - State Machine // - Listeners - // TODO: - // Review viewmodel set-up here to avoid recreation & also loading files on launch. + @StateObject private var clock = ClockViewModel() + @StateObject private var jelly = RiveViewModel(fileName: "hero_editor") + @StateObject private var playButton = RiveViewModel(fileName: "play_button_event_example") + @StateObject private var lighthouse = RiveViewModel(fileName: "switch_event_example") + @StateObject private var eightball = RiveViewModel(fileName: "magic_8-ball_v2") + @StateObject private var bearGuy = RiveViewModel(fileName: "leg_day_events_example") + @StateObject private var toggle = RiveViewModel(fileName: "light_switch") - var body: some View { - - let clock = ClockViewModel() - let jelly = RiveViewModel(fileName: "hero_editor") - let playButton = RiveViewModel(fileName: "play_button_event_example") - let lighthouse = RiveViewModel(fileName: "switch_event_example") - let eightball = RiveViewModel(fileName: "magic_8-ball_v2") - let bearGuy = RiveViewModel(fileName: "leg_day_events_example") - let toggle = RiveViewModel(fileName: "light_switch") - + var body: some View { ScrollView { VStack { jelly.view() diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftVariableFPS.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftVariableFPS.swift index 17ff699c..45f35568 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftVariableFPS.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftVariableFPS.swift @@ -12,7 +12,7 @@ import RiveRuntime struct SwiftVariableFPS: DismissableView { var dismiss: () -> Void = {} - private var stateChanger = RiveViewModel(fileName: "skills", stateMachineName: "Designer's Test") + @StateObject private var stateChanger = RiveViewModel(fileName: "skills", stateMachineName: "Designer's Test") var body: some View { ScrollView{ diff --git a/Example-iOS/Source/Examples/SwiftUI/SwiftWidgets.swift b/Example-iOS/Source/Examples/SwiftUI/SwiftWidgets.swift index 3c919790..4d2ac106 100644 --- a/Example-iOS/Source/Examples/SwiftUI/SwiftWidgets.swift +++ b/Example-iOS/Source/Examples/SwiftUI/SwiftWidgets.swift @@ -18,13 +18,11 @@ struct SwiftWidgets: DismissableView { /// Tracks the health value coming from the slide for the progress bar @State var health: Double = 0 + @StateObject private var rslider = RiveSlider() + @StateObject private var rprogress = RiveProgressBar(); + @StateObject private var rbutton = RiveButton(); var body: some View { - - let rslider = RiveSlider() - let rprogress = RiveProgressBar() - let rswitch = RiveSwitch() - ZStack { Color.gray .ignoresSafeArea() @@ -33,20 +31,12 @@ struct SwiftWidgets: DismissableView { VStack { HStack { Text("RiveButton:") - RiveButton().view { + rbutton.view { print("Button tapped") } } Spacer().padding() - HStack { - Text("RSwitch:") - rswitch.view { on in - print("The switch is " + (on ? "on" : "off")) - } - } - Spacer().padding() - VStack { Text("RiveProgressBar:") rprogress.view() diff --git a/Example-iOS/Source/Examples/ViewModel/RiveSwitch.swift b/Example-iOS/Source/Examples/ViewModel/RiveSwitch.swift deleted file mode 100644 index 6634896d..00000000 --- a/Example-iOS/Source/Examples/ViewModel/RiveSwitch.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// RiveSwitch.swift -// RiveExample -// -// Created by Zachary Duncan on 4/13/22. -// Copyright © 2022 Rive. All rights reserved. -// - -import SwiftUI -import RiveRuntime - -class RiveSwitch: RiveViewModel { - private let onAnimation: String = "On" - private let offAnimation: String = "Off" - private let startAnimation: String = "StartOff" - - var action: ((Bool) -> Void)? = nil - var isOn = false { - didSet { - stop() - play(animationName: isOn ? onAnimation : offAnimation) - action?(isOn) - } - } - - init() { - super.init(fileName: "switch", animationName: startAnimation, fit: .cover) - } - - func view(_ action: ((Bool) -> Void)? = nil) -> some View { - self.action = action - return super.view().frame(width: 100, height: 50, alignment: .center) - } - - func touchEnded(onArtboard artboard: RiveArtboard?, atLocation location: CGPoint) { - isOn.toggle() - } -} diff --git a/Example-iOS/Source/ExamplesMaster.swift b/Example-iOS/Source/ExamplesMaster.swift index ea48b560..65c1d71e 100644 --- a/Example-iOS/Source/ExamplesMaster.swift +++ b/Example-iOS/Source/ExamplesMaster.swift @@ -30,7 +30,6 @@ class ExamplesMasterTableViewController: UITableViewController { // MARK: SwiftUI View Examples /// Made from custom `Views` private lazy var swiftViews: [(String, AnyView)] = [ - //("Test Anim/SM Parity", typeErased(dismissableView: SwiftTestParityAnimSM())), ("Touch Events!", typeErased(dismissableView: SwiftTouchEvents())), ("Widget Collection", typeErased(dismissableView: SwiftWidgets())), ("Animation Player", typeErased(dismissableView: SwiftSimpleAnimation())),