2 * Copyright(c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 using global::System.Runtime.InteropServices;
20 using System.ComponentModel;
21 using System.Collections.Generic;
22 using System.Globalization;
24 namespace Tizen.NUI.BaseComponents
27 /// LottieAnimationView renders an animated vector image (Lottie file).
29 /// <since_tizen> 7 </since_tizen>
30 public class LottieAnimationView : ImageView
32 #region Constructor, Destructor, Dispose
34 /// LottieAnimationView constructor
36 /// <param name="scale">The factor of scaling image, default : 1.0f</param>
37 /// <param name="shown">false : not displayed (hidden), true : displayed (shown), default : true</param>
39 /// If the shown parameter is false, the animation is not visible even if the LottieAnimationView instance is created.
43 /// LottieAnimationView myLottie = new LottieAnimationView();
44 /// LottieAnimationView myLottie2 = new LottieAnimationView(2.0f);
45 /// LottieAnimationView myLottie3 = new LottieAnimationView(1.0f, false);
48 /// <since_tizen> 7 </since_tizen>
49 public LottieAnimationView(float scale = 1.0f, bool shown = true) : base()
51 NUILog.Debug($"< constructor GetId={GetId()} >");
52 currentStates.url = "";
53 currentStates.frame = -1;
54 currentStates.loopCount = 1;
55 currentStates.loopMode = LoopingModeType.Restart;
56 currentStates.stopEndAction = StopBehaviorType.CurrentFrame;
57 currentStates.framePlayRangeMin = -1;
58 currentStates.framePlayRangeMax = -1;
59 currentStates.changed = false;
60 currentStates.totalFrame = -1;
61 currentStates.scale = scale;
62 currentStates.redrawInScalingDown = true;
67 /// Dispose(DisposeTypes type)
69 /// <param name="type"></param>
70 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
71 [EditorBrowsable(EditorBrowsableState.Never)]
72 protected override void Dispose(DisposeTypes type)
79 //Release your own unmanaged resources here.
80 //You should not access any managed member here except static instance.
81 //because the execution order of Finalizes is non-deterministic.
83 //disconnect event signal
84 if (finishedEventHandler != null && visualEventSignalCallback != null)
86 VisualEventSignal().Disconnect(visualEventSignalCallback);
87 finishedEventHandler = null;
88 NUILog.Debug($"disconnect event signal");
93 #endregion Constructor, Destructor, Dispose
98 /// Set or Get resource URL of Lottie file.
100 /// <since_tizen> 7 </since_tizen>
105 string ret = (value == null ? "" : value);
106 currentStates.url = ret;
107 currentStates.changed = true;
109 NUILog.Debug($"<[{GetId()}]SET url={currentStates.url}");
111 PropertyMap map = new PropertyMap();
112 map.Add(Visual.Property.Type, new PropertyValue((int)DevelVisual.Type.AnimatedVectorImage))
113 .Add(ImageVisualProperty.URL, new PropertyValue(currentStates.url))
114 .Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount))
115 .Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction))
116 .Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
119 currentStates.contentInfo = null;
121 if (currentStates.scale != 1.0f)
123 Scale = new Vector3(currentStates.scale, currentStates.scale, 0.0f);
125 NUILog.Debug($"<[{GetId()}]>");
129 string ret = currentStates.url;
130 NUILog.Debug($"<[{GetId()}] GET");
132 PropertyMap map = Image;
135 PropertyValue val = map.Find(ImageVisualProperty.URL);
138 if (val.Get(out ret))
140 NUILog.Debug($"gotten url={ret} >");
145 Tizen.Log.Error(tag, $" [ERROR][{GetId()}](LottieAnimationView) Fail to get URL from dali >");
151 /// Gets the playing state
153 /// <since_tizen> 7 </since_tizen>
154 public PlayStateType PlayState
158 NUILog.Debug($"< Get!");
159 PropertyMap map = base.Image;
163 PropertyValue val = map.Find(ImageVisualProperty.PlayState);
166 if (val.Get(out ret))
168 currentStates.playState = (PlayStateType)ret;
169 NUILog.Debug($"gotten play state={ret} >");
175 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}]Fail to get PlayState from dali currentStates.playState={currentStates.playState}>");
177 return currentStates.playState;
182 /// Get the number of total frames
184 /// <since_tizen> 7 </since_tizen>
185 public int TotalFrame
190 PropertyMap map = Image;
193 PropertyValue val = map.Find(ImageVisualProperty.TotalFrameNumber);
196 if (val.Get(out ret))
198 //NUILog.Debug( $"TotalFrameNumber get! ret={ret}");
199 currentStates.totalFrame = ret;
204 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get TotalFrameNumber from dali>");
210 /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
213 /// Gets the value set by a user. If the setting value is out-ranged, it is reset as a minimum frame or a maximum frame.
216 /// We assume that the animation in myLottie.json file has 100 frames originally. If so, its frame index will be 0 - 99.
218 /// LottieAnimationView myLottie = new LottieAnimationView();
219 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
220 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
221 /// myLottie.CurrentFrame = 200; //display 99 frame
222 /// myLottie.SetMinMaxFrame(10, 20);
223 /// myLottie.CurrentFrame = 15; //display 15 frame
224 /// myLottie.CurrentFrame = 50; //display 20 frame, because the MinMax is set (10,20) above
227 /// <since_tizen> 7 </since_tizen>
228 public int CurrentFrame
232 currentStates.frame = value;
233 NUILog.Debug($"<[{GetId()}]SET frame={currentStates.frame}>");
234 DoAction(ImageView.Property.IMAGE, (int)actionType.jumpTo, new PropertyValue(currentStates.frame));
239 PropertyMap map = Image;
242 PropertyValue val = map.Find(ImageVisualProperty.CurrentFrameNumber);
245 if (val.Get(out ret))
247 //NUILog.Debug( $"CurrentFrameNumber get! val={ret}");
252 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get CurrentFrameNumber from dali!! ret={ret}>");
258 /// Sets or gets the looping mode of Lottie animation.
260 /// <since_tizen> 7 </since_tizen>
261 public LoopingModeType LoopingMode
265 currentStates.loopMode = (LoopingModeType)value;
266 currentStates.changed = true;
268 NUILog.Debug($"<[{GetId()}] SET loopMode={currentStates.loopMode}>");
269 PropertyMap map = new PropertyMap();
270 map.Add(ImageVisualProperty.LoopingMode, new PropertyValue((int)currentStates.loopMode));
271 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
275 //NUILog.Debug( $"LoopMode get!");
276 PropertyMap map = base.Image;
280 PropertyValue val = map.Find(ImageVisualProperty.LoopingMode);
283 if (val.Get(out ret))
285 //NUILog.Debug( $"gotten LoopMode={ret}");
286 if (ret != (int)currentStates.loopMode && ret > 0)
288 NUILog.Debug($" [ERROR][{GetId()}](LottieAnimationView) different LoopMode! gotten={ret}, loopMode={currentStates.loopMode}");
290 currentStates.loopMode = (LoopingModeType)ret;
291 return (LoopingModeType)ret;
295 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get loopMode from dali>");
296 return currentStates.loopMode;
301 /// Sets or gets the loop count.
304 /// The minus value means the infinite loop count.
308 /// LottieAnimationView myLottie = new LottieAnimationView();
309 /// myLottie.URL = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "myLottie.json"; //myLottie.json's total frame is 100 (frame: 0~99)
310 /// NUIApplication.GetDefaultWindow().GetDefaultLayer().Add(myLottie);
311 /// myLottie.LoopCount = -1; //infinite loop
313 /// myLottie.Stop(); //it plays continuously unless Stop() is called
314 /// myLottie.LoopCount = 2;
315 /// myLottie.Play(); //it plays only 2 times and stops automatically
318 /// <since_tizen> 7 </since_tizen>
323 currentStates.changed = true;
324 currentStates.loopCount = value;
325 NUILog.Debug($"<[{GetId()}]SET currentStates.loopCount={currentStates.loopCount}>");
326 PropertyMap map = new PropertyMap();
327 map.Add(ImageVisualProperty.LoopCount, new PropertyValue(currentStates.loopCount));
328 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
332 //NUILog.Debug( $"LoopCount get!");
333 PropertyMap map = base.Image;
337 PropertyValue val = map.Find(ImageVisualProperty.LoopCount);
340 if (val.Get(out ret))
342 //NUILog.Debug( $"gotten loop count={ret}");
343 if (ret != currentStates.loopCount && ret > 0)
345 NUILog.Debug($"<[ERROR][{GetId()}](LottieAnimationView) different loop count! gotten={ret}, loopCount={currentStates.loopCount}>");
347 currentStates.loopCount = ret;
348 return currentStates.loopCount;
352 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get LoopCount from dali currentStates.loopCount={currentStates.loopCount}>");
353 return currentStates.loopCount;
358 /// Sets or gets the stop behavior.
360 /// <since_tizen> 7 </since_tizen>
361 public StopBehaviorType StopBehavior
365 currentStates.stopEndAction = (StopBehaviorType)value;
366 currentStates.changed = true;
368 NUILog.Debug($"<[{GetId()}]SET val={currentStates.stopEndAction}>");
369 PropertyMap map = new PropertyMap();
370 map.Add(ImageVisualProperty.StopBehavior, new PropertyValue((int)currentStates.stopEndAction));
371 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
375 //NUILog.Debug( $"StopBehavior get!");
376 PropertyMap map = base.Image;
380 PropertyValue val = map.Find(ImageVisualProperty.StopBehavior);
383 if (val.Get(out ret))
385 //NUILog.Debug( $"gotten StopBehavior={ret}");
386 if (ret != (int)currentStates.stopEndAction)
388 NUILog.Debug($"<[ERROR][{GetId()}](LottieAnimationView) different StopBehavior! gotten={ret}, StopBehavior={currentStates.stopEndAction}>");
390 currentStates.stopEndAction = (StopBehaviorType)ret;
391 return (StopBehaviorType)ret;
395 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get StopBehavior from dali>");
396 return currentStates.stopEndAction;
401 /// Whether to redraw the image when the visual is scaled down.
405 /// It is used in the AnimatedVectorImageVisual.The default is true.
407 [EditorBrowsable(EditorBrowsableState.Never)]
408 public bool RedrawInScalingDown
412 currentStates.changed = true;
413 currentStates.redrawInScalingDown = value;
414 NUILog.Debug($"<[{GetId()}]SET currentStates.redrawInScalingDown={currentStates.redrawInScalingDown}>");
415 PropertyMap map = new PropertyMap();
416 map.Add(ImageVisualProperty.RedrawInScalingDown, new PropertyValue(currentStates.redrawInScalingDown));
417 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
421 PropertyMap map = base.Image;
425 PropertyValue val = map.Find(ImageVisualProperty.RedrawInScalingDown);
428 if (val.Get(out ret))
430 if (ret != currentStates.redrawInScalingDown)
432 NUILog.Debug($"<[ERROR][{GetId()}](LottieAnimationView) different redrawInScalingDown! gotten={ret}, redrawInScalingDown={currentStates.redrawInScalingDown}>");
434 currentStates.redrawInScalingDown = ret;
435 return currentStates.redrawInScalingDown;
439 Tizen.Log.Error(tag, $"<[ERROR][{GetId()}](LottieAnimationView) Fail to get redrawInScalingDown from dali currentStates.redrawInScalingDown={currentStates.redrawInScalingDown}>");
440 return currentStates.redrawInScalingDown;
448 /// Set the minimum and the maximum frame.
450 /// <param name="minFrame">minimum frame</param>
451 /// <param name="maxFrame">maximum frame</param>
452 /// <since_tizen> 7 </since_tizen>
453 public void SetMinMaxFrame(int minFrame, int maxFrame)
455 NUILog.Debug($"< [{GetId()}] SetPlayRange({minFrame}, {maxFrame})");
457 currentStates.changed = true;
458 currentStates.framePlayRangeMin = minFrame;
459 currentStates.framePlayRangeMax = maxFrame;
461 PropertyArray array = new PropertyArray();
462 array.PushBack(new PropertyValue(currentStates.framePlayRangeMin));
463 array.PushBack(new PropertyValue(currentStates.framePlayRangeMax));
465 PropertyMap map = new PropertyMap();
466 map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
467 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
468 NUILog.Debug($" [{GetId()}] currentStates.min:({currentStates.framePlayRangeMin}, max:{currentStates.framePlayRangeMax})>");
474 /// <since_tizen> 7 </since_tizen>
475 public new void Play()
477 NUILog.Debug($"<[{GetId()}] Play()");
480 NUILog.Debug($"[{GetId()}]>");
486 /// <since_tizen> 7 </since_tizen>
487 public new void Pause()
489 NUILog.Debug($"<[{GetId()}] Pause()>");
492 NUILog.Debug($"[{GetId()}]>");
498 /// <since_tizen> 7 </since_tizen>
499 public new void Stop()
501 NUILog.Debug($"<[{GetId()}] Stop()");
504 NUILog.Debug($"[{GetId()}]>");
508 /// Get the list of layers' information such as the start frame and the end frame in the Lottie file.
510 /// <returns>List of Tuple (string of layer name, integer of start frame, integer of end frame)</returns>
511 /// <since_tizen> 7 </since_tizen>
512 public List<Tuple<string, int, int>> GetContentInfo()
515 if (currentStates.contentInfo != null)
517 return currentStates.contentInfo;
520 PropertyMap imageMap = base.Image;
521 PropertyMap contentMap = new PropertyMap();
522 if (imageMap != null)
524 PropertyValue val = imageMap.Find(ImageVisualProperty.ContentInfo);
527 if (val.Get(contentMap))
529 currentStates.contentInfo = new List<Tuple<string, int, int>>();
530 for (uint i = 0; i < contentMap.Count(); i++)
532 string key = contentMap.GetKeyAt(i).StringKey;
533 PropertyArray arr = new PropertyArray();
534 contentMap.GetValue(i).Get(arr);
537 int startFrame, endFrame;
538 arr.GetElementAt(0).Get(out startFrame);
539 arr.GetElementAt(1).Get(out endFrame);
541 NUILog.Debug($"[{i}] layer name={key}, startFrame={startFrame}, endFrame={endFrame}");
543 Tuple<string, int, int> item = new Tuple<string, int, int>(key, startFrame, endFrame);
545 currentStates.contentInfo?.Add(item);
552 return currentStates.contentInfo;
556 /// A marker has its start frame and end frame.
557 /// Animation will play between the start frame and the end frame of the marker if one marker is specified.
558 /// Or animation will play between the start frame of the first marker and the end frame of the second marker if two markers are specified. *
560 /// <param name="marker1">First marker</param>
561 /// <param name="marker2">Second marker</param>
562 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
563 [EditorBrowsable(EditorBrowsableState.Never)]
564 public void SetMinMaxFrameByMarker(string marker1, string marker2 = null)
566 NUILog.Debug($"< [{GetId()}] SetMinMaxFrameByMarker({marker1}, {marker2})");
568 currentStates.changed = true;
569 currentStates.mark1 = marker1;
570 currentStates.mark2 = marker2;
572 PropertyArray array = new PropertyArray();
573 array.PushBack(new PropertyValue(currentStates.mark1));
576 array.PushBack(new PropertyValue(currentStates.mark2));
579 PropertyMap map = new PropertyMap();
580 map.Add(ImageVisualProperty.PlayRange, new PropertyValue(array));
581 DoAction(ImageView.Property.IMAGE, (int)actionType.updateProperty, new PropertyValue(map));
582 NUILog.Debug($" [{GetId()}] currentStates.mark1:{currentStates.mark1}, mark2:{currentStates.mark2} >");
588 /// <returns>Tuple of Min and Max frames</returns>
589 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
590 [EditorBrowsable(EditorBrowsableState.Never)]
591 public Tuple<int, int> GetMinMaxFrame()
593 NUILog.Debug($"< [{GetId()}] GetMinMaxFrame()! total frame={currentStates.totalFrame}");
595 PropertyMap map = Image;
598 PropertyValue val = map.Find(ImageVisualProperty.PlayRange);
601 PropertyArray array = new PropertyArray();
604 uint cnt = array.Count();
605 int item1 = -1, item2 = -1;
606 for (uint i = 0; i < cnt; i++)
608 PropertyValue v = array.GetElementAt(i);
610 if (v.Get(out intRet))
612 NUILog.Debug($"Got play range of string [{i}]: {intRet}");
624 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#1");
627 NUILog.Debug($" [{GetId()}] GetMinMaxFrame(min:{item1}, max:{item2})! >");
628 return new Tuple<int, int>(item1, item2);
632 Tizen.Log.Error("NUI", $"[ERR] fail to get play range from dali! case#2");
633 return new Tuple<int, int>(-1, -1);
638 #region Event, Enum, Struct, ETC
640 /// Animation finished event.
642 /// <since_tizen> 7 </since_tizen>
643 public event EventHandler Finished
647 if (finishedEventHandler == null)
649 NUILog.Debug($"<[{GetId()}] Finished eventhandler added>");
650 visualEventSignalCallback = onVisualEventSignal;
651 VisualEventSignal().Connect(visualEventSignalCallback);
653 finishedEventHandler += value;
657 NUILog.Debug($"<[{GetId()}] Finished eventhandler removed>");
658 finishedEventHandler -= value;
659 if (finishedEventHandler == null && visualEventSignalCallback != null)
661 VisualEventSignal().Disconnect(visualEventSignalCallback);
667 /// Enumeration for what state the vector animation is in
669 /// <since_tizen> 7 </since_tizen>
670 public enum PlayStateType
675 /// <since_tizen> 7 </since_tizen>
678 /// Vector Animation has stopped
680 /// <since_tizen> 7 </since_tizen>
683 /// The vector animation is playing
685 /// <since_tizen> 7 </since_tizen>
688 /// The vector animation is paused
690 /// <since_tizen> 7 </since_tizen>
695 /// Enumeration for what to do when the animation is stopped.
697 /// <since_tizen> 7 </since_tizen>
698 public enum StopBehaviorType
701 /// When the animation is stopped, the current frame is shown.
703 /// <since_tizen> 7 </since_tizen>
706 /// When the animation is stopped, the min frame (first frame) is shown.
708 /// <since_tizen> 7 </since_tizen>
711 /// When the animation is stopped, the max frame (last frame) is shown.
713 /// <since_tizen> 7 </since_tizen>
718 /// Enumeration for what looping mode is in.
720 /// <since_tizen> 7 </since_tizen>
721 public enum LoopingModeType
724 /// When the animation arrives at the end in looping mode, the animation restarts from the beginning.
726 /// <since_tizen> 7 </since_tizen>
729 /// When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
731 /// <since_tizen> 7 </since_tizen>
734 #endregion Event, Enum, Struct, ETC
738 internal class VisualEventSignalArgs : EventArgs
740 public int VisualIndex
752 internal event EventHandler<VisualEventSignalArgs> VisualEvent
756 if (visualEventSignalHandler == null)
758 visualEventSignalCallback = onVisualEventSignal;
759 VisualEventSignal().Connect(visualEventSignalCallback);
761 visualEventSignalHandler += value;
765 visualEventSignalHandler -= value;
766 if (visualEventSignalHandler == null && VisualEventSignal().Empty() == false)
768 VisualEventSignal().Disconnect(visualEventSignalCallback);
773 internal void EmitVisualEventSignal(int visualIndex, int signalId)
775 VisualEventSignal().Emit(this, visualIndex, signalId);
778 internal VisualEventSignal VisualEventSignal()
780 VisualEventSignal ret = new VisualEventSignal(Interop.VisualEventSignal.NewWithView(View.getCPtr(this)), false);
781 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
788 private struct states
792 internal int loopCount;
793 internal LoopingModeType loopMode;
794 internal StopBehaviorType stopEndAction;
795 internal int framePlayRangeMin;
796 internal int framePlayRangeMax;
797 internal bool changed;
798 internal int totalFrame;
799 internal float scale;
800 internal PlayStateType playState;
801 internal List<Tuple<string, int, int>> contentInfo;
802 internal string mark1, mark2;
803 internal bool redrawInScalingDown;
805 private states currentStates;
807 private enum actionType
816 private struct DevelVisual
820 AnimatedGradient = Visual.Type.AnimatedImage + 1,
821 AnimatedVectorImage = Visual.Type.AnimatedImage + 2,
825 private const string tag = "NUITEST";
826 private event EventHandler finishedEventHandler;
828 private void OnFinished()
830 NUILog.Debug($"<[{GetId()}] OnFinished()>");
831 finishedEventHandler?.Invoke(this, null);
834 private void onVisualEventSignal(IntPtr targetView, int visualIndex, int signalId)
838 if (targetView != IntPtr.Zero)
840 View v = Registry.GetManagedBaseHandleFromNativePtr(targetView) as View;
843 NUILog.Debug($"targetView is not null! name={v.Name}");
847 NUILog.Debug($"target is something created from dali");
850 VisualEventSignalArgs e = new VisualEventSignalArgs();
851 e.VisualIndex = visualIndex;
852 e.SignalId = signalId;
853 visualEventSignalHandler?.Invoke(this, e);
855 NUILog.Debug($"<[{GetId()}] onVisualEventSignal()! visualIndex={visualIndex}, signalId={signalId}>");
858 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
859 private delegate void VisualEventSignalCallbackType(IntPtr targetView, int visualIndex, int signalId);
861 private VisualEventSignalCallbackType visualEventSignalCallback;
862 private EventHandler<VisualEventSignalArgs> visualEventSignalHandler;
864 private void debugPrint()
866 NUILog.Debug($"===================================");
867 NUILog.Debug($"<[{GetId()}] get currentStates : url={currentStates.url}, loopCount={currentStates.loopCount}, \nframePlayRangeMin/Max({currentStates.framePlayRangeMin},{currentStates.framePlayRangeMax}) ");
868 NUILog.Debug($" get from Property : StopBehavior={StopBehavior}, LoopMode={LoopingMode}, LoopCount={LoopCount}, PlayState={PlayState}");
869 NUILog.Debug($" RedrawInScalingDown={RedrawInScalingDown} >");
870 NUILog.Debug($"===================================");
876 /// A class containing frame informations for a LottieAnimationView.
878 [EditorBrowsable(EditorBrowsableState.Never)]
879 public class LottieFrameInfo : ICloneable
882 /// Creates a new instance with a playing range.
884 [EditorBrowsable(EditorBrowsableState.Never)]
885 public LottieFrameInfo(int startFrame, int endFrame)
887 StartFrame = startFrame;
892 /// Creates a new instance with a still image frame.
894 [EditorBrowsable(EditorBrowsableState.Never)]
895 public LottieFrameInfo(int stillImageFrame) : this(stillImageFrame, stillImageFrame)
900 /// Create a new instance from a pair notation.
902 [EditorBrowsable(EditorBrowsableState.Never)]
903 public static implicit operator LottieFrameInfo((int, int) pair)
905 return new LottieFrameInfo(pair.Item1, pair.Item2);
909 /// Create a new instance from an int value.
911 [EditorBrowsable(EditorBrowsableState.Never)]
912 public static implicit operator LottieFrameInfo(int stillImageFrame)
914 return new LottieFrameInfo(stillImageFrame);
918 /// Create a new instance from string.
919 /// Possible input : "0, 10", "10"
921 [EditorBrowsable(EditorBrowsableState.Never)]
922 public static implicit operator LottieFrameInfo(string pair)
929 string[] parts = pair.Split(',');
930 if (parts.Length == 1)
932 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture));
934 else if (parts.Length == 2)
936 return new LottieFrameInfo(Int32.Parse(parts[0].Trim(), CultureInfo.InvariantCulture), Int32.Parse(parts[1].Trim(), CultureInfo.InvariantCulture));
939 Tizen.Log.Error("NUI", $"Can not convert string {pair} to LottieFrameInfo");
944 /// The start frame of the lottie animation.
946 [EditorBrowsable(EditorBrowsableState.Never)]
947 public int StartFrame { get; }
950 /// The end frame of the lottie animation.
952 [EditorBrowsable(EditorBrowsableState.Never)]
953 public int EndFrame { get; }
956 /// Create LottieFrameInfo struct with animation range information
958 [EditorBrowsable(EditorBrowsableState.Never)]
959 public static LottieFrameInfo CreateAnimationRange(int startFrame, int endFrame)
961 return new LottieFrameInfo(startFrame, endFrame);
965 /// Create LottieFrameInfo struct with still image information
967 [EditorBrowsable(EditorBrowsableState.Never)]
968 public static LottieFrameInfo CreateStillImage(int stillImageFrame)
970 return new LottieFrameInfo(stillImageFrame, stillImageFrame);
975 /// Whether this LottieFrameInfo represents one frame or more.
977 [EditorBrowsable(EditorBrowsableState.Never)]
978 public bool IsStillImage()
980 return StartFrame == EndFrame;
985 /// Play specified LottieAnimationView with this frame information.
987 /// <param name="lottieView">The target LottieAnimationView to play.</param>
988 /// <param name="noPlay">Whether go direct to the EndFrame. It is false by default.</param>
989 [EditorBrowsable(EditorBrowsableState.Never)]
990 public void Show(LottieAnimationView lottieView, bool noPlay = false)
992 if (!BeReadyToShow(lottieView))
997 lottieView.SetMinMaxFrame(StartFrame, Math.Min(EndFrame, lottieView.TotalFrame - 1));
999 if (IsStillImage() || noPlay)
1001 lottieView.CurrentFrame = EndFrame;
1005 lottieView.CurrentFrame = StartFrame;
1011 [EditorBrowsable(EditorBrowsableState.Never)]
1012 public object Clone() => new LottieFrameInfo(StartFrame, EndFrame);
1014 private bool BeReadyToShow(LottieAnimationView lottieView)
1016 // Validate input lottieView
1017 if (null == lottieView || lottieView.PlayState == LottieAnimationView.PlayStateType.Invalid)
1022 // Stop if it was playing
1023 if (lottieView.PlayState == LottieAnimationView.PlayStateType.Playing)