Skip to content

Commit

Permalink
Changed the RiveViewModel's view() method to return a type erased Any…
Browse files Browse the repository at this point in the history
…View to allow subclasses to override it. This is because currently in Swift opaque result types cannot be used for a non-final declaration within a class. I also removed some throws on methods in RiveViewModel to make the highest level of our API cleaner.
  • Loading branch information
duncandoit committed Jun 7, 2022
1 parent 139ae44 commit 921298e
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 70 deletions.
2 changes: 1 addition & 1 deletion Example-iOS/Source/Examples/SwiftUI/SwiftTouchEvents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct SwiftTouchEvents: DismissableView {
bearGuy.view()
.aspectRatio(1, contentMode: .fit)

clock.controlsView()
clock.view()

toggle.view()
.aspectRatio(1, contentMode: .fit)
Expand Down
2 changes: 1 addition & 1 deletion Example-iOS/Source/Examples/SwiftUI/SwiftWidgets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct SwiftWidgets: DismissableView {

VStack {
Text("RiveProgressBar:")
rprogress.formattedView()
rprogress.view()

Slider(value: Binding(
get: {
Expand Down
78 changes: 42 additions & 36 deletions Example-iOS/Source/Examples/ViewModel/ClockViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ import RiveRuntime

class ClockViewModel: RiveViewModel {
private var timer: Timer!
private var hour: Int = 0
private var minute: Int = 0
private var second: Int = 0

@Published var hours: Double = 0 {
@Published var time: Double = 0 {
didSet {
try? setInput("isTime", value: hours > 12 ? hours-12 : hours)
setInput("isTime", value: time > 12 ? time-12 : time)
}
}

Expand All @@ -25,11 +28,11 @@ class ClockViewModel: RiveViewModel {
let date = Date()
let calendar = Calendar.current

let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)
self.hour = calendar.component(.hour, from: date)
self.minute = calendar.component(.minute, from: date)
self.second = calendar.component(.second, from: date)

self.hours = Double(hour) + Double(minute)/60 + Double(second)/1200
self.time = Double(self.hour) + Double(self.minute)/60 + Double(self.second)/1200
}
} else {
timer?.invalidate()
Expand All @@ -46,39 +49,42 @@ class ClockViewModel: RiveViewModel {
timer?.invalidate()
}

func controlsView() -> some View {
return ZStack {
Color.gray

VStack {
view()
.aspectRatio(1, contentMode: .fit)
override func view() -> AnyView {
AnyView(
ZStack {
Color.gray

Button {
self.followTimer.toggle()
} label: {
ZStack {
Color.blue
Text(self.followTimer ? "Real Time" : "Manual")
.bold()
VStack {
super.view()
.aspectRatio(1, contentMode: .fit)

Button {
self.followTimer.toggle()
} label: {
ZStack {
Color.blue
Text(self.followTimer ? "Real Time" : "Manual")
.bold()
}
}
}
.foregroundColor(.white)
.frame(width: 200, height: 75, alignment: .center)
.cornerRadius(10)
.padding()

Text("Hour: \(round(hours * 100) / 100)")
.foregroundColor(.white)
.padding(.bottom)

Slider(value: Binding(
get: { self.hours },
set: { self.hours = round($0 * 100) / 100 }
), in: 0...24, step: 0.01)
.padding()
.disabled(followTimer)
.frame(width: 200, height: 75, alignment: .center)
.cornerRadius(10)
.padding()

let normalizedHour = hour%12 == 0 ? 12 : hour%12
Text("Time: \(normalizedHour):\(minute):\(second)")
.foregroundColor(.white)
.padding(.bottom)

Slider(value: Binding(
get: { self.time },
set: { self.time = round($0 * 100) / 100 }
), in: 0...24, step: 0.01)
.padding()
.disabled(followTimer)
}
}
}
)
}
}
4 changes: 2 additions & 2 deletions Example-iOS/Source/Examples/ViewModel/RiveButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class RiveButton: RiveViewModel {

func touchBegan(onArtboard artboard: RiveArtboard?, atLocation location: CGPoint) {
stop()
try? setInput(input, value: true)
setInput(input, value: true)
}

func touchEnded(onArtboard artboard: RiveArtboard?, atLocation location: CGPoint) {
Expand All @@ -35,6 +35,6 @@ class RiveButton: RiveViewModel {
}

func touchCancelled(onArtboard artboard: RiveArtboard?, atLocation location: CGPoint) {
try? setInput(input, value: false)
setInput(input, value: false)
}
}
10 changes: 6 additions & 4 deletions Example-iOS/Source/Examples/ViewModel/RiveProgressBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import SwiftUI
class RiveProgressBar: RiveViewModel {
var progress: Double {
didSet {
try? setInput("Energy", value: progress)
setInput("Energy", value: progress)
}
}

Expand All @@ -21,8 +21,10 @@ class RiveProgressBar: RiveViewModel {
super.init(fileName: "energy_bar_example", stateMachineName: "State Machine ", fit: .fitCover)
}

func formattedView() -> some View {
super.view()
.aspectRatio(4, contentMode: .fill)
override func view() -> AnyView {
AnyView(
super.view()
.aspectRatio(4, contentMode: .fill)
)
}
}
2 changes: 1 addition & 1 deletion Example-iOS/Source/Examples/ViewModel/RiveSlider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import SwiftUI
class RiveSlider: RiveViewModel {
var progress: Double {
didSet {
try? setInput("FillPercent", value: progress)
setInput("FillPercent", value: progress)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Example-iOS/Source/ExamplesMaster.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ extension ExamplesMasterTableViewController {

// Views made by the ViewModels
else if indexPath.section == 2 {
let anyView = AnyView(viewModels[indexPath.row].1.view())
let anyView = viewModels[indexPath.row].1.view()
controller = UIHostingController(rootView: anyView)
}

Expand Down
49 changes: 25 additions & 24 deletions Source/Components/RiveViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,30 +231,44 @@ open class RiveViewModel: NSObject, ObservableObject, RiveFileDelegate, RiveStat
)
}

open func triggerInput(_ inputName: String) throws {

/// Provide the active StateMachine a `Trigger` input
/// - Parameter inputName: The name of a `Trigger` input on the active StateMachine
open func triggerInput(_ inputName: String) {
riveModel?.stateMachine?.getTrigger(inputName).fire()
play()
}

open func setInput(_ inputName: String, value: Bool) throws {
/// Provide the active StateMachine a `Boolean` input
/// - Parameters:
/// - inputName: The name of a `Boolean` input on the active StateMachine
/// - value: A Bool value for the input
open func setInput(_ inputName: String, value: Bool) {
riveModel?.stateMachine?.getBool(inputName).setValue(value)
play()
}

open func setInput(_ inputName: String, value: Float) throws {
/// Provide the active StateMachine a `Number` input
/// - Parameters:
/// - inputName: The name of a `Number` input on the active StateMachine
/// - value: A Float value for the input
open func setInput(_ inputName: String, value: Float) {
riveModel?.stateMachine?.getNumber(inputName).setValue(value)
play()
}

open func setInput(_ inputName: String, value: Double) throws {
riveModel?.stateMachine?.getNumber(inputName).setValue(Float(value))
play()
/// Provide the active StateMachine a `Number` input
/// - Parameters:
/// - inputName: The name of a `Number` input on the active StateMachine
/// - value: A Double value for the input
open func setInput(_ inputName: String, value: Double) {
setInput(inputName, value: Float(value))
}

// MARK: - SwiftUI Helpers

/// Makes a new `RiveView` for the instance property with data from model which will
/// replace any previous `RiveView`. This is called when first drawing a `StandardView`.
/// replace any previous `RiveView`. This is called when first drawing a `RiveViewRepresentable`.
/// - Returns: Reference to the new view that the `RiveViewModel` will be maintaining
open func createRiveView() -> RiveView {
let view: RiveView
Expand All @@ -271,15 +285,15 @@ open class RiveViewModel: NSObject, ObservableObject, RiveFileDelegate, RiveStat
}

/// Gives updated layout values to the provided `RiveView`. This is called in
/// the process of re-displaying `StandardView`.
/// the process of re-displaying `RiveViewRepresentable`.
/// - Parameter rview: the `RiveView` that will be updated
@objc open func update(view: RiveView) {
view.fit = fit
view.alignment = alignment
}

/// Assigns the provided `RiveView` to its rview property. This is called when creating a
/// `StandardView`
/// `RiveViewRepresentable`
///
/// - Parameter view: the `Rview` that this `RiveViewModel` will maintain
fileprivate func registerView(_ view: RiveView) {
Expand All @@ -294,21 +308,8 @@ open class RiveViewModel: NSObject, ObservableObject, RiveFileDelegate, RiveStat
}

/// This can be added to the body of a SwiftUI `View`
open func view() -> some View {
return StandardView(viewModel: self)
}

/// A simple View designed to display
public struct StandardView: View {
let viewModel: RiveViewModel

init(viewModel: RiveViewModel) {
self.viewModel = viewModel
}

public var body: some View {
RiveViewRepresentable(viewModel: viewModel)
}
open func view() -> AnyView {
return AnyView(RiveViewRepresentable(viewModel: self))
}

// MARK: - UIKit Helper
Expand Down

0 comments on commit 921298e

Please sign in to comment.