mirror of
https://github.com/rive-app/rive-ios.git
synced 2026-01-18 17:11:28 +01:00
Changed the RiveViewModel's view() method to return a type erased AnyView 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.
This commit is contained in:
committed by
Zachary Duncan
parent
139ae4462f
commit
921298ef35
@@ -37,7 +37,7 @@ struct SwiftTouchEvents: DismissableView {
|
||||
bearGuy.view()
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
|
||||
clock.controlsView()
|
||||
clock.view()
|
||||
|
||||
toggle.view()
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
|
||||
@@ -47,7 +47,7 @@ struct SwiftWidgets: DismissableView {
|
||||
|
||||
VStack {
|
||||
Text("RiveProgressBar:")
|
||||
rprogress.formattedView()
|
||||
rprogress.view()
|
||||
|
||||
Slider(value: Binding(
|
||||
get: {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -35,6 +35,6 @@ class RiveButton: RiveViewModel {
|
||||
}
|
||||
|
||||
func touchCancelled(onArtboard artboard: RiveArtboard?, atLocation location: CGPoint) {
|
||||
try? setInput(input, value: false)
|
||||
setInput(input, value: false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import SwiftUI
|
||||
class RiveProgressBar: RiveViewModel {
|
||||
var progress: Double {
|
||||
didSet {
|
||||
try? setInput("Energy", value: progress)
|
||||
setInput("Energy", value: progress)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import SwiftUI
|
||||
class RiveSlider: RiveViewModel {
|
||||
var progress: Double {
|
||||
didSet {
|
||||
try? setInput("FillPercent", value: progress)
|
||||
setInput("FillPercent", value: progress)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -271,7 +285,7 @@ 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
|
||||
@@ -279,7 +293,7 @@ open class RiveViewModel: NSObject, ObservableObject, RiveFileDelegate, RiveStat
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user