/Controls/DataControls/DataControls.UWP/ListView/View/Services/ListViewAnimationService.cs

https://github.com/telerik/UI-For-UWP · C# · 323 lines · 273 code · 50 blank · 0 comment · 23 complexity · a317fdc9dbe94965b6047f66203dc144 MD5 · raw file

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Telerik.Core;
  6. using Telerik.Data.Core.Layouts;
  7. using Telerik.UI.Xaml.Controls.Data.ContainerGeneration;
  8. using Telerik.UI.Xaml.Controls.Data.ListView;
  9. using Telerik.UI.Xaml.Controls.Primitives;
  10. using Windows.Foundation;
  11. using Windows.UI.Xaml;
  12. namespace Telerik.UI.Xaml.Controls.Data
  13. {
  14. internal interface IAnimatingService
  15. {
  16. ListViewAnimationService AnimatingService { get; }
  17. }
  18. internal class ListViewAnimationService : ServiceBase<RadListView>
  19. {
  20. private readonly List<object> scheduledItemsForAnimation = new List<object>();
  21. private readonly Dictionary<RadAnimation, Tuple<object, Action<object>>> runningAnimations = new Dictionary<RadAnimation, Tuple<object, Action<object>>>();
  22. private readonly List<IAnimated> scheduledModelsForRecycle = new List<IAnimated>();
  23. public ListViewAnimationService(RadListView owner)
  24. : base(owner)
  25. {
  26. }
  27. internal void PlayCheckBoxLayerAnimation(UIElement element, bool forward, bool beforeItem, double itemLength)
  28. {
  29. var checkBoxanimation = new RadMoveAnimation { Duration = TimeSpan.FromSeconds(0.3), FillBehavior = AnimationFillBehavior.HoldEnd };
  30. checkBoxanimation.EndPoint = new Point(0, 0);
  31. itemLength = itemLength == 0 ? 29 : itemLength;
  32. var offset = beforeItem ? itemLength : -itemLength;
  33. checkBoxanimation.StartPoint = this.Owner.Orientation == Windows.UI.Xaml.Controls.Orientation.Vertical ? new Point(-offset, 0) : new Point(0, -offset);
  34. if (!forward)
  35. {
  36. checkBoxanimation = checkBoxanimation.CreateOpposite() as RadMoveAnimation;
  37. }
  38. RadAnimationManager.Play(element, checkBoxanimation);
  39. }
  40. internal void PlayCheckModeAnimation(UIElement element, bool forward, bool beforeItem, double itemLength)
  41. {
  42. var animation = new RadMoveAnimation { Duration = TimeSpan.FromSeconds(0.3), FillBehavior = AnimationFillBehavior.HoldEnd };
  43. animation.StartPoint = new Point(0, 0);
  44. itemLength = itemLength == 0 ? 29 : itemLength;
  45. var offset = beforeItem ? itemLength : -itemLength;
  46. animation.EndPoint = this.Owner.Orientation == Windows.UI.Xaml.Controls.Orientation.Vertical ? new Point(offset, 0) : new Point(0, offset);
  47. if (forward)
  48. {
  49. animation.Ended += this.ForwardCheckModeAnimationEnded;
  50. }
  51. else
  52. {
  53. animation = animation.CreateOpposite() as RadMoveAnimation;
  54. animation.Ended += this.BackwardsCheckModeAnimationEnded;
  55. }
  56. RadAnimationManager.Play(element, animation);
  57. }
  58. internal bool IsAnimating(ItemInfo? info)
  59. {
  60. return this.runningAnimations.Values.Any(tuple =>
  61. {
  62. var model = tuple.Item1 as GeneratedItemModel;
  63. return model != null && model.ItemInfo.Equals(info);
  64. });
  65. }
  66. internal bool HasItemsForAnimation()
  67. {
  68. return this.scheduledItemsForAnimation.Count > 0;
  69. }
  70. internal void ScheduleItemForAnimation(object item)
  71. {
  72. this.scheduledItemsForAnimation.Add(item);
  73. }
  74. internal void PlayNullSourceAnimation(Action<object> callback)
  75. {
  76. var animation = this.CreateAnimation(AnimationTrigger.NullSource);
  77. this.runningAnimations.Add(animation, new Tuple<object, Action<object>>(this.Owner.animatingChildrenPanel, callback));
  78. RadAnimationManager.Play(this.Owner.animatingChildrenPanel, animation);
  79. }
  80. internal void PlaySourceResetAnimation(Action<object> callback)
  81. {
  82. var animation = this.CreateAnimation(AnimationTrigger.ResetSource);
  83. this.runningAnimations.Add(animation, new Tuple<object, Action<object>>(this.Owner.animatingChildrenPanel, callback));
  84. RadAnimationManager.Play(this.Owner.animatingChildrenPanel, animation);
  85. }
  86. internal void PlayNewSourceAnimation(Action<object> callback)
  87. {
  88. var animation = this.CreateAnimation(AnimationTrigger.NewSource);
  89. this.runningAnimations.Add(animation, new Tuple<object, Action<object>>(this.Owner.animatingChildrenPanel, callback));
  90. RadAnimationManager.Play(this.Owner.animatingChildrenPanel, animation);
  91. }
  92. internal void PlayItemAddedAnimations(Action<object> callback)
  93. {
  94. foreach (var scheduledItem in this.scheduledItemsForAnimation)
  95. {
  96. foreach (var displayedItem in this.Owner.Model.ForEachDisplayedElement())
  97. {
  98. if (displayedItem.ItemInfo.Item.Equals(scheduledItem))
  99. {
  100. var animation = this.CreateAnimation(AnimationTrigger.AddedItem);
  101. displayedItem.IsAnimating = true;
  102. RadAnimationManager.Play(displayedItem.Container as FrameworkElement, animation);
  103. this.runningAnimations.Add(animation, new Tuple<object, Action<object>>(displayedItem, callback));
  104. }
  105. }
  106. }
  107. this.scheduledItemsForAnimation.Clear();
  108. }
  109. internal void PlayItemRemovedAnimation(IList changedItems, Action<object> callback)
  110. {
  111. foreach (var changedItem in changedItems)
  112. {
  113. foreach (var displayedItem in this.Owner.Model.ForEachDisplayedElement())
  114. {
  115. if (changedItem.Equals(displayedItem.ItemInfo.Item))
  116. {
  117. if (changedItem.Equals(this.Owner.CurrentItem))
  118. {
  119. var currencyVisual = this.Owner.currencyLayerCache.CurrencyVisual as IAnimated;
  120. if (currencyVisual != null)
  121. {
  122. currencyVisual.IsAnimating = true;
  123. var animation = this.Owner.ItemRemovedAnimation.Clone();
  124. animation.FillBehavior = AnimationFillBehavior.Stop;
  125. animation.Ended += this.CurrentItemAnimationEnded;
  126. RadAnimationManager.Play(currencyVisual.Container as FrameworkElement, animation);
  127. this.runningAnimations.Add(animation, new Tuple<object, Action<object>>(currencyVisual, callback));
  128. }
  129. }
  130. this.scheduledModelsForRecycle.Add(displayedItem);
  131. displayedItem.IsAnimating = true;
  132. if (displayedItem != null)
  133. {
  134. var animation = this.CreateAnimation(AnimationTrigger.RemovedItem);
  135. this.runningAnimations.Add(animation, new Tuple<object, Action<object>>(displayedItem, callback));
  136. RadAnimationManager.Play(displayedItem.Container as FrameworkElement, animation);
  137. }
  138. else
  139. {
  140. callback(null);
  141. }
  142. }
  143. }
  144. }
  145. }
  146. internal void StopAnimations()
  147. {
  148. while (this.runningAnimations.Count > 0)
  149. {
  150. RadAnimationManager.StopIfRunning(this.GetContainerForItem(this.runningAnimations.Values.First().Item1) as FrameworkElement, this.runningAnimations.Keys.First());
  151. }
  152. }
  153. internal void StopAnimation(object item)
  154. {
  155. var animation = this.runningAnimations.Single((keyValuePair) =>
  156. {
  157. if (keyValuePair.Value.Item1.Equals(item))
  158. {
  159. return true;
  160. }
  161. return false;
  162. }).Key;
  163. RadAnimationManager.StopIfRunning(this.GetContainerForItem(item) as FrameworkElement, animation);
  164. }
  165. private object GetContainerForItem(object item)
  166. {
  167. if (item is IAnimated)
  168. {
  169. return (item as IAnimated).Container;
  170. }
  171. return item;
  172. }
  173. private RadAnimation CreateAnimation(AnimationTrigger change)
  174. {
  175. RadAnimation animation;
  176. switch (change)
  177. {
  178. case AnimationTrigger.ResetSource:
  179. animation = this.Owner.ItemRemovedAnimation.Clone();
  180. animation.FillBehavior = AnimationFillBehavior.Stop;
  181. animation.Ended += this.ResetSourceAnimationEnded;
  182. return animation;
  183. case AnimationTrigger.NullSource:
  184. animation = this.Owner.ItemRemovedAnimation.Clone();
  185. animation.FillBehavior = AnimationFillBehavior.Stop;
  186. animation.Ended += this.NullSourceAnimationEnded;
  187. return animation;
  188. case AnimationTrigger.NewSource:
  189. animation = this.Owner.ItemAddedAnimation.Clone();
  190. animation.FillBehavior = AnimationFillBehavior.Stop;
  191. animation.Ended += this.AnimationEndedOnNewSource;
  192. return animation;
  193. case AnimationTrigger.AddedItem:
  194. animation = this.Owner.ItemAddedAnimation.Clone();
  195. animation.Ended += this.AnimationEndedOnAddedItem;
  196. animation.FillBehavior = AnimationFillBehavior.Stop;
  197. return animation;
  198. case AnimationTrigger.RemovedItem:
  199. animation = this.Owner.ItemRemovedAnimation.Clone();
  200. animation.FillBehavior = AnimationFillBehavior.Stop;
  201. animation.Ended += this.ItemRemovedAnimationEnded;
  202. return animation;
  203. }
  204. return null;
  205. }
  206. private void CurrentItemAnimationEnded(object sender, AnimationEndedEventArgs e)
  207. {
  208. var animation = sender as RadAnimation;
  209. var item = this.runningAnimations[animation].Item1;
  210. if (item is IAnimated)
  211. {
  212. (item as IAnimated).IsAnimating = false;
  213. }
  214. this.runningAnimations.Remove(animation);
  215. }
  216. private void ItemRemovedAnimationEnded(object sender, AnimationEndedEventArgs e)
  217. {
  218. var callback = this.runningAnimations[sender as RadAnimation].Item2;
  219. if (this.scheduledModelsForRecycle.Count > 0)
  220. {
  221. var itemForRecycle = this.scheduledModelsForRecycle.First();
  222. itemForRecycle.IsAnimating = false;
  223. this.scheduledModelsForRecycle.Remove(itemForRecycle);
  224. if (this.runningAnimations.Keys.Count > 0)
  225. {
  226. this.runningAnimations.Remove(sender as RadAnimation);
  227. }
  228. callback(itemForRecycle);
  229. }
  230. }
  231. private void AnimationEndedOnNewSource(object sender, AnimationEndedEventArgs e)
  232. {
  233. var callback = this.runningAnimations[sender as RadAnimation].Item2;
  234. this.runningAnimations.Remove(sender as RadAnimation);
  235. callback(null);
  236. }
  237. private void AnimationEndedOnAddedItem(object sender, AnimationEndedEventArgs e)
  238. {
  239. var animation = sender as RadAnimation;
  240. var callback = this.runningAnimations[animation].Item2;
  241. var item = this.runningAnimations[animation].Item1;
  242. if (item is IAnimated)
  243. {
  244. (item as IAnimated).IsAnimating = false;
  245. }
  246. this.runningAnimations.Remove(animation);
  247. callback(item);
  248. }
  249. private void NullSourceAnimationEnded(object sender, AnimationEndedEventArgs e)
  250. {
  251. var callback = this.runningAnimations[sender as RadAnimation].Item2;
  252. this.runningAnimations.Remove(sender as RadAnimation);
  253. callback(null);
  254. }
  255. private void BackwardsCheckModeAnimationEnded(object sender, AnimationEndedEventArgs e)
  256. {
  257. (sender as RadAnimation).Ended -= this.BackwardsCheckModeAnimationEnded;
  258. this.Owner.itemCheckBoxService.itemsAnimated = true;
  259. this.Owner.itemCheckBoxService.OnIsCheckModeActiveChanged();
  260. }
  261. private void ForwardCheckModeAnimationEnded(object sender, AnimationEndedEventArgs e)
  262. {
  263. (sender as RadAnimation).Ended -= this.ForwardCheckModeAnimationEnded;
  264. this.Owner.itemCheckBoxService.itemsAnimated = true;
  265. }
  266. private void ResetSourceAnimationEnded(object sender, AnimationEndedEventArgs e)
  267. {
  268. var callback = this.runningAnimations[sender as RadAnimation].Item2;
  269. this.runningAnimations.Remove(sender as RadAnimation);
  270. callback(null);
  271. }
  272. }
  273. }