mirror of
https://github.com/rive-app/rive-ios.git
synced 2026-01-18 17:11:28 +01:00
Added a helper method for animations to determine if they've ended. Moved model modifications out of RiveView's play method and into RiveViewModel's. When playing from the RiveViewModel we now check if an animation has ended so it can play again.
This commit is contained in:
committed by
Zachary Duncan
parent
6c172f7279
commit
b51be942bb
BIN
Example-iOS/Assets/button.riv
Normal file
BIN
Example-iOS/Assets/button.riv
Normal file
Binary file not shown.
@@ -52,6 +52,7 @@
|
||||
C3460A002800A6CE002DBCB7 /* bird.riv in Resources */ = {isa = PBXBuildFile; fileRef = C34609FD2800A6CE002DBCB7 /* bird.riv */; };
|
||||
C3468E6227FDCBC6008652FD /* SimpleSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3468E6127FDCBC6008652FD /* SimpleSlider.swift */; };
|
||||
C3745FCE282AE2320087F4AF /* hero_editor.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3745FCB282AE2320087F4AF /* hero_editor.riv */; };
|
||||
C3C07482283D582B00E8EB33 /* button.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3C0747F283D582B00E8EB33 /* button.riv */; };
|
||||
C3D187F3280751A8008B739A /* RiveProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D187F2280751A8008B739A /* RiveProgressBar.swift */; };
|
||||
C3D187F728075B6C008B739A /* riveslider.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3D187F628075B6C008B739A /* riveslider.riv */; };
|
||||
C3D187F9280770EA008B739A /* truck.riv in Resources */ = {isa = PBXBuildFile; fileRef = C3D187F8280770EA008B739A /* truck.riv */; };
|
||||
@@ -155,6 +156,7 @@
|
||||
C34609FD2800A6CE002DBCB7 /* bird.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = bird.riv; sourceTree = "<group>"; };
|
||||
C3468E6127FDCBC6008652FD /* SimpleSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleSlider.swift; sourceTree = "<group>"; };
|
||||
C3745FCB282AE2320087F4AF /* hero_editor.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = hero_editor.riv; sourceTree = "<group>"; };
|
||||
C3C0747F283D582B00E8EB33 /* button.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = button.riv; sourceTree = "<group>"; };
|
||||
C3D187F2280751A8008B739A /* RiveProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RiveProgressBar.swift; sourceTree = "<group>"; };
|
||||
C3D187F628075B6C008B739A /* riveslider.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = riveslider.riv; sourceTree = "<group>"; };
|
||||
C3D187F8280770EA008B739A /* truck.riv */ = {isa = PBXFileReference; lastKnownFileType = file; path = truck.riv; sourceTree = "<group>"; };
|
||||
@@ -251,6 +253,7 @@
|
||||
C9696B0E24FC6FD10041502A /* Assets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C3C0747F283D582B00E8EB33 /* button.riv */,
|
||||
C3E2B5872833ECB500A8651B /* bullet_man_game.riv */,
|
||||
C3745FCB282AE2320087F4AF /* hero_editor.riv */,
|
||||
C3E383472837E6B00029D65E /* watch_v1.riv */,
|
||||
@@ -479,6 +482,7 @@
|
||||
042C88DD2644447500E7DBB2 /* ui_swipe_left_to_delete.riv in Resources */,
|
||||
042C88E52644447500E7DBB2 /* explorer.riv in Resources */,
|
||||
042C88E22644447500E7DBB2 /* f22.riv in Resources */,
|
||||
C3C07482283D582B00E8EB33 /* button.riv in Resources */,
|
||||
046AFA712673AF04004ED497 /* blendmodes.riv in Resources */,
|
||||
042C88EC2644447500E7DBB2 /* vader.riv in Resources */,
|
||||
C9C73E9E24FC471E00EF9516 /* Assets.xcassets in Resources */,
|
||||
|
||||
@@ -12,25 +12,36 @@ import RiveRuntime
|
||||
|
||||
struct SwiftSimpleAnimation: DismissableView {
|
||||
var dismiss: () -> Void = {}
|
||||
var viewModel = RiveViewModel(fileName: "truck", autoPlay: false)
|
||||
var viewModel = RiveViewModel(fileName: "button", autoPlay: false)
|
||||
|
||||
var body: some View {
|
||||
viewModel.view()
|
||||
|
||||
HStack {
|
||||
PlayerButton(title: "▶︎") {
|
||||
viewModel.play()
|
||||
}
|
||||
|
||||
PlayerButton(title: " ▍▍") {
|
||||
viewModel.pause()
|
||||
}
|
||||
|
||||
PlayerButton(title: "◼︎") {
|
||||
viewModel.stop()
|
||||
ZStack {
|
||||
Color.gray
|
||||
|
||||
VStack {
|
||||
viewModel.view()
|
||||
|
||||
HStack {
|
||||
PlayerButton(title: "play") {
|
||||
viewModel.play(animationName: "active")
|
||||
}
|
||||
|
||||
PlayerButton(title: "pause") {
|
||||
viewModel.pause()
|
||||
}
|
||||
|
||||
PlayerButton(title: "stop") {
|
||||
viewModel.stop()
|
||||
}
|
||||
|
||||
PlayerButton(title: "backward.end") {
|
||||
viewModel.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.padding()
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
|
||||
struct PlayerButton: View {
|
||||
@@ -44,7 +55,7 @@ struct SwiftSimpleAnimation: DismissableView {
|
||||
} label: {
|
||||
ZStack {
|
||||
Color.blue
|
||||
Text(title)
|
||||
Image(systemName: title + ".fill")
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
|
||||
@@ -74,23 +74,11 @@ open class RiveView: RiveRendererView {
|
||||
// MARK: - Controls
|
||||
|
||||
/// Starts the render loop
|
||||
internal func play(loop: Loop = .loopAuto, direction: Direction = .directionAuto) {
|
||||
internal func play() {
|
||||
eventQueue.add {
|
||||
self.playerDelegate?.player(playedWithModel: self.riveModel)
|
||||
}
|
||||
|
||||
if let animation = riveModel.animation {
|
||||
if loop != .loopAuto {
|
||||
animation.loop(Int32(loop.rawValue))
|
||||
}
|
||||
|
||||
if direction == .directionForwards {
|
||||
animation.direction(1)
|
||||
} else if direction == .directionBackwards {
|
||||
animation.direction(-1)
|
||||
}
|
||||
}
|
||||
|
||||
isPlaying = true
|
||||
startTimer()
|
||||
}
|
||||
@@ -107,8 +95,22 @@ open class RiveView: RiveRendererView {
|
||||
|
||||
/// Asks the render loop to stop on the next cycle
|
||||
internal func stop() {
|
||||
self.playerDelegate?.player(stoppedWithModel: self.riveModel)
|
||||
isPlaying = false
|
||||
playerDelegate?.player(stoppedWithModel: self.riveModel)
|
||||
lastTime = 0
|
||||
|
||||
if !isPlaying {
|
||||
advance(delta: 0)
|
||||
} else {
|
||||
isPlaying = false
|
||||
}
|
||||
}
|
||||
|
||||
internal func reset() {
|
||||
lastTime = 0
|
||||
|
||||
if !isPlaying {
|
||||
advance(delta: 0)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Render Loop
|
||||
|
||||
@@ -119,29 +119,64 @@ open class RiveViewModel: NSObject, ObservableObject, RiveFileDelegate, RiveStat
|
||||
didSet { riveView?.alignment = alignment }
|
||||
}
|
||||
|
||||
open func play(animationName: String? = nil, loop: Loop? = nil) {
|
||||
/// Starts the active Animation or StateMachine from it's last position. It will start
|
||||
/// from the beginning if the active Animation has ended or a new one is provided.
|
||||
/// - Parameters:
|
||||
/// - animationName: The name of a new Animation to play on the current Artboard
|
||||
/// - loop: The loop mode for the active Animation
|
||||
open func play(animationName: String? = nil, loop: Loop = .loopAuto, direction: Direction = .directionAuto) {
|
||||
if let name = animationName {
|
||||
try! riveModel?.setAnimation(name)
|
||||
}
|
||||
if let loop = loop?.rawValue {
|
||||
riveModel?.animation?.loop(Int32(loop))
|
||||
|
||||
if let animation = riveModel?.animation {
|
||||
if loop != .loopAuto {
|
||||
animation.loop(Int32(loop.rawValue))
|
||||
}
|
||||
|
||||
if direction == .directionForwards {
|
||||
animation.direction(1)
|
||||
} else if direction == .directionBackwards {
|
||||
animation.direction(-1)
|
||||
}
|
||||
|
||||
if animation.hasEnded() {
|
||||
// Restarts Animation from beginning
|
||||
animation.setTime(0)
|
||||
}
|
||||
}
|
||||
|
||||
// We're not checking if a StateMachine is "ended" or "ExitState"
|
||||
// But we may want to in the future to enable restarting it by playing again
|
||||
|
||||
riveView?.play()
|
||||
}
|
||||
|
||||
/// Haults the active Animation or StateMachine and will resume from it's current position when next played
|
||||
open func pause() {
|
||||
riveView?.pause()
|
||||
}
|
||||
|
||||
/// Haults the active Animation or StateMachine and will restart from the beginning when next played
|
||||
open func stop() {
|
||||
resetScene()
|
||||
riveView?.stop()
|
||||
try! resetModelToDefault()
|
||||
}
|
||||
|
||||
@available(*, deprecated, renamed: "stop")
|
||||
/// Sets the active Animation or StateMachine back to their starting position
|
||||
open func reset() {
|
||||
stop()
|
||||
resetScene()
|
||||
riveView?.reset()
|
||||
}
|
||||
|
||||
private func resetScene() {
|
||||
if let stateMachine = riveModel?.stateMachine {
|
||||
// StateMachine can't reset itself so we reload from the Artboard
|
||||
try! riveModel!.setStateMachine(stateMachine.name())
|
||||
}
|
||||
else if let animation = riveModel?.animation {
|
||||
animation.setTime(0)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - RiveModel
|
||||
|
||||
@@ -40,9 +40,11 @@
|
||||
- (bool)advanceBy:(double)elapsedSeconds {
|
||||
return instance->advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
- (void)direction:(int)direction {
|
||||
instance->direction(direction);
|
||||
}
|
||||
|
||||
- (int)direction {
|
||||
return instance->direction();
|
||||
}
|
||||
@@ -68,8 +70,6 @@
|
||||
delete instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (NSInteger)fps {
|
||||
return instance->fps();
|
||||
}
|
||||
@@ -108,4 +108,8 @@
|
||||
return animation->duration() / fps;
|
||||
}
|
||||
|
||||
- (bool)hasEnded {
|
||||
return [self time] >= [self endTime];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -37,6 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (NSInteger)duration;
|
||||
- (NSInteger)effectiveDuration;
|
||||
- (float)effectiveDurationInSeconds;
|
||||
- (bool)hasEnded;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user