cbed098b09996a2c6661e2d71b076eb40d493317
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Navigation / Navigator.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.ComponentModel;
21 using Tizen.NUI.BaseComponents;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// The Navigator is a class which navigates pages with stack methods such as Push and Pop.
27     /// </summary>
28     /// <remarks>
29     /// With Transition class, Navigator supports smooth transition of View pair between two Pages
30     /// by using <see cref="PushWithTransition(Page)"/> and <see cref="PopWithTransition()"/> methods.
31     /// If current top Page and next top Page have <see cref="View"/>s those have same TransitionTag,
32     /// Navigator creates smooth transition motion for them.
33     /// Navigator.Transition property can be used to set properties of the Transition such as TimePeriod and AlphaFunction.
34     /// When all transitions are finished, Navigator calls a callback methods those connected on the "TransitionFinished" event.
35     /// </remarks>
36     /// <example>
37     /// <code>
38     /// Navigator navigator = new Navigator()
39     /// {
40     ///     TimePeriod = new TimePeriod(500),
41     ///     AlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseInOutSine)
42     /// };
43     ///
44     /// View view = new View()
45     /// {
46     ///     TransitionOptions = new TransitionOptions()
47     ///     {
48     ///         /* Set properties for the transition of this View */
49     ///     }
50     /// };
51     ///
52     /// ContentPage newPage = new ContentPage()
53     /// {
54     ///     Content = view,
55     /// };
56     ///
57     /// Navigator.PushWithTransition(newPage);
58     /// </code>
59     /// </example>
60     /// <since_tizen> 9 </since_tizen>
61     public class Navigator : Control
62     {
63         private const int DefaultTransitionDuration = 500;
64
65         //This will be replaced with view transition class instance.
66         private Animation curAnimation = null;
67
68         //This will be replaced with view transition class instance.
69         private Animation newAnimation = null;
70
71         private TransitionSet transitionSet = null;
72
73         private Transition transition = new Transition()
74         {
75             TimePeriod = new TimePeriod(DefaultTransitionDuration),
76             AlphaFunction = new AlphaFunction(AlphaFunction.BuiltinFunctions.Default),
77         };
78
79         private bool transitionFinished = true;
80
81         //TODO: Needs to consider how to remove disposed window from dictionary.
82         //Two dictionaries are required to remove disposed navigator from dictionary.
83         private static Dictionary<Window, Navigator> windowNavigator = new Dictionary<Window, Navigator>();
84         private static Dictionary<Navigator, Window> navigatorWindow = new Dictionary<Navigator, Window>();
85
86         private List<Page> navigationPages = new List<Page>();
87
88         /// <summary>
89         /// Creates a new instance of a Navigator.
90         /// </summary>
91         /// <since_tizen> 9 </since_tizen>
92         public Navigator() : base()
93         {
94             Layout = new AbsoluteLayout();
95         }
96         
97         /// <summary>
98         /// An event fired when Transition has been finished.
99         /// </summary>
100         /// <since_tizen> 9 </since_tizen>
101         public event EventHandler<EventArgs> TransitionFinished;
102
103         /// <summary>
104         /// Returns the count of pages in Navigator.
105         /// </summary>
106         /// <since_tizen> 9 </since_tizen>
107         public int PageCount => navigationPages.Count;
108
109         /// <summary>
110         /// Transition properties for the transition of View pair having same transition tag.
111         /// </summary>
112         /// <since_tizen> 9 </since_tizen>
113         public Transition Transition
114         {
115             set
116             {
117                 transition = value;
118             }
119             get
120             {
121                 return transition;
122             }
123         }
124
125         /// <summary>
126         /// Pushes a page to Navigator.
127         /// If the page is already in Navigator, then it is not pushed.
128         /// </summary>
129         /// <param name="page">The page to push to Navigator.</param>
130         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
131         /// <since_tizen> 9 </since_tizen>
132         public void PushWithTransition(Page page)
133         {
134             if (!transitionFinished)
135             {
136                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
137                 return;
138             }
139
140             if (page == null)
141             {
142                 throw new ArgumentNullException(nameof(page), "page should not be null.");
143             }
144
145             //Duplicate page is not pushed.
146             if (navigationPages.Contains(page)) return;
147
148             var topPage = Peek();
149
150             if (!topPage)
151             {
152                 Insert(0, page);
153                 return;
154             }
155
156             navigationPages.Add(page);
157             Add(page);
158             page.Navigator = this;
159
160             //Invoke Page events
161             page.InvokeAppearing();
162             topPage.InvokeDisappearing();
163
164             transitionSet = CreateTransition(topPage, page, true);
165             transitionSet.Finished += (object sender, EventArgs e) =>
166             {
167                 if (page is DialogPage == false)
168                 {
169                    topPage.SetVisible(false);      
170                 }
171
172                 //Invoke Page events
173                 page.InvokeAppeared();
174                 topPage.InvokeDisappeared();
175             };
176             transitionFinished = false;
177         }
178
179         /// <summary>
180         /// Pops the top page from Navigator.
181         /// </summary>
182         /// <returns>The popped page.</returns>
183         /// <exception cref="InvalidOperationException">Thrown when there is no page in Navigator.</exception>
184         /// <since_tizen> 9 </since_tizen>
185         public Page PopWithTransition()
186         {
187             if (!transitionFinished)
188             {
189                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
190                 return null;
191             }
192
193             if (navigationPages.Count == 0)
194             {
195                 throw new InvalidOperationException("There is no page in Navigator.");
196             }
197
198             var topPage = Peek();
199
200             if (navigationPages.Count == 1)
201             {
202                 Remove(topPage);
203                 return topPage;
204             }
205             var newTopPage = navigationPages[navigationPages.Count - 2];
206
207 //            newTopPage.RaiseAbove(topPage);
208
209             //Invoke Page events
210             newTopPage.InvokeAppearing();
211             topPage.InvokeDisappearing();
212
213             transitionSet = CreateTransition(topPage, newTopPage, false);
214             transitionSet.Finished += (object sender, EventArgs e) =>
215             {
216                 Remove(topPage);
217                 topPage.SetVisible(true);
218
219                 //Invoke Page events
220                 newTopPage.InvokeAppeared();
221                 topPage.InvokeDisappeared();
222             };
223             transitionFinished = false;
224
225             return topPage;
226         }
227
228         /// <summary>
229         /// Pushes a page to Navigator.
230         /// If the page is already in Navigator, then it is not pushed.
231         /// </summary>
232         /// <param name="page">The page to push to Navigator.</param>
233         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
234         /// <since_tizen> 9 </since_tizen>
235         public void Push(Page page)
236         {
237             if (!transitionFinished)
238             {
239                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
240                 return;
241             }
242
243             if (page == null)
244             {
245                 throw new ArgumentNullException(nameof(page), "page should not be null.");
246             }
247
248             //Duplicate page is not pushed.
249             if (navigationPages.Contains(page)) return;
250
251             var curTop = Peek();
252
253             if (!curTop)
254             {
255                 Insert(0, page);
256                 return;
257             }
258
259             navigationPages.Add(page);
260             Add(page);
261             page.Navigator = this;
262
263             //Invoke Page events
264             page.InvokeAppearing();
265             curTop.InvokeDisappearing();
266
267             //TODO: The following transition codes will be replaced with view transition.
268             InitializeAnimation();
269
270             if (page is DialogPage == false)
271             {
272                 curAnimation = new Animation(1000);
273                 curAnimation.AnimateTo(curTop, "Opacity", 1.0f, 0, 1000);
274                 curAnimation.EndAction = Animation.EndActions.StopFinal;
275                 curAnimation.Finished += (object sender, EventArgs args) =>
276                 {
277                     curTop.SetVisible(false);
278
279                     //Invoke Page events
280                     curTop.InvokeDisappeared();
281                 };
282                 curAnimation.Play();
283
284                 page.Opacity = 0.0f;
285                 page.SetVisible(true);
286                 newAnimation = new Animation(1000);
287                 newAnimation.AnimateTo(page, "Opacity", 1.0f, 0, 1000);
288                 newAnimation.EndAction = Animation.EndActions.StopFinal;
289                 newAnimation.Finished += (object sender, EventArgs e) =>
290                 {
291                     //Invoke Page events
292                     page.InvokeAppeared();
293                 };
294                 newAnimation.Play();
295             }
296         }
297
298         /// <summary>
299         /// Pops the top page from Navigator.
300         /// </summary>
301         /// <returns>The popped page.</returns>
302         /// <exception cref="InvalidOperationException">Thrown when there is no page in Navigator.</exception>
303         /// <since_tizen> 9 </since_tizen>
304         public Page Pop()
305         {
306             if (!transitionFinished)
307             {
308                 Tizen.Log.Error("NUI", "Transition is still not finished.\n");
309                 return null;
310             }
311
312             if (navigationPages.Count == 0)
313             {
314                 throw new InvalidOperationException("There is no page in Navigator.");
315             }
316
317             var curTop = Peek();
318
319             if (navigationPages.Count == 1)
320             {
321                 Remove(curTop);
322                 return curTop;
323             }
324
325             var newTop = navigationPages[navigationPages.Count - 2];
326
327             //Invoke Page events
328             newTop.InvokeAppearing();
329             curTop.InvokeDisappearing();
330
331             //TODO: The following transition codes will be replaced with view transition.
332             InitializeAnimation();
333
334             if (curTop is DialogPage == false)
335             {
336                 curAnimation = new Animation(1000);
337                 curAnimation.AnimateTo(curTop, "Opacity", 0.0f, 0, 1000);
338                 curAnimation.EndAction = Animation.EndActions.StopFinal;
339                 curAnimation.Finished += (object sender, EventArgs e) =>
340                 {
341                     //Removes the current top page after transition is finished.
342                     Remove(curTop);
343                     curTop.Opacity = 1.0f;
344
345                     //Invoke Page events
346                     curTop.InvokeDisappeared();
347                 };
348                 curAnimation.Play();
349
350                 newTop.Opacity = 1.0f;
351                 newTop.SetVisible(true);
352                 newAnimation = new Animation(1000);
353                 newAnimation.AnimateTo(newTop, "Opacity", 1.0f, 0, 1000);
354                 newAnimation.EndAction = Animation.EndActions.StopFinal;
355                 newAnimation.Finished += (object sender, EventArgs e) =>
356                 {
357                     //Invoke Page events
358                     newTop.InvokeAppeared();
359                 };
360                 newAnimation.Play();
361             }
362             else
363             {
364                 Remove(curTop);
365             }
366
367             return curTop;
368         }
369
370         /// <summary>
371         /// Returns the page of the given index in Navigator.
372         /// The indices of pages in Navigator are basically the order of pushing or inserting to Navigator.
373         /// So a page's index in Navigator can be changed whenever push/insert or pop/remove occurs.
374         /// </summary>
375         /// <param name="index">The index of a page in Navigator.</param>
376         /// <returns>The page of the given index in Navigator.</returns>
377         /// <exception cref="ArgumentOutOfRangeException">Thrown when the argument index is less than 0, or greater than the number of pages.</exception>
378         public Page GetPage(int index)
379         {
380             if ((index < 0) || (index > navigationPages.Count))
381             {
382                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than or equal to the number of pages.");
383             }
384
385             return navigationPages[index];
386         }
387
388         /// <summary>
389         /// Returns the current index of the given page in Navigator.
390         /// The indices of pages in Navigator are basically the order of pushing or inserting to Navigator.
391         /// So a page's index in Navigator can be changed whenever push/insert or pop/remove occurs.
392         /// </summary>
393         /// <param name="page">The page in Navigator.</param>
394         /// <returns>The index of the given page in Navigator. If the given page is not in the Navigator, then -1 is returned.</returns>
395         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
396         /// <since_tizen> 9 </since_tizen>
397         public int IndexOf(Page page)
398         {
399             if (page == null)
400             {
401                 throw new ArgumentNullException(nameof(page), "page should not be null.");
402             }
403
404             for (int i = 0; i < navigationPages.Count; i++)
405             {
406                 if (navigationPages[i] == page)
407                 {
408                     return i;
409                 }
410             }
411
412             return -1;
413         }
414
415         /// <summary>
416         /// Inserts a page at the specified index of Navigator.
417         /// The indices of pages in Navigator are basically the order of pushing or inserting to Navigator.
418         /// So a page's index in Navigator can be changed whenever push/insert or pop/remove occurs.
419         /// To find the current index of a page in Navigator, please use IndexOf(page).
420         /// If the page is already in Navigator, then it is not inserted.
421         /// </summary>
422         /// <param name="index">The index of a page in Navigator where the page will be inserted.</param>
423         /// <param name="page">The page to insert to Navigator.</param>
424         /// <exception cref="ArgumentOutOfRangeException">Thrown when the argument index is less than 0, or greater than the number of pages.</exception>
425         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
426         /// <since_tizen> 9 </since_tizen>
427         public void Insert(int index, Page page)
428         {
429             if ((index < 0) || (index > navigationPages.Count))
430             {
431                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than or equal to the number of pages.");
432             }
433
434             if (page == null)
435             {
436                 throw new ArgumentNullException(nameof(page), "page should not be null.");
437             }
438
439             //Duplicate page is not pushed.
440             if (navigationPages.Contains(page)) return;
441
442             //TODO: The following transition codes will be replaced with view transition.
443             InitializeAnimation();
444
445             if (index == PageCount)
446             {
447                 page.Opacity = 1.0f;
448                 page.SetVisible(true);
449             }
450             else
451             {
452                 page.SetVisible(false);
453                 page.Opacity = 0.0f;
454             }
455
456             navigationPages.Insert(index, page);
457             Add(page);
458             page.Navigator = this;
459         }
460
461         /// <summary>
462         /// Inserts a page to Navigator before an existing page.
463         /// If the page is already in Navigator, then it is not inserted.
464         /// </summary>
465         /// <param name="before">The existing page, before which a page will be inserted.</param>
466         /// <param name="page">The page to insert to Navigator.</param>
467         /// <exception cref="ArgumentNullException">Thrown when the argument before is null.</exception>
468         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
469         /// <exception cref="ArgumentException">Thrown when the argument before does not exist in Navigator.</exception>
470         /// <since_tizen> 9 </since_tizen>
471         public void InsertBefore(Page before, Page page)
472         {
473             if (before == null)
474             {
475                 throw new ArgumentNullException(nameof(before), "before should not be null.");
476             }
477
478             if (page == null)
479             {
480                 throw new ArgumentNullException(nameof(page), "page should not be null.");
481             }
482
483             //Find the index of before page.
484             int beforeIndex = navigationPages.FindIndex(x => x == before);
485
486             //before does not exist in Navigator.
487             if (beforeIndex == -1)
488             {
489                 throw new ArgumentException("before does not exist in Navigator.", nameof(before));
490             }
491
492             Insert(beforeIndex, page);
493         }
494
495         /// <summary>
496         /// Removes a page from Navigator.
497         /// </summary>
498         /// <param name="page">The page to remove from Navigator.</param>
499         /// <exception cref="ArgumentNullException">Thrown when the argument page is null.</exception>
500         /// <since_tizen> 9 </since_tizen>
501         public void Remove(Page page)
502         {
503             if (page == null)
504             {
505                 throw new ArgumentNullException(nameof(page), "page should not be null.");
506             }
507
508             //TODO: The following transition codes will be replaced with view transition.
509             InitializeAnimation();
510
511             if ((page == Peek()) && (PageCount >= 2))
512             {
513                 navigationPages[PageCount - 2].Opacity = 1.0f;
514                 navigationPages[PageCount - 2].SetVisible(true);
515             }
516
517             page.Navigator = null;
518             navigationPages.Remove(page);
519             base.Remove(page);
520         }
521
522         /// <summary>
523         /// Removes a page at the specified index of Navigator.
524         /// The indices of pages in Navigator are basically the order of pushing or inserting to Navigator.
525         /// So a page's index in Navigator can be changed whenever push/insert or pop/remove occurs.
526         /// To find the current index of a page in Navigator, please use IndexOf(page).
527         /// </summary>
528         /// <param name="index">The index of a page in Navigator where the page will be removed.</param>
529         /// <exception cref="ArgumentOutOfRangeException">Thrown when the index is less than 0, or greater than or equal to the number of pages.</exception>
530         /// <since_tizen> 9 </since_tizen>
531         public void RemoveAt(int index)
532         {
533             if ((index < 0) || (index >= navigationPages.Count))
534             {
535                 throw new ArgumentOutOfRangeException(nameof(index), "index should be greater than or equal to 0, and less than the number of pages.");
536             }
537
538             Remove(navigationPages[index]);
539         }
540
541         /// <summary>
542         /// Returns the page at the top of Navigator.
543         /// </summary>
544         /// <returns>The page at the top of Navigator.</returns>
545         /// <since_tizen> 9 </since_tizen>
546         public Page Peek()
547         {
548             if (navigationPages.Count == 0) return null;
549
550             return navigationPages[navigationPages.Count - 1];
551         }
552
553         /// <summary>
554         /// Disposes Navigator and all children on it.
555         /// </summary>
556         /// <param name="type">Dispose type.</param>
557         [EditorBrowsable(EditorBrowsableState.Never)]
558         protected override void Dispose(DisposeTypes type)
559         {
560             if (disposed)
561             {
562                 return;
563             }
564
565             if (type == DisposeTypes.Explicit)
566             {
567                 foreach (Page page in navigationPages)
568                 {
569                     Utility.Dispose(page);
570                 }
571                 navigationPages.Clear();
572
573                 Window window;
574
575                 if (navigatorWindow.TryGetValue(this, out window) == true)
576                 {
577                     navigatorWindow.Remove(this);
578                     windowNavigator.Remove(window);
579                 }
580             }
581
582             base.Dispose(type);
583         }
584
585         /// <summary>
586         /// Returns the default navigator of the given window.
587         /// </summary>
588         /// <returns>The default navigator of the given window.</returns>
589         /// <exception cref="ArgumentNullException">Thrown when the argument window is null.</exception>
590         /// <since_tizen> 9 </since_tizen>
591         public static Navigator GetDefaultNavigator(Window window)
592         {
593             if (window == null)
594             {
595                 throw new ArgumentNullException(nameof(window), "window should not be null.");
596             }
597
598             if (windowNavigator.ContainsKey(window) == true)
599             {
600                 return windowNavigator[window];
601             }
602
603             var defaultNavigator = new Navigator();
604             defaultNavigator.WidthResizePolicy = ResizePolicyType.FillToParent;
605             defaultNavigator.HeightResizePolicy = ResizePolicyType.FillToParent;
606             window.Add(defaultNavigator);
607             windowNavigator.Add(window, defaultNavigator);
608             navigatorWindow.Add(defaultNavigator, window);
609
610             return defaultNavigator;
611         }
612
613         /// <summary>
614         /// Create Transition between currentTopPage and newTopPage
615         /// </summary>
616         /// <param name="currentTopPage">The top page of Navigator.</param>
617         /// <param name="newTopPage">The new top page after transition.</param>
618         /// <param name="pushTransition">True if this transition is for push new page</param>
619         private TransitionSet CreateTransition(Page currentTopPage, Page newTopPage, bool pushTransition)
620         {
621             currentTopPage.SetVisible(true);
622             newTopPage.SetVisible(true);
623
624             List<View> taggedViewsInNewTopPage = new List<View>();
625             RetrieveTaggedViews(taggedViewsInNewTopPage, newTopPage, true);
626             List<View> taggedViewsInCurrentTopPage = new List<View>();
627             RetrieveTaggedViews(taggedViewsInCurrentTopPage, currentTopPage, true);
628
629             List<KeyValuePair<View, View>> sameTaggedViewPair = new List<KeyValuePair<View, View>>();
630             foreach(View currentTopPageView in taggedViewsInCurrentTopPage)
631             {
632                 bool findPair = false;
633                 foreach(View newTopPageView in taggedViewsInNewTopPage)
634                 {
635                     if((currentTopPageView.TransitionOptions != null) && (newTopPageView.TransitionOptions != null) &&
636                         currentTopPageView.TransitionOptions?.TransitionTag == newTopPageView.TransitionOptions?.TransitionTag)
637                     {
638                         sameTaggedViewPair.Add(new KeyValuePair<View, View>(currentTopPageView, newTopPageView));
639                         findPair = true;
640                         break;
641                     }
642                 }
643                 if(findPair)
644                 {
645                     taggedViewsInNewTopPage.Remove(sameTaggedViewPair[sameTaggedViewPair.Count - 1].Value);
646                 }
647             }
648             foreach(KeyValuePair<View, View> pair in sameTaggedViewPair)
649             {
650                 taggedViewsInCurrentTopPage.Remove(pair.Key);
651             }
652
653             TransitionSet newTransitionSet = new TransitionSet();
654             sameTaggedViewPair.Reverse();
655             foreach(KeyValuePair<View, View> pair in sameTaggedViewPair)
656             {
657                 TransitionItem pairTransition = transition.CreateTransition(pair.Key, pair.Value);
658                 if(pair.Value.TransitionOptions?.TransitionWithChild ?? false)
659                 {
660                     pairTransition.TransitionWithChild = true;
661                 }
662                 newTransitionSet.AddTransition(pairTransition);
663             }
664
665             newTransitionSet.Finished += (object sender, EventArgs e) =>
666             {
667                 transitionFinished = true;
668                 InvokeTransitionFinished();
669                 transitionSet.Dispose();
670                 currentTopPage.Opacity = 1.0f;
671             };
672
673             // default appearing/disappearing transition - fast fade (half duration compaired with that of view pair transition)
674             int duration = (transition.TimePeriod.DurationMilliseconds + transition.TimePeriod.DelayMilliseconds);
675             float durationSeconds = (float)duration / 1000.0f;
676
677             if (!pushTransition || newTopPage is DialogPage == false)
678             {
679                 TransitionItemBase disappearingTransition = currentTopPage.DisappearingTransition.CreateTransition(currentTopPage, false);
680                 newTransitionSet.AddTransition(disappearingTransition);
681                 disappearingTransition.TransitionWithChild = true;
682             }
683             if (pushTransition || currentTopPage is DialogPage == false)
684             {
685                 TransitionItemBase appearingTransition = newTopPage.AppearingTransition.CreateTransition(newTopPage, true);
686                 appearingTransition.TransitionWithChild = true;
687                 newTransitionSet.AddTransition(appearingTransition);
688             }
689
690             newTransitionSet.Play();
691
692             return newTransitionSet;
693         }
694
695         /// <summary>
696         /// Retrieve Tagged Views in the view tree.
697         /// </summary>
698         /// <param name="taggedViews">Returned tagged view list..</param>
699         /// <param name="view">Root View to get tagged child View.</param>
700         /// <param name="isPage">Flag to check current View is page or not</param>
701         private void RetrieveTaggedViews(List<View> taggedViews, View view, bool isPage)
702         {
703             if (!isPage)
704             {
705                 if (!string.IsNullOrEmpty(view.TransitionOptions?.TransitionTag))
706                 {
707                     taggedViews.Add((view as View));
708                 }
709
710                 if (view.ChildCount == 0)
711                 {
712                     return;
713                 }
714
715                 if (view.TransitionOptions?.TransitionWithChild ?? false)
716                 {
717                     return;
718                 }
719             }
720             foreach (View child in view.Children)
721             {
722                 RetrieveTaggedViews(taggedViews, child, false);
723             }
724         }
725
726         internal void InvokeTransitionFinished()
727         {
728             TransitionFinished?.Invoke(this, new EventArgs());
729         }
730
731         //TODO: The following transition codes will be replaced with view transition.
732         private void InitializeAnimation()
733         {
734             if (curAnimation != null)
735             {
736                 curAnimation.Stop();
737                 curAnimation.Clear();
738                 curAnimation = null;
739             }
740
741             if (newAnimation != null)
742             {
743                 newAnimation.Stop();
744                 newAnimation.Clear();
745                 newAnimation = null;
746             }
747         }
748     }
749 }