Skip to content
This repository was archived by the owner on Jan 12, 2026. It is now read-only.

Commit ec1270c

Browse files
committed
Fix Android
1 parent 91756a0 commit ec1270c

File tree

12 files changed

+202
-220
lines changed

12 files changed

+202
-220
lines changed

samples/Example/Pages/UpdatePropertiesPage.xaml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<VerticalStackLayout>
1717

1818
<riveMaui:RivePlayer Margin="0,40,0,0"
19-
ResourceName="{Binding ResourceName}"
19+
ResourceName="emoji"
2020
ArtboardName="{Binding ArtboardName}"
2121
Fit="Cover"
2222
HeightRequest="400" />
@@ -25,11 +25,6 @@
2525
Padding="10"
2626
HorizontalOptions="Center">
2727

28-
<Button Text="ResourceName"
29-
Margin="5,5,0,5"
30-
Command="{Binding UpdatePropertyCommand, Mode=OneTime}"
31-
CommandParameter="resource" />
32-
3328
<Button Text="ArtboardName"
3429
Margin="5,5,0,5"
3530
Command="{Binding UpdatePropertyCommand, Mode=OneTime}"

samples/Example/Pages/UpdatePropertiesPageViewModel.cs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,16 @@ namespace Example.Pages;
55

66
public partial class UpdatePropertiesPageViewModel : ObservableObject
77
{
8-
[ObservableProperty]
9-
private string _resourceName = "emoji";
10-
118
[ObservableProperty]
129
private string? _artboardName;
1310

1411
[RelayCommand]
15-
private Task UpdateProperty(string property)
12+
private void UpdateProperty(string property)
1613
{
17-
switch (property)
14+
ArtboardName = property switch
1815
{
19-
case "resource":
20-
ResourceName = ResourceName == "emoji" ? "runner" : "emoji";
21-
break;
22-
case "artboard":
23-
if (ResourceName == "emoji")
24-
ArtboardName = ArtboardName == "Emoji_package" ? "Onfire" : "Emoji_package";
25-
break;
26-
}
27-
28-
return Task.CompletedTask;
16+
"artboard" => ArtboardName == "Emoji_package" ? "Onfire" : "Emoji_package",
17+
_ => ArtboardName
18+
};
2919
}
3020
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using Android.Content;
2+
using Android.Views;
3+
using Android.Widget;
4+
using Rive.Android;
5+
6+
namespace Rive.Maui;
7+
8+
public sealed class CustomRiveView : LinearLayout
9+
{
10+
internal RiveAnimationView? AnimationView;
11+
internal WeakReference<RivePlayer?> VirtualView = new(null);
12+
internal string? ResourceName;
13+
14+
private StateListener? _stateListener;
15+
private EventListener? _eventListener;
16+
private readonly Context _context;
17+
18+
public CustomRiveView(Context context) : base(context)
19+
{
20+
_context = context;
21+
LayoutParameters = new LayoutParams(
22+
ViewGroup.LayoutParams.MatchParent,
23+
ViewGroup.LayoutParams.MatchParent
24+
);
25+
}
26+
27+
public void CreateAnimationView()
28+
{
29+
if (!VirtualView.TryGetTarget(out var virtualView) || string.IsNullOrWhiteSpace(virtualView.ResourceName))
30+
throw new Exception("Invalid ResourceName");
31+
32+
var resourceIdentifier = _context.Resources?.GetIdentifier(virtualView.ResourceName, "drawable", _context.PackageName) ?? 0;
33+
if (resourceIdentifier == 0)
34+
throw new Exception("Resource not found");
35+
36+
ResourceName = virtualView.ResourceName;
37+
38+
var riveAlignment = virtualView.Alignment.AsRive();
39+
var riveFit = virtualView.Fit.AsRive();
40+
var riveLoop = virtualView.Loop.AsRive();
41+
42+
var animationView = new RiveAnimationView(_context, null);
43+
44+
if (virtualView.DynamicAssets?.Count > 0)
45+
{
46+
animationView.SetAssetLoader(new AssetLoader(_context, virtualView.DynamicAssets));
47+
}
48+
49+
animationView.SetRiveResource(
50+
resourceIdentifier,
51+
virtualView.ArtboardName,
52+
virtualView.AnimationName,
53+
virtualView.StateMachineName,
54+
virtualView.AutoPlay,
55+
riveFit,
56+
riveAlignment,
57+
riveLoop
58+
);
59+
60+
_stateListener = new StateListener();
61+
_stateListener.RiveViewReference.SetTarget(this);
62+
animationView.RegisterListener(_stateListener);
63+
64+
_eventListener = new EventListener();
65+
_eventListener.RiveViewReference.SetTarget(this);
66+
animationView.AddEventListener(_eventListener);
67+
68+
AnimationView = animationView;
69+
}
70+
71+
public void RemoveAnimationView()
72+
{
73+
if (AnimationView == null)
74+
return;
75+
76+
RemoveView(AnimationView);
77+
78+
if (_stateListener != null)
79+
AnimationView.UnregisterListener(_stateListener);
80+
81+
if (_eventListener != null)
82+
AnimationView.RemoveEventListener(_eventListener);
83+
84+
AnimationView.Dispose();
85+
AnimationView = null;
86+
}
87+
88+
protected override void OnLayout(bool changed, int l, int t, int r, int b)
89+
{
90+
AnimationView?.Layout(0, 0, r - l, b - t);
91+
}
92+
93+
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
94+
{
95+
if (AnimationView != null)
96+
{
97+
AnimationView.Measure(widthMeasureSpec, heightMeasureSpec);
98+
SetMeasuredDimension(AnimationView.MeasuredWidth, AnimationView.MeasuredHeight);
99+
return;
100+
}
101+
102+
SetMeasuredDimension(0, 0);
103+
}
104+
105+
protected override void OnAttachedToWindow()
106+
{
107+
if (AnimationView == null)
108+
CreateAnimationView();
109+
110+
AddView(AnimationView, ViewGroup.LayoutParams.MatchParent);
111+
112+
base.OnAttachedToWindow();
113+
}
114+
115+
protected override void OnDetachedFromWindow()
116+
{
117+
RemoveAnimationView();
118+
119+
base.OnDetachedFromWindow();
120+
}
121+
122+
public new void Dispose()
123+
{
124+
RemoveAnimationView();
125+
126+
if (_stateListener != null)
127+
{
128+
_stateListener.RiveViewReference.SetTarget(null);
129+
_stateListener.Dispose();
130+
_stateListener = null;
131+
}
132+
133+
if (_eventListener != null)
134+
{
135+
_eventListener.RiveViewReference.SetTarget(null);
136+
_eventListener.Dispose();
137+
_eventListener = null;
138+
}
139+
140+
if (VirtualView.TryGetTarget(out var control))
141+
control.StateMachineInputs.Dispose();
142+
143+
VirtualView.SetTarget(null);
144+
145+
base.Dispose();
146+
}
147+
}

src/Rive.Maui/Platforms/Android/EventListener.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ namespace Rive.Maui;
66

77
public class EventListener : Object, RiveFileController.IRiveEventListener
88
{
9-
public WeakReference<RiveView?> RiveViewReference { get; set; } = new(null);
9+
public WeakReference<CustomRiveView?> RiveViewReference { get; set; } = new(null);
1010

1111
public void NotifyEvent(RiveEvent evt)
1212
{
13-
if (!RiveViewReference.TryGetTarget(out var handler))
13+
if (!RiveViewReference.TryGetTarget(out var handler) || !handler.VirtualView.TryGetTarget(out var virtualView))
1414
return;
1515

1616
var type = RivePlayerEvent.GeneralEvent;
@@ -22,7 +22,8 @@ public void NotifyEvent(RiveEvent evt)
2222
var properties = evt.Properties
2323
.ToDictionary<KeyValuePair<string, Object>, string, object>(k => k.Key, k => k.Value);
2424
var args = new EventReceivedArgs(evt.Name, type, properties);
25-
handler.VirtualView.EventReceivedManager.HandleEvent(this, args, nameof(RivePlayer.EventReceived));
26-
handler.VirtualView.EventReceivedCommand?.Execute(args);
25+
26+
virtualView.EventReceivedManager.HandleEvent(this, args, nameof(RivePlayer.EventReceived));
27+
virtualView.EventReceivedCommand?.Execute(args);
2728
}
2829
}

src/Rive.Maui/Platforms/Android/RivePlayerHandler.cs

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,36 @@
22

33
namespace Rive.Maui;
44

5-
public partial class RivePlayerHandler() : ViewHandler<RivePlayer, RiveView>(PropertyMapper, CommandMapper)
5+
public partial class RivePlayerHandler() : ViewHandler<RivePlayer, CustomRiveView>(PropertyMapper, CommandMapper)
66
{
7-
protected override RiveView CreatePlatformView()
7+
protected override CustomRiveView CreatePlatformView()
88
{
9-
var riveView = new RiveView(Context, VirtualView);
10-
return riveView;
9+
var platformView = new CustomRiveView(Context);
10+
platformView.VirtualView.SetTarget(VirtualView);
11+
12+
return platformView;
1113
}
1214

13-
protected override void ConnectHandler(RiveView platformView)
15+
protected override void ConnectHandler(CustomRiveView platformView)
1416
{
1517
platformView.CreateAnimationView();
16-
//riveView.CreateAnimationView();
1718
}
1819

19-
protected override void DisconnectHandler(RiveView platformView)
20+
protected override void DisconnectHandler(CustomRiveView platformView)
2021
{
2122
platformView.Dispose();
2223
}
2324

2425
public static void MapArtboardName(RivePlayerHandler handler, RivePlayer view)
2526
{
26-
if (!string.Equals(handler.PlatformView.AnimationView?.ArtboardName, view.ArtboardName, StringComparison.OrdinalIgnoreCase))
27+
if (handler.PlatformView.AnimationView != null &&
28+
!string.Equals(handler.PlatformView.AnimationView.ArtboardName, view.ArtboardName, StringComparison.OrdinalIgnoreCase))
2729
handler.PlatformView.AnimationView.ArtboardName = view.ArtboardName;
2830
}
2931

3032
public static void MapAnimationName(RivePlayerHandler handler, RivePlayer view)
3133
{
32-
if (string.IsNullOrWhiteSpace(view.AnimationName))
34+
if (handler.PlatformView.AnimationView == null || string.IsNullOrWhiteSpace(view.AnimationName))
3335
return;
3436

3537
var riveLoop = view.Loop.AsRive();
@@ -44,45 +46,42 @@ public static void MapAnimationName(RivePlayerHandler handler, RivePlayer view)
4446

4547
public static void MapStateMachineName(RivePlayerHandler handler, RivePlayer view)
4648
{
49+
if (handler.PlatformView.AnimationView == null)
50+
return;
51+
4752
var rendererAttributes = handler.PlatformView.AnimationView.GetRendererAttributes();
4853

4954
if (!string.Equals(rendererAttributes.StateMachineName, view.StateMachineName, StringComparison.OrdinalIgnoreCase))
5055
rendererAttributes.StateMachineName = view.StateMachineName;
5156
}
5257

53-
public static void MapResourceName(RivePlayerHandler handler, RivePlayer view)
54-
{
55-
if (string.IsNullOrWhiteSpace(view.ResourceName) ||
56-
string.Equals(view.ResourceName, handler.PlatformView.ResourceName, StringComparison.OrdinalIgnoreCase))
57-
return;
58-
59-
handler.CreatePlatformView();
60-
}
61-
6258
public static void MapAutoPlay(RivePlayerHandler handler, RivePlayer view)
6359
{
64-
if (handler.PlatformView.AnimationView.Autoplay != view.AutoPlay)
60+
if (handler.PlatformView.AnimationView != null && handler.PlatformView.AnimationView.Autoplay != view.AutoPlay)
6561
handler.PlatformView.AnimationView.Autoplay = view.AutoPlay;
6662
}
6763

6864
public static void MapFit(RivePlayerHandler handler, RivePlayer view)
6965
{
7066
var riveFit = view.Fit.AsRive();
71-
if (handler.PlatformView.AnimationView.Fit != riveFit)
67+
if (handler.PlatformView.AnimationView != null && handler.PlatformView.AnimationView.Fit != riveFit)
7268
handler.PlatformView.AnimationView.Fit = riveFit;
7369
}
7470

7571
public static void MapAlignment(RivePlayerHandler handler, RivePlayer view)
7672
{
7773
var riveAlignment = view.Alignment.AsRive();
78-
if (handler.PlatformView.AnimationView.Alignment != riveAlignment)
74+
if (handler.PlatformView.AnimationView != null && handler.PlatformView.AnimationView.Alignment != riveAlignment)
7975
handler.PlatformView.AnimationView.Alignment = riveAlignment;
8076
}
8177

8278
public static void MapLoop(RivePlayerHandler handler, RivePlayer view)
8379
{
84-
var rendererAttributes = handler.PlatformView.AnimationView.GetRendererAttributes();
85-
rendererAttributes.Loop = view.Loop.AsRive();
80+
if (handler.PlatformView.AnimationView != null)
81+
{
82+
var rendererAttributes = handler.PlatformView.AnimationView.GetRendererAttributes();
83+
rendererAttributes.Loop = view.Loop.AsRive();
84+
}
8685
}
8786

8887
public static void MapDirection(RivePlayerHandler handler, RivePlayer view)
@@ -92,13 +91,15 @@ public static void MapDirection(RivePlayerHandler handler, RivePlayer view)
9291

9392
public static void MapPlay(RivePlayerHandler handler, RivePlayer view, object? args)
9493
{
94+
if (handler.PlatformView.AnimationView == null)
95+
return;
96+
9597
var riveLoop = view.Loop.AsRive();
9698
var riveDirection = view.Direction.AsRive();
9799

98100
if (!string.IsNullOrWhiteSpace(view.AnimationName))
99101
{
100102
handler.PlatformView.AnimationView.Play(view.AnimationName, riveLoop, riveDirection, false, true);
101-
handler.PlatformView.RiveAnimation = handler.PlatformView.AnimationView.Animations.FirstOrDefault(x => x.Name == view.AnimationName);
102103
return;
103104
}
104105

@@ -120,13 +121,13 @@ public static void MapPlay(RivePlayerHandler handler, RivePlayer view, object? a
120121
}
121122

122123
public static void MapPause(RivePlayerHandler handler, RivePlayer view, object? args)
123-
=> handler.PlatformView.AnimationView.Pause();
124+
=> handler.PlatformView.AnimationView?.Pause();
124125

125126
public static void MapStop(RivePlayerHandler handler, RivePlayer view, object? args)
126-
=> handler.PlatformView.AnimationView.Stop();
127+
=> handler.PlatformView.AnimationView?.Stop();
127128

128129
public static void MapReset(RivePlayerHandler handler, RivePlayer view, object? args)
129-
=> handler.PlatformView.AnimationView.Reset();
130+
=> handler.PlatformView.AnimationView?.Reset();
130131

131132
public static void MapSetInput(RivePlayerHandler handler, RivePlayer view, object? args)
132133
{
@@ -136,13 +137,13 @@ public static void MapSetInput(RivePlayerHandler handler, RivePlayer view, objec
136137
switch (inputArgs.Value)
137138
{
138139
case double doubleValue:
139-
handler.PlatformView.AnimationView.SetNumberState(inputArgs.StateMachineName, inputArgs.InputName, (float)doubleValue);
140+
handler.PlatformView.AnimationView?.SetNumberState(inputArgs.StateMachineName, inputArgs.InputName, (float)doubleValue);
140141
break;
141142
case float floatValue:
142-
handler.PlatformView.AnimationView.SetNumberState(inputArgs.StateMachineName, inputArgs.InputName, floatValue);
143+
handler.PlatformView.AnimationView?.SetNumberState(inputArgs.StateMachineName, inputArgs.InputName, floatValue);
143144
break;
144145
case bool boolValue:
145-
handler.PlatformView.AnimationView.SetBooleanState(inputArgs.StateMachineName, inputArgs.InputName, boolValue);
146+
handler.PlatformView.AnimationView?.SetBooleanState(inputArgs.StateMachineName, inputArgs.InputName, boolValue);
146147
break;
147148
}
148149
}
@@ -151,7 +152,7 @@ public static void MapTriggerInput(RivePlayerHandler handler, RivePlayer view, o
151152
{
152153
if (args is StateMachineTriggerInputArgs triggerInputArgs)
153154
{
154-
handler.PlatformView.AnimationView.FireState(triggerInputArgs.StateMachineName, triggerInputArgs.InputName);
155+
handler.PlatformView.AnimationView?.FireState(triggerInputArgs.StateMachineName, triggerInputArgs.InputName);
155156
}
156157
}
157158
}

0 commit comments

Comments
 (0)